Updated PCI IDs to latest snapshot.
[tangerine.git] / rom / dos / lock.c
blob63e958adeeb7bd55e044d481b3453b444acd69b2
1 /*
2 Copyright © 1995-2008, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Locks a file or directory.
6 Lang: English
7 */
9 #include <proto/exec.h>
10 #include <utility/tagitem.h>
11 #include <dos/dosextens.h>
12 #include <dos/filesystem.h>
13 #include <proto/dos.h>
14 #include <proto/utility.h>
15 #include "dos_intern.h"
17 #define DEBUG 0
18 #include <aros/debug.h>
20 LONG InternalLock(CONST_STRPTR name, LONG accessMode,
21 struct FileHandle *handle, LONG soft_nesting, struct DosLibrary *DOSBase);
23 #define MAX_SOFT_LINK_NESTING 16 /* Maximum level of soft links nesting */
25 /*****************************************************************************
27 NAME */
28 #include <proto/dos.h>
30 AROS_LH2(BPTR, Lock,
32 /* SYNOPSIS */
33 AROS_LHA(CONST_STRPTR, name, D1),
34 AROS_LHA(LONG, accessMode, D2),
36 /* LOCATION */
37 struct DosLibrary *, DOSBase, 14, Dos)
39 /* FUNCTION
40 Gets a lock on a file or directory. There may be more than one
41 shared lock on a file but only one if it is an exclusive one.
42 Locked files or directories may not be deleted.
44 INPUTS
45 name - NUL terminated name of the file or directory.
46 accessMode - One of SHARED_LOCK
47 EXCLUSIVE_LOCK
49 RESULT
50 Handle to the file or directory or 0 if the object couldn't be locked.
51 IoErr() gives additional information in that case.
53 NOTES
54 The lock structure returned by this function is different
55 from that of AmigaOS (in fact it is identical to a filehandle).
56 Do not try to read any internal fields.
58 *****************************************************************************/
61 AROS_LIBFUNC_INIT
63 LONG error;
65 ASSERT_VALID_PTR(name);
67 /* Sanity check */
68 if (name == NULL)
69 return NULL;
71 /* Create filehandle */
72 struct FileHandle *ret = (struct FileHandle *)AllocDosObject(DOS_FILEHANDLE, NULL);
74 if (ret != NULL)
76 if(InternalLock(name, accessMode, ret, MAX_SOFT_LINK_NESTING, DOSBase))
78 return MKBADDR(ret);
80 else
82 error = IoErr();
83 FreeDosObject(DOS_FILEHANDLE, ret);
86 else
88 error = ERROR_NO_FREE_STORE;
91 SetIoErr(error);
92 return NULL;
94 AROS_LIBFUNC_EXIT
95 } /* Lock */
97 /* Try to lock name recursively calling itself in case it's a soft link.
98 Store result in handle. Return boolean value indicating result. */
99 LONG InternalLock(CONST_STRPTR name, LONG accessMode,
100 struct FileHandle *handle, LONG soft_nesting, struct DosLibrary *DOSBase)
102 /* Get pointer to I/O request. Use stackspace for now. */
103 struct IOFileSys iofs;
104 /* Get pointer to process structure */
105 struct Process *me = (struct Process *)FindTask(NULL);
106 struct DevProc *dvp;
107 LONG ret = DOSFALSE;
108 LONG error = 0;
109 LONG error2 = 0;
111 if(soft_nesting == 0)
113 SetIoErr(ERROR_TOO_MANY_LEVELS);
114 return DOSFALSE;
117 /* Prepare I/O request. */
118 InitIOFS(&iofs, FSA_OPEN, DOSBase);
120 switch (accessMode)
122 case EXCLUSIVE_LOCK:
123 iofs.io_Union.io_OPEN.io_FileMode = FMF_LOCK | FMF_READ;
124 break;
126 case SHARED_LOCK:
127 iofs.io_Union.io_OPEN.io_FileMode = FMF_READ;
128 break;
130 default:
131 D(bug("[Lock] incompatible mode %d\n", accessMode));
132 SetIoErr(ERROR_ACTION_NOT_KNOWN);
133 return DOSFALSE;
136 /* catch the zero-length special case. we can't (currently) call
137 * GetDeviceProc(), as it will call NameFromLock(), which will
138 * DupLock(), which will end up here */
139 if (*name == '\0') {
140 BPTR cur;
141 struct FileHandle *fh;
143 cur = me->pr_CurrentDir;
144 if (!cur)
145 cur = DOSBase->dl_SYSLock;
147 if (cur)
149 fh = BADDR(cur);
151 iofs.io_Union.io_OPEN.io_Filename = (STRPTR) "";
153 iofs.IOFS.io_Device = fh->fh_Device;
154 iofs.IOFS.io_Unit = fh->fh_Unit;
156 DosDoIO(&iofs.IOFS);
158 error = me->pr_Result2 = iofs.io_DosError;
160 else
162 error = ERROR_OBJECT_NOT_FOUND;
163 SetIoErr(error);
166 else
168 iofs.io_Union.io_OPEN.io_Filename = StripVolume(name);
169 dvp = NULL;
173 if ((dvp = GetDeviceProc(name, dvp)) == NULL)
175 error = IoErr();
176 break;
179 error = DoIOFS(&iofs, dvp, NULL, DOSBase);
180 } while (error == ERROR_OBJECT_NOT_FOUND);
182 if (error == ERROR_NO_MORE_ENTRIES)
183 error = me->pr_Result2 = ERROR_OBJECT_NOT_FOUND;
185 if(error == ERROR_IS_SOFT_LINK)
187 ULONG buffer_size = 256;
188 STRPTR softname;
189 LONG continue_loop;
190 LONG written;
194 continue_loop = FALSE;
195 if(!(softname = AllocVec(buffer_size, MEMF_PUBLIC)))
197 error2 = ERROR_NO_FREE_STORE;
198 break;
201 written = ReadLink(dvp->dvp_Port, dvp->dvp_Lock, name, softname, buffer_size);
202 if(written == -1)
204 /* An error occured */
205 error2 = IoErr();
207 else if(written == -2)
209 /* If there's not enough space in the buffer, increase
210 it and try again */
211 continue_loop = TRUE;
212 buffer_size *= 2;
214 else if(written >= 0)
216 /* All OK */
217 BPTR olddir;
218 olddir = CurrentDir(dvp->dvp_Lock);
219 ret = InternalLock(softname, accessMode, handle, soft_nesting - 1, DOSBase);
220 error2 = IoErr();
221 CurrentDir(olddir);
223 else
224 error2 = ERROR_UNKNOWN;
226 FreeVec(softname);
228 while(continue_loop);
231 FreeDeviceProc(dvp);
234 if(!error)
236 handle->fh_Device = iofs.IOFS.io_Device;
237 handle->fh_Unit = iofs.IOFS.io_Unit;
238 return DOSTRUE;
240 else if(error == ERROR_IS_SOFT_LINK)
242 if(!ret)
243 SetIoErr(error2);
244 else
245 SetIoErr(0);
246 return ret;
248 else
250 SetIoErr(error);
251 return DOSFALSE;