- Return a non-zero return code on errors.
[AROS.git] / rom / dos / open.c
blobc5bfddd0d3ebfd37152635a3c688b5429cd1cd98
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Open a file with the specified mode.
6 Lang: english
7 */
9 #include <aros/debug.h>
10 #include <exec/memory.h>
11 #include <exec/lists.h>
12 #include <proto/exec.h>
13 #include <utility/tagitem.h>
14 #include <dos/dosextens.h>
15 #include <dos/stdio.h>
16 #include <proto/dos.h>
17 #include <proto/utility.h>
19 #include "dos_intern.h"
21 static LONG InternalOpen(CONST_STRPTR name, LONG accessMode,
22 struct FileHandle *handle, LONG soft_nesting, struct DosLibrary *DOSBase);
24 #define MAX_SOFT_LINK_NESTING 16 /* Maximum level of soft links nesting */
26 /*****************************************************************************
28 NAME */
29 #include <proto/dos.h>
31 AROS_LH2(BPTR, Open,
33 /* SYNOPSIS */
34 AROS_LHA(CONST_STRPTR, name, D1),
35 AROS_LHA(LONG, accessMode, D2),
37 /* LOCATION */
38 struct DosLibrary *, DOSBase, 5, Dos)
40 /* FUNCTION
41 Opens a file for read and/or write depending on the accessmode given.
43 INPUTS
44 name - NUL terminated name of the file.
45 accessMode - One of MODE_OLDFILE - open existing file
46 MODE_NEWFILE - delete old, create new file
47 exclusive lock
48 MODE_READWRITE - open new one if it doesn't exist
50 RESULT
51 Handle to the file or 0 if the file couldn't be opened.
52 IoErr() gives additional information in that case.
54 NOTES
56 EXAMPLE
58 BUGS
60 SEE ALSO
62 INTERNALS
64 *****************************************************************************/
66 AROS_LIBFUNC_INIT
68 struct FileHandle *ret;
69 LONG error;
71 /* Sanity check */
72 if (name == NULL) return BNULL;
74 /* Create filehandle */
75 ret = (struct FileHandle *)AllocDosObject(DOS_FILEHANDLE,NULL);
77 if (ret != NULL)
79 LONG ok = InternalOpen(name, accessMode, ret, MAX_SOFT_LINK_NESTING, DOSBase);
80 D(bug("[Open] = %p, Error = %d\n", ok ? MKBADDR(ret) : BNULL, IoErr()));
81 if (ok)
83 return MKBADDR(ret);
85 else
87 error = IoErr();
88 FreeDosObject(DOS_FILEHANDLE,ret);
91 else
92 error = ERROR_NO_FREE_STORE;
94 SetIoErr(error);
95 return BNULL;
97 AROS_LIBFUNC_EXIT
98 } /* Open */
101 static LONG dupHandle(struct FileHandle *fh, BPTR lock, struct DosLibrary *DOSBase)
103 LONG err;
104 struct MsgPort *port;
105 struct FileLock *fl;
107 if (lock == BNULL)
108 return DOSFALSE;
110 fl = BADDR(lock);
111 port = fl->fl_Task;
113 err = dopacket2(DOSBase, NULL, port, ACTION_FH_FROM_LOCK, MKBADDR(fh), lock);
115 if (err != DOSFALSE) {
116 fh->fh_Type = port;
117 if (fh->fh_Interactive)
118 SetVBuf(MKBADDR(fh), NULL, BUF_LINE, -1);
119 else
120 SetVBuf(MKBADDR(fh), NULL, BUF_NONE, -1);
123 return err;
127 /* Try to open name recursively calling itself in case it's a soft link.
128 Store result in handle. Return boolean value indicating result. */
129 static LONG InternalOpen(CONST_STRPTR name, LONG accessMode,
130 struct FileHandle *handle, LONG soft_nesting, struct DosLibrary *DOSBase)
132 /* Get pointer to process structure */
133 struct Process *me = (struct Process *)FindTask(NULL);
134 LONG ret = DOSFALSE;
135 LONG error = 0;
136 BPTR con, ast;
138 ASSERT_VALID_PROCESS(me);
140 D(bug("[Open] %s: 0x%p \"%s\", Name: \"%s\" File: %p\n",
141 __is_process(me) ? "Process" : "Task", me, me->pr_Task.tc_Node.ln_Name,
142 name, MKBADDR(handle)));
144 if(soft_nesting == 0)
146 SetIoErr(ERROR_TOO_MANY_LEVELS);
147 return DOSFALSE;
150 /* IN:, OUT:, ERR: pseudodevices
152 if (pseudoLock(name, (accessMode == MODE_OLDFILE) ? ACCESS_READ :
153 ((accessMode == MODE_NEWFILE) ? ACCESS_WRITE : 0),
154 &ast, &ret, DOSBase)) {
155 return dupHandle(handle, ast, DOSBase);
158 switch(accessMode)
160 case MODE_NEWFILE:
161 case MODE_READWRITE:
162 con = me->pr_COS;
163 ast = me->pr_CES ? me->pr_CES : me->pr_COS;
165 break;
167 case MODE_OLDFILE:
168 ast = con = me->pr_CIS;
169 break;
171 default:
172 SetIoErr(ERROR_NOT_IMPLEMENTED);
173 return DOSFALSE;
176 if (!Stricmp(name, "CONSOLE:"))
177 error = fs_Open(handle, me->pr_ConsoleTask, con, accessMode, name, DOSBase);
178 else if (!Stricmp(name, "*"))
179 error = fs_Open(handle, me->pr_ConsoleTask, ast, accessMode, name, DOSBase);
180 else if (!Stricmp(name, "NIL:"))
182 error = fs_Open(handle, BNULL, BNULL, accessMode, name, DOSBase);
183 SetIoErr(0);
185 else
187 BPTR cur = BNULL;
188 struct DevProc *dvp = NULL;
189 STRPTR filename = strchr(name, ':');
191 if (!filename)
193 struct MsgPort *port;
195 /* No ':', pathname relative to current dir */
196 cur = me->pr_CurrentDir;
198 if (cur && cur != (BPTR)-1) {
199 port = ((struct FileLock *)BADDR(cur))->fl_Task;
200 } else {
201 port = DOSBase->dl_Root->rn_BootProc;
202 cur = BNULL;
205 error = fs_Open(handle, port, cur, accessMode, name, DOSBase);
207 else
209 filename++;
212 if ((dvp = GetDeviceProc(name, dvp)) == NULL)
214 error = IoErr();
215 break;
218 error = fs_Open(handle, dvp->dvp_Port, dvp->dvp_Lock, accessMode, filename, DOSBase);
219 } while(error == ERROR_OBJECT_NOT_FOUND && accessMode != MODE_NEWFILE);
221 if (error == ERROR_NO_MORE_ENTRIES)
222 error = ERROR_OBJECT_NOT_FOUND;
225 if (error == ERROR_IS_SOFT_LINK)
227 STRPTR softname = ResolveSoftlink(cur, dvp, name, DOSBase);
229 if (softname)
231 /* All OK */
232 BPTR olddir = BNULL;
234 if (dvp)
236 olddir = me->pr_CurrentDir;
237 error = RootDir(dvp, DOSBase);
239 else
240 error = 0;
242 if (!error)
244 ret = InternalOpen(softname, accessMode, handle, soft_nesting - 1, DOSBase);
245 error = ret ? 0 : IoErr();
247 if (olddir)
248 UnLock(CurrentDir(olddir));
251 FreeVec(softname);
253 else
254 error = IoErr();
257 FreeDeviceProc(dvp);
260 if (!error)
262 if (IsInteractive(MKBADDR(handle)))
263 SetVBuf(MKBADDR(handle), NULL, BUF_LINE, -1);
265 return DOSTRUE;
267 else
269 SetIoErr(error);
270 return DOSFALSE;