2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
5 Desc: Locks a file or directory.
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 /*****************************************************************************
29 #include <proto/dos.h>
34 AROS_LHA(CONST_STRPTR
, name
, D1
),
35 AROS_LHA(LONG
, accessMode
, D2
),
38 struct DosLibrary
*, DOSBase
, 14, Dos
)
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.
46 name - NUL terminated name of the file or directory.
47 accessMode - One of SHARED_LOCK
51 Handle to the file or directory or 0 if the object couldn't be locked.
52 IoErr() gives additional information in that case.
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 *****************************************************************************/
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
));
80 D(bug("[Lock] failed, err=%d\n", IoErr()));
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
);
95 ASSERT_VALID_PROCESS(me
);
98 if (!Stricmp(name
, "IN:") || !Stricmp(name
, "STDIN:")) {
99 if (lockMode
!= ACCESS_READ
) {
100 SetIoErr(ERROR_OBJECT_IN_USE
);
109 if (!Stricmp(name
, "OUT:") || !Stricmp(name
, "STDOUT:")) {
110 if (lockMode
!= ACCESS_WRITE
) {
111 SetIoErr(ERROR_OBJECT_IN_USE
);
121 if (!Stricmp(name
, "ERR:") || !Stricmp(name
, "STDERR:")) {
122 if (lockMode
!= ACCESS_WRITE
) {
123 SetIoErr(ERROR_OBJECT_IN_USE
);
135 SetIoErr(ERROR_OBJECT_NOT_FOUND
);
140 *lock
= DupLockFromFH(fh
);
142 struct FileLock
*fl
= BADDR(*lock
);
143 fl
->fl_Access
= lockMode
;
145 *ret
= (*lock
!= BNULL
) ? DOSTRUE
: DOSFALSE
;
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
);
158 struct DevProc
*dvp
= NULL
;
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
);
172 /* Check for a pseudo-file lock
173 * (ie IN:, STDOUT:, ERR:, etc)
175 if (pseudoLock(name
, accessMode
, handle
, &ret
, DOSBase
))
178 filename
= strchr(name
, ':');
181 struct MsgPort
*port
;
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
;
190 port
= DOSBase
->dl_Root
->rn_BootProc
;
194 error
= fs_LocateObject(handle
, port
, lock
, name
, accessMode
, DOSBase
);
202 if ((dvp
= GetDeviceProc(name
, dvp
)) == NULL
)
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
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
);
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.
236 olddir
= me
->pr_CurrentDir
;
237 error
= RootDir(dvp
, DOSBase
);
244 ret
= InternalLock(softname
, accessMode
, handle
, soft_nesting
- 1, DOSBase
);
245 error
= ret
? 0 : IoErr();
246 D(bug("[Lock] Resolve error %d\n", error
));
249 UnLock(CurrentDir(olddir
));
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;
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
);
294 written
= fs_ReadLink(cur
, dvp
, name
, softname
, buffer_size
, DOSBase
);
299 /* An error occured */
300 DLINK(bug("[Softlink] Error %d reading softlink\n", IoErr()));
304 /* If there's not enough space in the buffer, increase it and try again */
305 continue_loop
= TRUE
;
308 DLINK(bug("[Softlink] Increased buffer size up to %u\n", buffer_size
));
313 DLINK(bug("[Softlink] Resolved path: %s\n", softname
));
319 while(continue_loop
);
324 /* Change to root directory of the specified device */
325 LONG
RootDir(struct DevProc
*dvp
, struct DosLibrary
*DOSBase
)
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
);