2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
5 Desc: GetDeviceProc() - Find the filesystem for a path.
9 #include <aros/debug.h>
11 #include <proto/exec.h>
12 #include <proto/utility.h>
14 #include "dos_intern.h"
16 extern struct Process
*r(struct DeviceNode
*dn
, struct DosLibrary
*DOSBase
);
17 static struct DevProc
*deviceproc_internal(struct DosLibrary
*DOSBase
, CONST_STRPTR name
, struct DevProc
*dp
);
19 /*****************************************************************************
22 #include <proto/dos.h>
24 AROS_LH2(struct DevProc
*, GetDeviceProc
,
27 AROS_LHA(CONST_STRPTR
, name
, D1
),
28 AROS_LHA(struct DevProc
*, dp
, D2
),
31 struct DosLibrary
*, DOSBase
, 107, Dos
)
34 GetDeviceProc() will search for the filesystem handler which
35 you should send a command to for a specific path.
37 By calling GetDeviceProc() multiple times, the caller will
38 be able to handle multi-assign paths.
40 The first call to GetDeviceProc() should have the |dp| parameter
44 name - Name of the object to find.
45 dp - Previous result of GetDeviceProc() or NULL.
48 A pointer to a DevProc structure containing the information
49 required to send a command to a filesystem.
56 Currently doesn't return dvp_DevNode for locks which are
57 relative to "PROGDIR:", ":", or the current directory.
64 *****************************************************************************/
70 D(bug("[GetDeviceProc] '%s':0x%p\n", name
, dp
));
71 dp2
= deviceproc_internal(DOSBase
, name
, dp
);
74 bug("[GetDeviceProc] = 0x%p", dp2
);
76 bug(", port=0x%p lock=0x%p dv=0x%p\n", dp2
->dvp_Port
, dp2
->dvp_Lock
, dp2
->dvp_DevNode
);
86 static struct DevProc
*deviceproc_internal(struct DosLibrary
*DOSBase
, CONST_STRPTR name
, struct DevProc
*dp
)
88 struct Process
*pr
= (struct Process
*)FindTask(NULL
);
89 struct DosList
*dl
= NULL
;
94 CONST_STRPTR origname
= name
;
97 ASSERT_VALID_PROCESS(pr
);
99 /* if they passed us the result of a previous call, then they're wanted to
100 * loop over the targets of a multidirectory assign */
103 /* if what they passed us is not a multidirectory assign, then there's
104 * nothing for us to do */
105 if (dp
->dvp_DevNode
!= NULL
&&
106 (dp
->dvp_DevNode
->dol_Type
!= DLT_DIRECTORY
|| !(dp
->dvp_Flags
& DVPF_ASSIGN
))) {
109 if (dp
->dvp_Flags
& DVPF_UNLOCK
)
110 UnLock(dp
->dvp_Lock
);
112 FreeMem(dp
, sizeof(struct DevProc
));
113 SetIoErr(ERROR_NO_MORE_ENTRIES
);
117 /* it's fine, we'll start from here */
118 dl
= dp
->dvp_DevNode
;
120 /* lock the dos list here, to match the result of the next block */
121 LockDosList(LDF_ALL
| LDF_READ
);
124 /* otherwise we need to find a place to start in the doslist based on the
125 * name they passed in */
127 /* allocate structure for return */
128 if ((dp
= AllocMem(sizeof(struct DevProc
), MEMF_ANY
| MEMF_CLEAR
)) == NULL
) {
129 SetIoErr(ERROR_NO_FREE_STORE
);
133 /* something real, work out what it's relative to */
134 if (Strnicmp(name
, "PROGDIR:", 8) == 0) {
135 lock
= pr
->pr_HomeDir
;
136 /* I am not sure if these are correct but AOS does return
137 * non-NULL PROGDIR: handle even if pr_HomeDir is cleared */
139 lock
= pr
->pr_CurrentDir
;
142 dp
->dvp_Port
= fl
->fl_Task
;
144 dp
->dvp_DevNode
= BADDR(fl
->fl_Volume
);
146 dp
->dvp_Port
= DOSBase
->dl_Root
->rn_BootProc
;
147 dp
->dvp_Lock
= BNULL
;
148 dp
->dvp_DevNode
= NULL
;
154 /* extract the volume name */
155 len
= SplitName(name
, ':', vol
, 0, sizeof(vol
) - 1);
157 /* if there wasn't one (or we found a lone ':') -> current dir */
159 lock
= pr
->pr_CurrentDir
;
160 /* if we got NULL, then it's relative to the system root lock */
163 dp
->dvp_Port
= fl
->fl_Task
;
165 dp
->dvp_DevNode
= BADDR(fl
->fl_Volume
);
167 dp
->dvp_Port
= DOSBase
->dl_Root
->rn_BootProc
;
168 dp
->dvp_Lock
= BNULL
;
169 dp
->dvp_DevNode
= NULL
;
172 /* Jump to the root directory if name[0] == ':' */
174 dp
->dvp_Lock
= (dp
->dvp_DevNode
) ? dp
->dvp_DevNode
->dol_Lock
: BNULL
;
181 /* now find the doslist entry for the named volume */
182 dl
= LockDosList(LDF_ALL
| LDF_READ
);
183 dl
= FindDosEntry(dl
, vol
, LDF_ALL
);
185 /* not found, bail out */
187 UnLockDosList(LDF_ALL
| LDF_READ
);
189 if (ErrorReport(ERROR_DEVICE_NOT_MOUNTED
, REPORT_INSERT
, (IPTR
)vol
, NULL
) == DOSTRUE
) {
190 FreeMem(dp
, sizeof(struct DevProc
));
197 /* at this point, we have an allocated devproc in dp, the doslist is
198 * locked for read, and we have the entry for the named "volume"
199 * (device, assign, etc) in dl and a filename relative to that in name */
201 /* late assign. we resolve the target and then promote the doslist entry
203 if (dl
->dol_Type
== DLT_LATE
) {
204 /* obtain a lock on the target */
205 lock
= Lock(dl
->dol_misc
.dol_assign
.dol_AssignName
, SHARED_LOCK
);
207 /* didn't find the target */
209 UnLockDosList(LDF_ALL
| LDF_READ
);
210 FreeMem(dp
, sizeof(struct DevProc
));
214 /* Directly change assign type without calling AssignXXX(),
215 * mimics AOS behavior, AOS programs assume it is safe to
216 * keep LDF_WRITE lock while calling Lock("late assign:");
218 dl
->dol_Type
= DLT_DIRECTORY
;
220 dl
->dol_Task
= ((struct FileLock
*)BADDR(lock
))->fl_Task
;
221 FreeVec(dl
->dol_misc
.dol_assign
.dol_AssignName
);
222 dl
->dol_misc
.dol_assign
.dol_AssignName
= NULL
;
224 /* the added entry will be a DLT_DIRECTORY, so we can just copy the
225 * details in and get out of here */
226 dp
->dvp_Port
= dl
->dol_Task
;
227 dp
->dvp_Lock
= dl
->dol_Lock
;
229 dp
->dvp_DevNode
= dl
;
231 UnLockDosList(LDF_ALL
| LDF_READ
);
236 /* nonbinding assign. like a late assign, but with no doslist promotion */
237 if (dl
->dol_Type
== DLT_NONBINDING
) {
238 lock
= Lock(dl
->dol_misc
.dol_assign
.dol_AssignName
, SHARED_LOCK
);
240 /* just fill out the dp and return */
241 dp
->dvp_Port
= ((struct FileLock
*) BADDR(lock
))->fl_Task
;
243 dp
->dvp_Flags
= DVPF_UNLOCK
; /* remember to unlock in FreeDeviceNode() */
244 dp
->dvp_DevNode
= dl
;
246 UnLockDosList(LDF_ALL
| LDF_READ
);
251 /* devices and volumes are easy */
252 if (dl
->dol_Type
== DLT_DEVICE
|| dl
->dol_Type
== DLT_VOLUME
)
254 struct MsgPort
*newhandler
= NULL
;
256 if (dl
->dol_Type
== DLT_DEVICE
)
258 /* Check if the handler is not started */
259 newhandler
= dl
->dol_Task
;
262 D(bug("[GetDeviceProc] Accessing device '%b', path='%s'\n", dl
->dol_Name
, origname
));
265 * Unlock before starting handler, handler may internally
266 * require dos list locks, for example to add volume node.
268 UnLockDosList(LDF_ALL
| LDF_READ
);
270 newhandler
= RunHandler((struct DeviceNode
*)dl
, origname
, DOSBase
);
273 FreeMem(dp
, sizeof(struct DevProc
));
274 SetIoErr(ERROR_DEVICE_NOT_MOUNTED
);
278 LockDosList(LDF_ALL
| LDF_READ
);
285 while (res
&& !dl
->dol_Task
)
287 D(bug("[GetDeviceProc] Accessing offline volume '%b'\n", dl
->dol_Name
));
288 res
= !ErrorReport(ERROR_DEVICE_NOT_MOUNTED
, REPORT_VOLUME
, (IPTR
)dl
, NULL
);
293 UnLockDosList(LDF_ALL
| LDF_READ
);
294 FreeMem(dp
, sizeof(struct DevProc
));
295 SetIoErr(ERROR_DEVICE_NOT_MOUNTED
);
301 * A handler theoretically may choose to use custom MsgPort for communications.
302 * Pick up its preference if specified.
304 dp
->dvp_Port
= dl
->dol_Task
? dl
->dol_Task
: newhandler
;
305 dp
->dvp_Lock
= BNULL
;
307 dp
->dvp_DevNode
= dl
;
309 UnLockDosList(LDF_ALL
| LDF_READ
);
315 if (dl
->dol_Type
!= DLT_DIRECTORY
) {
316 UnLockDosList(LDF_ALL
| LDF_READ
);
317 FreeMem(dp
, sizeof(struct DevProc
));
318 kprintf("%s:%d: DosList entry 0x%p has unknown type %d. Probably a bug, report it!\n"
319 " GetDeviceProc() called for '%s'\n",
320 __FILE__
, __LINE__
, dl
, dl
->dol_Type
, name
);
321 SetIoErr(ERROR_BAD_NUMBER
);
325 /* real assigns. first, see if it's just pointing to a single dir */
326 if (dp
->dvp_Flags
!= DVPF_ASSIGN
) {
327 /* just a plain assign, easy */
328 dp
->dvp_Port
= dl
->dol_Task
;
329 dp
->dvp_Lock
= dl
->dol_Lock
;
330 dp
->dvp_DevNode
= dl
;
332 /* note multidirectory assigns so the caller knows to loop */
333 dp
->dvp_Flags
= dl
->dol_misc
.dol_assign
.dol_List
!= NULL
? DVPF_ASSIGN
: 0;
335 UnLockDosList(LDF_ALL
| LDF_READ
);
339 /* finally the tricky bit - multidirectory assigns */
341 /* if we're pointing at the "primary" lock, then we just take the first
343 if (dp
->dvp_Lock
== dl
->dol_Lock
)
344 dp
->dvp_Lock
= dl
->dol_misc
.dol_assign
.dol_List
->al_Lock
;
346 /* otherwise we're finding the next */
348 struct AssignList
*al
= dl
->dol_misc
.dol_assign
.dol_List
;
350 /* find our current lock (ie the one we returned last time) */
351 for (; al
!= NULL
&& al
->al_Lock
!= dp
->dvp_Lock
; al
= al
->al_Next
);
353 /* if we didn't find it, or we didn't but there's none after it, then
355 if (al
== NULL
|| (al
= al
->al_Next
) == NULL
) {
356 UnLockDosList(LDF_ALL
| LDF_READ
);
357 FreeMem(dp
, sizeof(struct DevProc
));
359 SetIoErr(ERROR_NO_MORE_ENTRIES
);
363 /* fill out the lock from the new entry */
364 dp
->dvp_Lock
= al
->al_Lock
;
368 dp
->dvp_Port
= ((struct FileLock
*) BADDR(dp
->dvp_Lock
))->fl_Task
;
369 dp
->dvp_Flags
= DVPF_ASSIGN
;
370 dp
->dvp_DevNode
= dl
;
372 UnLockDosList(LDF_READ
|LDF_ALL
);