Detabbed
[AROS.git] / rom / dos / open.c
blob061d217cac00f09a1912b870c7f694aa788591ec
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 /* NIL: ? */
112 fl = BADDR(lock);
113 port = fl->fl_Task;
115 if (port) {
116 err = dopacket2(DOSBase, NULL, port, ACTION_FH_FROM_LOCK, MKBADDR(fh), lock);
117 } else {
118 /* NIL: device */
119 fh->fh_Interactive = DOSFALSE;
120 err = DOSTRUE;
123 if (err != DOSFALSE) {
124 fh->fh_Type = port;
125 if (fh->fh_Interactive)
126 SetVBuf(MKBADDR(fh), NULL, BUF_LINE, -1);
127 else
128 SetVBuf(MKBADDR(fh), NULL, BUF_NONE, -1);
131 return err;
135 /* Try to open name recursively calling itself in case it's a soft link.
136 Store result in handle. Return boolean value indicating result. */
137 static LONG InternalOpen(CONST_STRPTR name, LONG accessMode,
138 struct FileHandle *handle, LONG soft_nesting, struct DosLibrary *DOSBase)
140 /* Get pointer to process structure */
141 struct Process *me = (struct Process *)FindTask(NULL);
142 LONG ret = DOSFALSE;
143 LONG error = 0;
144 BPTR con, ast;
146 ASSERT_VALID_PROCESS(me);
148 D(bug("[Open] %s: 0x%p \"%s\", Name: \"%s\" File: %p\n",
149 __is_process(me) ? "Process" : "Task", me, me->pr_Task.tc_Node.ln_Name,
150 name, MKBADDR(handle)));
152 if(soft_nesting == 0)
154 SetIoErr(ERROR_TOO_MANY_LEVELS);
155 return DOSFALSE;
158 /* IN:, OUT:, ERR: pseudodevices
160 if (pseudoLock(name, (accessMode == MODE_OLDFILE) ? ACCESS_READ :
161 ((accessMode == MODE_NEWFILE) ? ACCESS_WRITE : 0),
162 &ast, &ret, DOSBase)) {
163 return dupHandle(handle, ast, DOSBase);
167 * Special case for NIL:, since it has no
168 * device task attached to it.
170 if (!Stricmp(name, "NIL:"))
172 SetIoErr(0);
174 handle->fh_Type = BNULL;
175 /* NIL: is not considered interactive */
176 handle->fh_Interactive = DOSFALSE;
177 return DOSTRUE;
180 switch(accessMode)
182 case MODE_NEWFILE:
183 case MODE_READWRITE:
184 con = me->pr_COS;
185 ast = me->pr_CES ? me->pr_CES : me->pr_COS;
187 break;
189 case MODE_OLDFILE:
190 ast = con = me->pr_CIS;
191 break;
193 default:
194 SetIoErr(ERROR_NOT_IMPLEMENTED);
195 return DOSFALSE;
198 if (!Stricmp(name, "CONSOLE:"))
199 error = fs_Open(handle, me->pr_ConsoleTask, con, accessMode, name, DOSBase);
200 else if (!Stricmp(name, "*"))
201 error = fs_Open(handle, me->pr_ConsoleTask, ast, accessMode, name, DOSBase);
202 else
204 BPTR cur = BNULL;
205 struct DevProc *dvp = NULL;
206 STRPTR filename = strchr(name, ':');
208 if (!filename)
210 struct MsgPort *port;
212 /* No ':', pathname relative to current dir */
213 cur = me->pr_CurrentDir;
215 if (cur && cur != (BPTR)-1) {
216 port = ((struct FileLock *)BADDR(cur))->fl_Task;
217 } else {
218 port = DOSBase->dl_Root->rn_BootProc;
219 cur = BNULL;
222 error = fs_Open(handle, port, cur, accessMode, name, DOSBase);
224 else
226 filename++;
229 if ((dvp = GetDeviceProc(name, dvp)) == NULL)
231 error = IoErr();
232 break;
235 error = fs_Open(handle, dvp->dvp_Port, dvp->dvp_Lock, accessMode, filename, DOSBase);
236 } while(error == ERROR_OBJECT_NOT_FOUND && accessMode != MODE_NEWFILE);
238 if (error == ERROR_NO_MORE_ENTRIES)
239 error = ERROR_OBJECT_NOT_FOUND;
242 if (error == ERROR_IS_SOFT_LINK)
244 STRPTR softname = ResolveSoftlink(cur, dvp, name, DOSBase);
246 if (softname)
248 /* All OK */
249 BPTR olddir = BNULL;
251 if (dvp)
253 olddir = me->pr_CurrentDir;
254 error = RootDir(dvp, DOSBase);
256 else
257 error = 0;
259 if (!error)
261 ret = InternalOpen(softname, accessMode, handle, soft_nesting - 1, DOSBase);
262 error = ret ? 0 : IoErr();
264 if (olddir)
265 UnLock(CurrentDir(olddir));
268 FreeVec(softname);
270 else
271 error = IoErr();
274 FreeDeviceProc(dvp);
277 if (!error)
279 if (IsInteractive(MKBADDR(handle)))
280 SetVBuf(MKBADDR(handle), NULL, BUF_LINE, -1);
282 return DOSTRUE;
284 else
286 SetIoErr(error);
287 return DOSFALSE;