Do not try to get stack pointer from invalid ESP field, which coincidentally
[AROS.git] / rom / dos / lock.c
blob32f5fa6811539e58afa2544ad833318d432ad177
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 DEBUG 0
10 #define DLINK(x)
12 #include <aros/debug.h>
13 #include <proto/exec.h>
14 #include <utility/tagitem.h>
15 #include <dos/dosextens.h>
16 #include <dos/filesystem.h>
17 #include <proto/dos.h>
18 #include <proto/utility.h>
20 #include "dos_intern.h"
21 #include "fs_driver.h"
23 static LONG InternalLock(CONST_STRPTR name, LONG accessMode,
24 BPTR *handle, LONG soft_nesting, struct DosLibrary *DOSBase);
26 #define MAX_SOFT_LINK_NESTING 16 /* Maximum level of soft links nesting */
28 /*****************************************************************************
30 NAME */
31 #include <proto/dos.h>
33 AROS_LH2(BPTR, Lock,
35 /* SYNOPSIS */
36 AROS_LHA(CONST_STRPTR, name, D1),
37 AROS_LHA(LONG, accessMode, D2),
39 /* LOCATION */
40 struct DosLibrary *, DOSBase, 14, Dos)
42 /* FUNCTION
43 Gets a lock on a file or directory. There may be more than one
44 shared lock on a file but only one if it is an exclusive one.
45 Locked files or directories may not be deleted.
47 INPUTS
48 name - NUL terminated name of the file or directory.
49 accessMode - One of SHARED_LOCK
50 EXCLUSIVE_LOCK
52 RESULT
53 Handle to the file or directory or 0 if the object couldn't be locked.
54 IoErr() gives additional information in that case.
56 NOTES
57 The lock structure returned by this function is different
58 from that of AmigaOS (in fact it is identical to a filehandle).
59 Do not try to read any internal fields.
61 *****************************************************************************/
64 AROS_LIBFUNC_INIT
66 BPTR fl;
68 /* Sanity check */
69 if (name == NULL)
70 return BNULL;
72 ASSERT_VALID_PTR(name);
74 D(bug("[Lock] '%s':%d\n", name, accessMode));
76 if (InternalLock(name, accessMode, &fl, MAX_SOFT_LINK_NESTING, DOSBase))
78 D(bug("[Lock] returned 0x%p\n", fl));
79 return fl;
82 D(bug("[Lock] failed, err=%d\n", IoErr()));
83 return BNULL;
85 AROS_LIBFUNC_EXIT
86 } /* Lock */
88 /* Try to lock name recursively calling itself in case it's a soft link.
89 Store result in handle. Return boolean value indicating result. */
90 static LONG InternalLock(CONST_STRPTR name, LONG accessMode,
91 BPTR *handle, LONG soft_nesting, struct DosLibrary *DOSBase)
93 /* Get pointer to process structure */
94 struct Process *me = (struct Process *)FindTask(NULL);
95 BPTR cur = BNULL;
96 struct DevProc *dvp = NULL;
97 LONG ret = DOSFALSE;
98 LONG error = 0;
99 STRPTR filename;
101 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));
103 if(soft_nesting == 0)
105 SetIoErr(ERROR_TOO_MANY_LEVELS);
106 return DOSFALSE;
109 filename = strchr(name, ':');
110 if (!filename)
112 /* No ':' in the pathname, path is relative to current directory */
113 cur = me->pr_CurrentDir;
114 if (!cur)
115 cur = DOSBase->dl_SYSLock;
117 if (cur && (cur != (BPTR)-1))
118 error = fs_LocateObject(handle, cur, NULL, name, accessMode, DOSBase);
119 else
120 error = ERROR_OBJECT_NOT_FOUND;
122 SetIoErr(error);
124 else
126 filename++;
129 if ((dvp = GetDeviceProc(name, dvp)) == NULL)
131 error = IoErr();
132 break;
135 error = fs_LocateObject(handle, BNULL, dvp, filename, accessMode, DOSBase);
137 } while (error == ERROR_OBJECT_NOT_FOUND);
139 /* FIXME: On Linux hosted we sometimes get ERROR_IS_SOFTLINK with dvp == NULL,
140 * which causes segfaults below if we don't change "error". Adding !dvp below
141 * is probably a hack
143 if (error == ERROR_NO_MORE_ENTRIES || !dvp)
144 error = me->pr_Result2 = ERROR_OBJECT_NOT_FOUND;
147 if (error == ERROR_IS_SOFT_LINK)
149 STRPTR softname = ResolveSoftlink(cur, dvp, name, DOSBase);
151 if (softname)
153 BPTR olddir = BNULL;
156 * ResolveSoftLink() gives us path relative to either 'cur' lock
157 * (if on current volume), or 'dvp' volume root (if on different volume).
158 * In the latter case we need to change current directory to volume's root
159 * in order to follow the link correctly.
161 if (dvp)
163 olddir = me->pr_CurrentDir;
164 error = RootDir(dvp, DOSBase);
166 else
167 error = 0;
169 if (!error)
171 ret = InternalLock(softname, accessMode, handle, soft_nesting - 1, DOSBase);
172 error = ret ? 0 : IoErr();
173 D(bug("[Lock] Resolve error %d\n", error));
175 if (olddir)
176 UnLock(CurrentDir(olddir));
179 FreeVec(softname);
181 else
182 error = IoErr();
185 FreeDeviceProc(dvp);
187 if (error)
189 SetIoErr(error);
190 ret = DOSFALSE;
192 else
193 ret = DOSTRUE;
195 return ret;
199 * Resolve a softlink.
200 * Returns AllocVec()ed buffer with softlink contents.
202 STRPTR ResolveSoftlink(BPTR cur, struct DevProc *dvp, CONST_STRPTR name, struct DosLibrary *DOSBase)
204 ULONG buffer_size = 256;
205 STRPTR softname;
206 LONG continue_loop;
207 LONG written;
209 DLINK(bug("[Softlink] Resolving softlink %s...\n", name));
213 continue_loop = FALSE;
215 if (!(softname = AllocVec(buffer_size, MEMF_PUBLIC|MEMF_CLEAR)))
217 SetIoErr(ERROR_NO_FREE_STORE);
218 break;
221 written = fs_ReadLink(cur, dvp, name, softname, buffer_size, DOSBase);
223 switch (written)
225 case -1:
226 /* An error occured */
227 DLINK(bug("[Softlink] Error %d reading softlink\n", IoErr()));
228 break;
230 case -2:
231 /* If there's not enough space in the buffer, increase it and try again */
232 continue_loop = TRUE;
233 buffer_size <<= 1;
235 DLINK(bug("[Softlink] Increased buffer size up to %u\n", buffer_size));
236 break;
238 default:
239 /* All OK */
240 DLINK(bug("[Softlink] Resolved path: %s\n", softname));
241 return softname;
244 FreeVec(softname);
246 while(continue_loop);
248 return NULL;
251 /* Change to root directory of the specified device */
252 LONG RootDir(struct DevProc *dvp, struct DosLibrary *DOSBase)
254 BPTR lock = BNULL;
255 LONG error;
257 /* We already have a DeviceProc structure, so just use internal routine. */
258 error = fs_LocateObject(&lock, BNULL, dvp, "", SHARED_LOCK, DOSBase);
260 if (!error)
261 CurrentDir(lock);
263 return error;