delint/fix to build with paranoia flags
[AROS.git] / rom / dos / lock.c
blob25b125fe2a0f5596e891eee6325c7b1556c3066d
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Locks a file or directory.
6 Lang: English
7 */
9 #define DLINK(x)
11 #include <aros/debug.h>
12 #include <proto/exec.h>
13 #include <utility/tagitem.h>
14 #include <dos/dosextens.h>
15 #include <proto/dos.h>
16 #include <proto/utility.h>
18 #include "dos_intern.h"
19 #include "fs_driver.h"
21 static LONG InternalLock(CONST_STRPTR name, LONG accessMode,
22 BPTR *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, Lock,
33 /* SYNOPSIS */
34 AROS_LHA(CONST_STRPTR, name, D1),
35 AROS_LHA(LONG, accessMode, D2),
37 /* LOCATION */
38 struct DosLibrary *, DOSBase, 14, Dos)
40 /* FUNCTION
41 Gets a lock on a file or directory. There may be more than one
42 shared lock on a file but only one if it is an exclusive one.
43 Locked files or directories may not be deleted.
45 INPUTS
46 name - NUL terminated name of the file or directory.
47 accessMode - One of SHARED_LOCK
48 EXCLUSIVE_LOCK
50 RESULT
51 Handle to the file or directory or 0 if the object couldn't be locked.
52 IoErr() gives additional information in that case.
54 NOTES
55 The lock structure returned by this function is different
56 from that of AmigaOS (in fact it is identical to a filehandle).
57 Do not try to read any internal fields.
59 *****************************************************************************/
62 AROS_LIBFUNC_INIT
64 BPTR fl;
66 /* Sanity check */
67 if (name == NULL)
68 return BNULL;
70 ASSERT_VALID_PTR(name);
72 D(bug("[Lock] '%s':%d\n", name, accessMode));
74 if (InternalLock(name, accessMode, &fl, MAX_SOFT_LINK_NESTING, DOSBase))
76 D(bug("[Lock] returned 0x%p\n", fl));
77 return fl;
80 D(bug("[Lock] failed, err=%d\n", IoErr()));
81 return BNULL;
83 AROS_LIBFUNC_EXIT
84 } /* Lock */
87 /* Attempt to create a synthetic IN:, OUT:, ERR:,
88 * STDIN:, STDOUT, or STDERR: lock
90 BOOL pseudoLock(CONST_STRPTR name, LONG lockMode, BPTR *lock, LONG *ret, struct DosLibrary *DOSBase)
92 struct Process *me = (struct Process *)FindTask(NULL);
93 BPTR fh = (BPTR)-1;
95 ASSERT_VALID_PROCESS(me);
97 /* IN:, STDIN: */
98 if (!Stricmp(name, "IN:") || !Stricmp(name, "STDIN:")) {
99 if (lockMode != ACCESS_READ) {
100 SetIoErr(ERROR_OBJECT_IN_USE);
101 *ret = DOSFALSE;
102 return TRUE;
105 fh = me->pr_CIS;
108 /* OUT:, STDOUT: */
109 if (!Stricmp(name, "OUT:") || !Stricmp(name, "STDOUT:")) {
110 if (lockMode != ACCESS_WRITE) {
111 SetIoErr(ERROR_OBJECT_IN_USE);
112 *ret = DOSFALSE;
113 return TRUE;
116 fh = me->pr_COS;
120 /* ERR:, STDERR: */
121 if (!Stricmp(name, "ERR:") || !Stricmp(name, "STDERR:")) {
122 if (lockMode != ACCESS_WRITE) {
123 SetIoErr(ERROR_OBJECT_IN_USE);
124 *ret = DOSFALSE;
125 return TRUE;
128 fh = me->pr_CES;
131 if (fh == (BPTR)-1)
132 return FALSE;
134 if (fh == BNULL) {
135 SetIoErr(ERROR_OBJECT_NOT_FOUND);
136 *ret = DOSFALSE;
137 return TRUE;
140 *lock = DupLockFromFH(fh);
141 if (*lock) {
142 struct FileLock *fl = BADDR(*lock);
143 fl->fl_Access = lockMode;
145 *ret = (*lock != BNULL) ? DOSTRUE : DOSFALSE;
146 return TRUE;
150 /* Try to lock name recursively calling itself in case it's a soft link.
151 Store result in handle. Return boolean value indicating result. */
152 static LONG InternalLock(CONST_STRPTR name, LONG accessMode,
153 BPTR *handle, LONG soft_nesting, struct DosLibrary *DOSBase)
155 /* Get pointer to process structure */
156 struct Process *me = (struct Process *)FindTask(NULL);
157 BPTR cur = BNULL;
158 struct DevProc *dvp = NULL;
159 LONG ret = DOSFALSE;
160 LONG error = 0;
161 STRPTR filename;
163 ASSERT_VALID_PROCESS(me);
164 D(bug("[Lock] Process: 0x%p \"%s\", Window: 0x%p, Name: \"%s\", \n", me, me->pr_Task.tc_Node.ln_Name, me->pr_WindowPtr, name));
166 if(soft_nesting == 0)
168 SetIoErr(ERROR_TOO_MANY_LEVELS);
169 return DOSFALSE;
172 /* Check for a pseudo-file lock
173 * (ie IN:, STDOUT:, ERR:, etc)
175 if (pseudoLock(name, accessMode, handle, &ret, DOSBase))
176 return ret;
178 filename = strchr(name, ':');
179 if (!filename)
181 struct MsgPort *port;
182 BPTR lock;
184 /* No ':' in the pathname, path is relative to current directory */
185 cur = me->pr_CurrentDir;
186 if (cur && cur != (BPTR)-1) {
187 port = ((struct FileLock *)BADDR(cur))->fl_Task;
188 lock = cur;
189 } else {
190 port = DOSBase->dl_Root->rn_BootProc;
191 lock = BNULL;
194 error = fs_LocateObject(handle, port, lock, name, accessMode, DOSBase);
195 SetIoErr(error);
197 else
199 filename++;
202 if ((dvp = GetDeviceProc(name, dvp)) == NULL)
204 error = IoErr();
205 break;
208 error = fs_LocateObject(handle, dvp->dvp_Port, dvp->dvp_Lock, filename, accessMode, DOSBase);
210 } while (error == ERROR_OBJECT_NOT_FOUND);
212 if (error == ERROR_NO_MORE_ENTRIES)
213 error = me->pr_Result2 = ERROR_OBJECT_NOT_FOUND;
215 #ifndef __mc68000
216 /* FIXME: On Linux hosted we sometimes get ERROR_IS_SOFTLINK with dvp == NULL,
217 * which causes segfaults below if we don't change "error". Adding !dvp below
218 * is probably a hack.
220 * This is wrong, GetDeviceProc() can return other errors than ERROR_OBJECT_NOT_FOUND.
222 if (!dvp)
223 error = me->pr_Result2 = ERROR_OBJECT_NOT_FOUND;
224 #endif
227 if (error == ERROR_IS_SOFT_LINK)
229 STRPTR softname = ResolveSoftlink(cur, dvp, name, DOSBase);
231 if (softname)
233 BPTR olddir = BNULL;
236 * ResolveSoftlink() gives us path relative to either 'cur' lock
237 * (if on current volume), or 'dvp' volume root (if on different volume).
238 * In the latter case we need to change current directory to volume's root
239 * in order to follow the link correctly.
241 if (dvp)
243 olddir = me->pr_CurrentDir;
244 error = RootDir(dvp, DOSBase);
246 else
247 error = 0;
249 if (!error)
251 ret = InternalLock(softname, accessMode, handle, soft_nesting - 1, DOSBase);
252 error = ret ? 0 : IoErr();
253 D(bug("[Lock] Resolve error %d\n", error));
255 if (olddir)
256 UnLock(CurrentDir(olddir));
259 FreeVec(softname);
261 else
262 error = IoErr();
265 FreeDeviceProc(dvp);
267 if (error)
269 SetIoErr(error);
270 ret = DOSFALSE;
272 else
273 ret = DOSTRUE;
275 return ret;
279 * Resolve a softlink.
280 * Returns AllocVec()ed buffer with softlink contents.
282 STRPTR ResolveSoftlink(BPTR cur, struct DevProc *dvp, CONST_STRPTR name, struct DosLibrary *DOSBase)
284 ULONG buffer_size = 256;
285 STRPTR softname;
286 LONG continue_loop;
287 LONG written;
289 DLINK(bug("[Softlink] Resolving softlink %s...\n", name));
293 continue_loop = FALSE;
295 if (!(softname = AllocVec(buffer_size, MEMF_PUBLIC|MEMF_CLEAR)))
297 SetIoErr(ERROR_NO_FREE_STORE);
298 break;
301 written = fs_ReadLink(cur, dvp, name, softname, buffer_size, DOSBase);
303 switch (written)
305 case -1:
306 /* An error occured */
307 DLINK(bug("[Softlink] Error %d reading softlink\n", IoErr()));
308 break;
310 case -2:
311 /* If there's not enough space in the buffer, increase it and try again */
312 continue_loop = TRUE;
313 buffer_size <<= 1;
315 DLINK(bug("[Softlink] Increased buffer size up to %u\n", buffer_size));
316 break;
318 default:
319 /* All OK */
320 DLINK(bug("[Softlink] Resolved path: %s\n", softname));
321 return softname;
324 FreeVec(softname);
326 while(continue_loop);
328 return NULL;
331 /* Change to root directory of the specified device */
332 LONG RootDir(struct DevProc *dvp, struct DosLibrary *DOSBase)
334 BPTR lock = BNULL;
335 LONG error;
337 /* We already have a DeviceProc structure, so just use internal routine. */
338 error = fs_LocateObject(&lock, dvp->dvp_Port, dvp->dvp_Lock, "", SHARED_LOCK, DOSBase);
340 if (!error)
341 CurrentDir(lock);
343 return error;