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 if (error
== ERROR_NO_MORE_ENTRIES
)
213 error
= me
->pr_Result2
= ERROR_OBJECT_NOT_FOUND
;
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.
223 error
= me
->pr_Result2
= ERROR_OBJECT_NOT_FOUND
;
227 if (error
== ERROR_IS_SOFT_LINK
)
229 STRPTR softname
= ResolveSoftlink(cur
, dvp
, name
, DOSBase
);
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.
243 olddir
= me
->pr_CurrentDir
;
244 error
= RootDir(dvp
, DOSBase
);
251 ret
= InternalLock(softname
, accessMode
, handle
, soft_nesting
- 1, DOSBase
);
252 error
= ret
? 0 : IoErr();
253 D(bug("[Lock] Resolve error %d\n", error
));
256 UnLock(CurrentDir(olddir
));
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;
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
);
301 written
= fs_ReadLink(cur
, dvp
, name
, softname
, buffer_size
, DOSBase
);
306 /* An error occured */
307 DLINK(bug("[Softlink] Error %d reading softlink\n", IoErr()));
311 /* If there's not enough space in the buffer, increase it and try again */
312 continue_loop
= TRUE
;
315 DLINK(bug("[Softlink] Increased buffer size up to %u\n", buffer_size
));
320 DLINK(bug("[Softlink] Resolved path: %s\n", softname
));
326 while(continue_loop
);
331 /* Change to root directory of the specified device */
332 LONG
RootDir(struct DevProc
*dvp
, struct DosLibrary
*DOSBase
)
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
);