2 Copyright © 1995-2016, 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 want 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 if (name
== NULL
|| Strnicmp(name
, "NIL:", 4) == 0) {
128 SetIoErr(ERROR_DEVICE_NOT_MOUNTED
);
132 /* allocate structure for return */
133 if ((dp
= AllocMem(sizeof(struct DevProc
), MEMF_ANY
| MEMF_CLEAR
)) == NULL
) {
134 SetIoErr(ERROR_NO_FREE_STORE
);
138 /* something real, work out what it's relative to */
139 if (Strnicmp(name
, "PROGDIR:", 8) == 0) {
140 lock
= pr
->pr_HomeDir
;
141 /* I am not sure if these are correct but AOS does return
142 * non-NULL PROGDIR: handle even if pr_HomeDir is cleared */
144 lock
= pr
->pr_CurrentDir
;
147 dp
->dvp_Port
= fl
->fl_Task
;
149 dp
->dvp_DevNode
= BADDR(fl
->fl_Volume
);
151 dp
->dvp_Port
= DOSBase
->dl_Root
->rn_BootProc
;
152 dp
->dvp_Lock
= BNULL
;
153 dp
->dvp_DevNode
= NULL
;
159 /* extract the volume name */
160 len
= SplitName(name
, ':', vol
, 0, sizeof(vol
) - 1);
162 /* if there wasn't one (or we found a lone ':') -> current dir */
164 lock
= pr
->pr_CurrentDir
;
165 /* if we got NULL, then it's relative to the system root lock */
168 dp
->dvp_Port
= fl
->fl_Task
;
170 dp
->dvp_DevNode
= BADDR(fl
->fl_Volume
);
172 dp
->dvp_Port
= DOSBase
->dl_Root
->rn_BootProc
;
173 dp
->dvp_Lock
= BNULL
;
174 dp
->dvp_DevNode
= NULL
;
177 /* Jump to the root directory if name[0] == ':' */
179 dp
->dvp_Lock
= (dp
->dvp_DevNode
) ? dp
->dvp_DevNode
->dol_Lock
: BNULL
;
186 /* now find the doslist entry for the named volume */
187 dl
= LockDosList(LDF_ALL
| LDF_READ
);
188 dl
= FindDosEntry(dl
, vol
, LDF_ALL
);
190 /* not found, bail out */
192 UnLockDosList(LDF_ALL
| LDF_READ
);
194 if (ErrorReport(ERROR_DEVICE_NOT_MOUNTED
, REPORT_INSERT
, (IPTR
)vol
, NULL
) == DOSTRUE
) {
195 FreeMem(dp
, sizeof(struct DevProc
));
202 /* at this point, we have an allocated devproc in dp, the doslist is
203 * locked for read, and we have the entry for the named "volume"
204 * (device, assign, etc) in dl and a filename relative to that in name */
206 /* late assign. we resolve the target and then promote the doslist entry
208 if (dl
->dol_Type
== DLT_LATE
) {
209 /* obtain a lock on the target */
210 lock
= Lock(dl
->dol_misc
.dol_assign
.dol_AssignName
, SHARED_LOCK
);
212 /* didn't find the target */
214 UnLockDosList(LDF_ALL
| LDF_READ
);
215 FreeMem(dp
, sizeof(struct DevProc
));
219 /* Directly change assign type without calling AssignXXX(),
220 * mimics AOS behavior, AOS programs assume it is safe to
221 * keep LDF_WRITE lock while calling Lock("late assign:");
223 dl
->dol_Type
= DLT_DIRECTORY
;
225 dl
->dol_Task
= ((struct FileLock
*)BADDR(lock
))->fl_Task
;
226 FreeVec(dl
->dol_misc
.dol_assign
.dol_AssignName
);
227 dl
->dol_misc
.dol_assign
.dol_AssignName
= NULL
;
229 /* the added entry will be a DLT_DIRECTORY, so we can just copy the
230 * details in and get out of here */
231 dp
->dvp_Port
= dl
->dol_Task
;
232 dp
->dvp_Lock
= dl
->dol_Lock
;
234 dp
->dvp_DevNode
= dl
;
236 UnLockDosList(LDF_ALL
| LDF_READ
);
241 /* nonbinding assign. like a late assign, but with no doslist promotion */
242 if (dl
->dol_Type
== DLT_NONBINDING
) {
243 lock
= Lock(dl
->dol_misc
.dol_assign
.dol_AssignName
, SHARED_LOCK
);
245 /* just fill out the dp and return */
246 dp
->dvp_Port
= ((struct FileLock
*) BADDR(lock
))->fl_Task
;
248 dp
->dvp_Flags
= DVPF_UNLOCK
; /* remember to unlock in FreeDeviceNode() */
249 dp
->dvp_DevNode
= dl
;
251 UnLockDosList(LDF_ALL
| LDF_READ
);
256 /* devices and volumes are easy */
257 if (dl
->dol_Type
== DLT_DEVICE
|| dl
->dol_Type
== DLT_VOLUME
)
259 struct MsgPort
*newhandler
= NULL
;
261 if (dl
->dol_Type
== DLT_DEVICE
)
263 /* Check if the handler is not started */
264 newhandler
= dl
->dol_Task
;
267 D(bug("[GetDeviceProc] Accessing device '%b', path='%s'\n", dl
->dol_Name
, origname
));
270 * Unlock before starting handler, handler may internally
271 * require dos list locks, for example to add volume node.
273 UnLockDosList(LDF_ALL
| LDF_READ
);
275 newhandler
= RunHandler((struct DeviceNode
*)dl
, origname
, DOSBase
);
278 FreeMem(dp
, sizeof(struct DevProc
));
279 SetIoErr(ERROR_DEVICE_NOT_MOUNTED
);
283 LockDosList(LDF_ALL
| LDF_READ
);
290 while (res
&& !dl
->dol_Task
)
292 D(bug("[GetDeviceProc] Accessing offline volume '%b'\n", dl
->dol_Name
));
293 res
= !ErrorReport(ERROR_DEVICE_NOT_MOUNTED
, REPORT_VOLUME
, (IPTR
)dl
, NULL
);
298 UnLockDosList(LDF_ALL
| LDF_READ
);
299 FreeMem(dp
, sizeof(struct DevProc
));
300 SetIoErr(ERROR_DEVICE_NOT_MOUNTED
);
306 * A handler theoretically may choose to use custom MsgPort for communications.
307 * Pick up its preference if specified.
309 dp
->dvp_Port
= dl
->dol_Task
? dl
->dol_Task
: newhandler
;
310 dp
->dvp_Lock
= BNULL
;
312 dp
->dvp_DevNode
= dl
;
314 UnLockDosList(LDF_ALL
| LDF_READ
);
320 if (dl
->dol_Type
!= DLT_DIRECTORY
) {
321 UnLockDosList(LDF_ALL
| LDF_READ
);
322 FreeMem(dp
, sizeof(struct DevProc
));
323 kprintf("%s:%d: DosList entry 0x%p has unknown type %d. Probably a bug, report it!\n"
324 " GetDeviceProc() called for '%s'\n",
325 __FILE__
, __LINE__
, dl
, dl
->dol_Type
, name
);
326 SetIoErr(ERROR_BAD_NUMBER
);
330 /* real assigns. first, see if it's just pointing to a single dir */
331 if (dp
->dvp_Flags
!= DVPF_ASSIGN
) {
332 /* just a plain assign, easy */
333 dp
->dvp_Port
= dl
->dol_Task
;
334 dp
->dvp_Lock
= dl
->dol_Lock
;
335 dp
->dvp_DevNode
= dl
;
337 /* note multidirectory assigns so the caller knows to loop */
338 dp
->dvp_Flags
= dl
->dol_misc
.dol_assign
.dol_List
!= NULL
? DVPF_ASSIGN
: 0;
340 UnLockDosList(LDF_ALL
| LDF_READ
);
344 /* finally the tricky bit - multidirectory assigns */
346 /* if we're pointing at the "primary" lock, then we just take the first
348 if (dp
->dvp_Lock
== dl
->dol_Lock
)
349 dp
->dvp_Lock
= dl
->dol_misc
.dol_assign
.dol_List
->al_Lock
;
351 /* otherwise we're finding the next */
353 struct AssignList
*al
= dl
->dol_misc
.dol_assign
.dol_List
;
355 /* find our current lock (ie the one we returned last time) */
356 for (; al
!= NULL
&& al
->al_Lock
!= dp
->dvp_Lock
; al
= al
->al_Next
);
358 /* if we didn't find it, or we didn't but there's none after it, then
360 if (al
== NULL
|| (al
= al
->al_Next
) == NULL
) {
361 UnLockDosList(LDF_ALL
| LDF_READ
);
362 FreeMem(dp
, sizeof(struct DevProc
));
364 SetIoErr(ERROR_NO_MORE_ENTRIES
);
368 /* fill out the lock from the new entry */
369 dp
->dvp_Lock
= al
->al_Lock
;
373 dp
->dvp_Port
= ((struct FileLock
*) BADDR(dp
->dvp_Lock
))->fl_Task
;
374 dp
->dvp_Flags
= DVPF_ASSIGN
;
375 dp
->dvp_DevNode
= dl
;
377 UnLockDosList(LDF_READ
|LDF_ALL
);