Corrected invalid characters.
[tangerine.git] / rom / dos / open.c
blobb09903101295b9328204ffe9783746eadd6ad0c9
1 /*
2 Copyright © 1995-2008, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Open a file with the specified mode.
6 Lang: english
7 */
8 #include <exec/memory.h>
9 #include <exec/lists.h>
10 #include <proto/exec.h>
11 #include <utility/tagitem.h>
12 #include <dos/dosextens.h>
13 #include <dos/filesystem.h>
14 #include <dos/stdio.h>
15 #include <proto/dos.h>
16 #include <proto/utility.h>
17 #include "dos_intern.h"
19 LONG InternalOpen(CONST_STRPTR name, LONG accessMode,
20 struct FileHandle *handle, LONG soft_nesting, struct DosLibrary *DOSBase);
22 #define MAX_SOFT_LINK_NESTING 16 /* Maximum level of soft links nesting */
24 /*****************************************************************************
26 NAME */
27 #include <proto/dos.h>
29 AROS_LH2(BPTR, Open,
31 /* SYNOPSIS */
32 AROS_LHA(CONST_STRPTR, name, D1),
33 AROS_LHA(LONG, accessMode, D2),
35 /* LOCATION */
36 struct DosLibrary *, DOSBase, 5, Dos)
38 /* FUNCTION
39 Opens a file for read and/or write depending on the accessmode given.
41 INPUTS
42 name - NUL terminated name of the file.
43 accessMode - One of MODE_OLDFILE - open existing file
44 MODE_NEWFILE - delete old, create new file
45 exclusive lock
46 MODE_READWRITE - open new one if it doesn't exist
48 RESULT
49 Handle to the file or 0 if the file couldn't be opened.
50 IoErr() gives additional information in that case.
52 NOTES
54 EXAMPLE
56 BUGS
58 SEE ALSO
60 INTERNALS
62 *****************************************************************************/
64 AROS_LIBFUNC_INIT
66 struct FileHandle *ret;
67 LONG error;
69 /* Sanity check */
70 if (name == NULL) return NULL;
72 /* Create filehandle */
73 ret = (struct FileHandle *)AllocDosObject(DOS_FILEHANDLE,NULL);
75 if(ret != NULL)
77 if(InternalOpen(name, accessMode, ret, MAX_SOFT_LINK_NESTING, DOSBase))
79 return MKBADDR(ret);
81 else
83 error = IoErr();
84 FreeDosObject(DOS_FILEHANDLE,ret);
87 else
88 error = ERROR_NO_FREE_STORE;
90 SetIoErr(error);
91 return NULL;
93 AROS_LIBFUNC_EXIT
94 } /* Open */
96 /* Try to open name recursively calling itself in case it's a soft link.
97 Store result in handle. Return boolean value indicating result. */
98 LONG InternalOpen(CONST_STRPTR name, LONG accessMode,
99 struct FileHandle *handle, LONG soft_nesting, struct DosLibrary *DOSBase)
101 /* Get pointer to I/O request. Use stackspace for now. */
102 struct IOFileSys iofs;
103 /* Get pointer to process structure */
104 struct Process *me = (struct Process *)FindTask(NULL);
105 LONG ret = DOSFALSE;
106 LONG error = 0;
107 LONG error2 = 0;
108 LONG doappend = 0;
109 BPTR con, ast;
111 if(soft_nesting == 0)
113 SetIoErr(ERROR_TOO_MANY_LEVELS);
114 return DOSFALSE;
117 /* Prepare I/O request. */
118 InitIOFS(&iofs, FSA_OPEN_FILE, DOSBase);
120 switch(accessMode)
122 case MODE_OLDFILE:
123 iofs.io_Union.io_OPEN_FILE.io_FileMode = FMF_MODE_OLDFILE;
124 ast = con = me->pr_CIS;
125 break;
127 case MODE_NEWFILE:
128 iofs.io_Union.io_OPEN_FILE.io_FileMode = FMF_MODE_NEWFILE;
129 con = me->pr_COS;
130 ast = me->pr_CES ? me->pr_CES : me->pr_COS;
131 break;
133 case MODE_READWRITE:
134 iofs.io_Union.io_OPEN_FILE.io_FileMode = FMF_MODE_READWRITE;
135 con = me->pr_COS;
136 ast = me->pr_CES ? me->pr_CES : me->pr_COS;
137 break;
139 default:
140 /* See if the user requested append mode */
141 doappend = accessMode & FMF_APPEND;
143 /* The append mode is all taken care by dos.library */
144 accessMode &= ~FMF_APPEND;
146 iofs.io_Union.io_OPEN_FILE.io_FileMode = accessMode;
147 ast = con = me->pr_CIS;
148 break;
151 iofs.io_Union.io_OPEN_FILE.io_Protection = 0;
153 /* check for an empty filename. this supports this form that was
154 * required pre-2.0, which didn't have OpenFromLock():
156 * old = CurrentDir(lock);
157 * fh = Open("", MODE_OLDFILE);
158 * CurrentDir(old);
160 if (*name == '\0') {
161 BPTR cur;
162 struct FileHandle *fh;
164 cur = me->pr_CurrentDir;
165 if (!cur)
166 cur = DOSBase->dl_SYSLock;
168 if (cur) {
169 fh = BADDR(cur);
171 iofs.io_Union.io_OPEN_FILE.io_Filename = (STRPTR) "";
173 iofs.IOFS.io_Device = fh->fh_Device;
174 iofs.IOFS.io_Unit = fh->fh_Unit;
176 DosDoIO(&iofs.IOFS);
178 error = me->pr_Result2 = iofs.io_DosError;
179 } else {
180 error = ERROR_OBJECT_NOT_FOUND;
181 SetIoErr(error);
184 else if(!Stricmp(name, (STRPTR) "CONSOLE:"))
186 iofs.IOFS.io_Device = ((struct FileHandle *)BADDR(con))->fh_Device;
187 iofs.IOFS.io_Unit = ((struct FileHandle *)BADDR(con))->fh_Unit;
188 iofs.io_Union.io_OPEN_FILE.io_Filename = (STRPTR) "";
189 DosDoIO(&iofs.IOFS);
190 error = me->pr_Result2 = iofs.io_DosError;
192 else if(!Stricmp(name, (STRPTR) "*"))
194 iofs.IOFS.io_Device = ((struct FileHandle *)BADDR(ast))->fh_Device;
195 iofs.IOFS.io_Unit = ((struct FileHandle *)BADDR(ast))->fh_Unit;
196 iofs.io_Union.io_OPEN_FILE.io_Filename = (STRPTR) "";
197 DosDoIO(&iofs.IOFS);
198 error = me->pr_Result2 = iofs.io_DosError;
200 else
202 struct DevProc *dvp = NULL;
204 iofs.io_Union.io_OPEN_FILE.io_Filename = StripVolume(name);
206 do {
207 if ((dvp = GetDeviceProc(name, dvp)) == NULL) {
208 error = IoErr();
209 break;
212 error = DoIOFS(&iofs, dvp, NULL, DOSBase);
213 } while(error == ERROR_OBJECT_NOT_FOUND && accessMode != MODE_NEWFILE);
215 if (error == ERROR_NO_MORE_ENTRIES)
216 error = me->pr_Result2 = ERROR_OBJECT_NOT_FOUND;
218 if(error == ERROR_IS_SOFT_LINK)
220 ULONG buffer_size = 256;
221 STRPTR softname;
222 LONG continue_loop;
223 LONG written;
227 continue_loop = FALSE;
228 if(!(softname = AllocVec(buffer_size, MEMF_ANY)))
230 error2 = ERROR_NO_FREE_STORE;
231 break;
234 written = ReadLink(dvp->dvp_Port, dvp->dvp_Lock, name, softname, buffer_size);
235 if(written == -1)
237 /* An error occured */
238 error2 = IoErr();
240 else if(written == -2)
242 /* If there's not enough space in the buffer, increase
243 it and try again */
244 continue_loop = TRUE;
245 buffer_size *= 2;
247 else if(written >= 0)
249 /* All OK */
250 BPTR olddir;
251 olddir = CurrentDir(dvp->dvp_Lock);
252 ret = InternalOpen(softname, accessMode, handle, soft_nesting - 1, DOSBase);
253 error2 = IoErr();
254 CurrentDir(olddir);
256 else
257 error2 = ERROR_UNKNOWN;
259 FreeVec(softname);
261 while(continue_loop);
264 FreeDeviceProc(dvp);
267 if(!error)
269 handle->fh_Device = iofs.IOFS.io_Device;
270 handle->fh_Unit = iofs.IOFS.io_Unit;
271 if (doappend)
273 /* See if the handler supports FSA_SEEK */
274 if (Seek(MKBADDR(handle), 0, OFFSET_END) != -1)
276 /* if so then set the proper flag in the FileHandle struct */
277 handle->fh_Flags |= FHF_APPEND;
280 if (IsInteractive(MKBADDR(handle)))
281 SetVBuf(MKBADDR(handle), NULL, BUF_LINE, -1);
283 return DOSTRUE;
285 else if(error == ERROR_IS_SOFT_LINK)
287 if(!ret)
288 SetIoErr(error2);
289 else
290 SetIoErr(0);
291 return ret;
293 else
295 SetIoErr(error);
296 return DOSFALSE;