Detabbed
[AROS.git] / rom / dos / lock.c
blob5a7937d9b80e014d40d241680474d6c17a4f4239
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 /* FIXME: On Linux hosted we sometimes get ERROR_IS_SOFTLINK with dvp == NULL,
213 * which causes segfaults below if we don't change "error". Adding !dvp below
214 * is probably a hack
216 if (error == ERROR_NO_MORE_ENTRIES || !dvp)
217 error = me->pr_Result2 = ERROR_OBJECT_NOT_FOUND;
220 if (error == ERROR_IS_SOFT_LINK)
222 STRPTR softname = ResolveSoftlink(cur, dvp, name, DOSBase);
224 if (softname)
226 BPTR olddir = BNULL;
229 * ResolveSoftLink() gives us path relative to either 'cur' lock
230 * (if on current volume), or 'dvp' volume root (if on different volume).
231 * In the latter case we need to change current directory to volume's root
232 * in order to follow the link correctly.
234 if (dvp)
236 olddir = me->pr_CurrentDir;
237 error = RootDir(dvp, DOSBase);
239 else
240 error = 0;
242 if (!error)
244 ret = InternalLock(softname, accessMode, handle, soft_nesting - 1, DOSBase);
245 error = ret ? 0 : IoErr();
246 D(bug("[Lock] Resolve error %d\n", error));
248 if (olddir)
249 UnLock(CurrentDir(olddir));
252 FreeVec(softname);
254 else
255 error = IoErr();
258 FreeDeviceProc(dvp);
260 if (error)
262 SetIoErr(error);
263 ret = DOSFALSE;
265 else
266 ret = DOSTRUE;
268 return ret;
272 * Resolve a softlink.
273 * Returns AllocVec()ed buffer with softlink contents.
275 STRPTR ResolveSoftlink(BPTR cur, struct DevProc *dvp, CONST_STRPTR name, struct DosLibrary *DOSBase)
277 ULONG buffer_size = 256;
278 STRPTR softname;
279 LONG continue_loop;
280 LONG written;
282 DLINK(bug("[Softlink] Resolving softlink %s...\n", name));
286 continue_loop = FALSE;
288 if (!(softname = AllocVec(buffer_size, MEMF_PUBLIC|MEMF_CLEAR)))
290 SetIoErr(ERROR_NO_FREE_STORE);
291 break;
294 written = fs_ReadLink(cur, dvp, name, softname, buffer_size, DOSBase);
296 switch (written)
298 case -1:
299 /* An error occured */
300 DLINK(bug("[Softlink] Error %d reading softlink\n", IoErr()));
301 break;
303 case -2:
304 /* If there's not enough space in the buffer, increase it and try again */
305 continue_loop = TRUE;
306 buffer_size <<= 1;
308 DLINK(bug("[Softlink] Increased buffer size up to %u\n", buffer_size));
309 break;
311 default:
312 /* All OK */
313 DLINK(bug("[Softlink] Resolved path: %s\n", softname));
314 return softname;
317 FreeVec(softname);
319 while(continue_loop);
321 return NULL;
324 /* Change to root directory of the specified device */
325 LONG RootDir(struct DevProc *dvp, struct DosLibrary *DOSBase)
327 BPTR lock = BNULL;
328 LONG error;
330 /* We already have a DeviceProc structure, so just use internal routine. */
331 error = fs_LocateObject(&lock, dvp->dvp_Port, dvp->dvp_Lock, "", SHARED_LOCK, DOSBase);
333 if (!error)
334 CurrentDir(lock);
336 return error;