2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
5 Desc: Examine a directory.
8 #include <exec/memory.h>
9 #include <proto/exec.h>
10 #include <dos/filesystem.h>
11 #include <dos/exall.h>
13 #include "dos_intern.h"
14 #include <aros/asmcall.h>
15 #include <aros/debug.h>
17 /*****************************************************************************
20 #include <proto/dos.h>
25 AROS_LHA(BPTR
, lock
, D1
),
26 AROS_LHA(struct ExAllData
*, buffer
, D2
),
27 AROS_LHA(LONG
, size
, D3
),
28 AROS_LHA(LONG
, data
, D4
),
29 AROS_LHA(struct ExAllControl
*, control
, D5
),
32 struct DosLibrary
*, DOSBase
, 72, Dos
)
36 Examine an entire directory.
40 lock -- lock on the directory to be examined
41 buffer -- buffer for the data that is returned (must be aligned)
42 which is filled with (partial) ExAllData structures
44 size -- size of 'buffer' in bytes
45 type -- type of the data to be returned
46 control -- a control structure allocated by AllocDosObject()
50 An indicator of if ExAll() is done. If FALSE is returned, either ExAll()
51 has completed in which case IoErr() is ERROR_NO_MORE_ENTRIES or an
52 error occurred. If a non-zero value is returned ExAll() must be called
53 again until it returns FALSE.
57 The following information is essential information on the ExAllData
64 ED_SIZE -- size in bytes
65 ED_PROTECTION -- protection bits
66 ED_DATE -- date information (3 longwords)
67 ED_COMMENT -- file comment (NULL if no comment exists)
68 ED_OWNER -- owner user and group id
70 This is an incremental list meaning that if you specify ED_OWNER you
71 will get ALL attributes!
74 Filesystems that support ExAll() must support at least up to ED_COMMENT.
75 If a filesystem doesn't support a particular type, ERROR_BAD_NUMBER must
78 ead_Next : pointer to the next entry in the buffer. The last entry
79 has a NULL value for ead_Next.
82 The control structure have the following fields.
84 eac_Entries : the number of entries in the buffer after a call to ExAll().
85 Make sure that your code handles the case when eac_Entries
86 is 0 and ExAll() returns TRUE.
88 eac_LastKey : must be initialized to 0 before calling ExAll() for the
91 eac_MatchString : if NULL then information on all files will be returned.
92 If non-NULL it's interpreted as a pointer to a string
93 used for pattern matching which files to return
94 information on. This string must have been parsed by
97 eac_MatchFunc : pointer to a hook that will be called to decide if an
98 entry should be included in the buffer. If NULL, no
99 matching function will be called. The hook is called as
102 BOOL = MatchFunc(hook, data, typeptr)
110 Examine(), ExNext(), MatchPatternNoCase(), ParsePatternNoCase(),
111 AllocDosObject(), ExAllEnd()
115 *****************************************************************************/
118 AROS_LIBBASE_EXT_DECL(struct DosLibrary
*,DOSBase
)
120 /* Get pointer to filehandle */
121 struct FileHandle
*fh
= (struct FileHandle
*)BADDR(lock
);
123 /* Get pointer to I/O request. Use stackspace for now. */
124 struct IOFileSys iofs
;
126 /* If fib != NULL it means we've already been called and found out that
127 we needed to emulate ExAll, thus don't waste time sending messages to the
129 if (((struct InternalExAllControl
*)control
)->fib
!= NULL
||
130 control
->eac_MatchString
|| control
->eac_MatchFunc
)
132 #warning "Hack because of problem with our filesystem API regarding"
133 #warning "ExAll handling. Filesystems don't get passed matchstring/matchfunc"
134 #warning "so they cannot handle it. As workaround for now we force emulation"
135 #warning "of ExAll() if any of matchstring/matchfunc is set."
136 #warning "It would be better to pass ExAllControl structure to filesystems."
137 #warning "Ie. change filesystem API. Also because of eac_LastKey!!!"
139 iofs
.io_DosError
= ERROR_ACTION_NOT_KNOWN
;
143 /* Prepare I/O request. */
144 InitIOFS(&iofs
, FSA_EXAMINE_ALL
, DOSBase
);
146 iofs
.IOFS
.io_Device
= fh
->fh_Device
;
147 iofs
.IOFS
.io_Unit
= fh
->fh_Unit
;
149 iofs
.io_Union
.io_EXAMINE_ALL
.io_ead
= buffer
;
150 iofs
.io_Union
.io_EXAMINE_ALL
.io_eac
= control
;
151 iofs
.io_Union
.io_EXAMINE_ALL
.io_Size
= size
;
152 iofs
.io_Union
.io_EXAMINE_ALL
.io_Mode
= data
;
154 /* Send the request. */
160 iofs
.io_DosError
== ERROR_NOT_IMPLEMENTED
||
161 iofs
.io_DosError
== ERROR_ACTION_NOT_KNOWN
164 /* Try to emulate it */
165 STRPTR end
= (STRPTR
)buffer
+ size
;
168 struct ExAllData
*last
= buffer
, *curr
= buffer
;
170 struct InternalExAllControl
*icontrol
= (struct InternalExAllControl
*)control
;
172 static const ULONG sizes
[]=
175 offsetof(struct ExAllData
,ed_Type
),
176 offsetof(struct ExAllData
,ed_Size
),
177 offsetof(struct ExAllData
,ed_Prot
),
178 offsetof(struct ExAllData
,ed_Days
),
179 offsetof(struct ExAllData
,ed_Comment
),
180 offsetof(struct ExAllData
,ed_OwnerUID
),
181 sizeof(struct ExAllData
)
184 /* No errors for now. */
185 iofs
.io_DosError
= 0;
187 /* Allocate the FIB structure, if not allocated yet. It will be deallocated
188 by DeleteDosObject(). */
191 icontrol
->fib
= AllocDosObject(DOS_FIB
, NULL
);
194 iofs
.io_DosError
== IoErr();
199 /* No entries found as of now yet. */
200 control
->eac_Entries
= 0;
202 /* If LastKey == 0 it means this is the first time we're getting called,
203 in which case we need to initialize the FIB structure and a few other things.
204 A "nice" side effect of this, is that if one wants to restart the scanning,
205 he/she just has to set LastKey to 0. */
206 if (control
->eac_LastKey
== 0)
208 if (!Examine(lock
, icontrol
->fib
))
210 iofs
.io_DosError
== IoErr();
213 if (icontrol
->fib
->fib_DirEntryType
<= 0)
215 iofs
.io_DosError
= ERROR_OBJECT_WRONG_TYPE
;
220 /* Macro used when the data doesn't fit in the provided buffer.
221 In case not even one element fit in the buffer, return a buffer
222 overflow error, so that the user knows he/she has to increase the
224 #define ReturnOverflow() \
227 iofs.io_DosError = ERROR_BUFFER_OVERFLOW; \
229 icontrol->fib->fib_DiskKey = control->eac_LastKey; \
233 /* Copy a string pointer by _source into the buffer provided
234 to the ExAll function. This macro gracefully handles buffer
236 #define CopyStringSafe(_source) \
238 STRPTR source = _source; \
244 if (!(*next++ = *source++)) \
251 /* We don't have that many fields to fill in... */
252 iofs
.io_DosError
= ERROR_BAD_NUMBER
;
257 ExNext(lock
, icontrol
->fib
);
258 /* Record the latest DiskKey into LastKey so that we can roll back to it
259 in case of a buffer overflow and when getting called again. */
260 control
->eac_LastKey
= icontrol
->fib
->fib_DiskKey
263 /* Try to match the filename, if required. */
264 if (control
->eac_MatchString
&&
265 !MatchPatternNoCase(control
->eac_MatchString
,
266 icontrol
->fib
->fib_FileName
))
269 next
= (STRPTR
)curr
+ sizes
[data
];
271 /* Oops, the buffer is full. */
275 /* Switch over the requested fields and fill them as appropriate. */
279 curr
->ed_OwnerUID
= icontrol
->fib
->fib_OwnerUID
;
280 curr
->ed_OwnerGID
= icontrol
->fib
->fib_OwnerGID
;
284 curr
->ed_Comment
= next
;
285 CopyStringSafe(icontrol
->fib
->fib_Comment
);
289 curr
->ed_Days
= icontrol
->fib
->fib_Date
.ds_Days
;
290 curr
->ed_Mins
= icontrol
->fib
->fib_Date
.ds_Minute
;
291 curr
->ed_Ticks
= icontrol
->fib
->fib_Date
.ds_Tick
;
295 curr
->ed_Prot
= icontrol
->fib
->fib_Protection
;
299 curr
->ed_Size
= icontrol
->fib
->fib_Size
;
303 curr
->ed_Type
= icontrol
->fib
->fib_DirEntryType
;
307 curr
->ed_Name
= next
;
308 CopyStringSafe(icontrol
->fib
->fib_FileName
);
312 curr
->ed_Next
= (struct ExAllData
*)(((IPTR
)next
+ AROS_PTRALIGN
- 1) & ~(AROS_PTRALIGN
- 1));
315 /* Do some more matching... */
316 if (control
->eac_MatchFunc
&&
317 !AROS_UFC3(LONG
, control
->eac_MatchFunc
,
318 AROS_UFCA(struct Hook
*, control
->eac_MatchFunc
, A0
),
319 AROS_UFCA(struct ExAllData
*, curr
, A2
),
320 AROS_UFCA(LONG
*, &data
, A1
)))
323 /* Finally go to the next entry in the buffer. */
325 curr
= curr
->ed_Next
;
326 control
->eac_Entries
++;
328 iofs
.io_DosError
= IoErr();
331 /* This is the last one, after it there's nothing. */
332 last
->ed_Next
= NULL
;
335 /* Set error code and return */
336 SetIoErr(iofs
.io_DosError
);
337 return (iofs
.io_DosError
== 0) ? DOSTRUE
: DOSFALSE
;