2 Copyright © 1995-2007, 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 *****************************************************************************/
119 /* Get pointer to filehandle */
120 struct FileHandle
*fh
= (struct FileHandle
*)BADDR(lock
);
122 /* Get pointer to I/O request. Use stackspace for now. */
123 struct IOFileSys iofs
;
125 /* If fib != NULL it means we've already been called and found out that
126 we needed to emulate ExAll, thus don't waste time sending messages to the
128 if (((struct InternalExAllControl
*)control
)->fib
!= NULL
||
129 control
->eac_MatchString
|| control
->eac_MatchFunc
)
131 #warning "Hack because of problem with our filesystem API regarding"
132 #warning "ExAll handling. Filesystems don't get passed matchstring/matchfunc"
133 #warning "so they cannot handle it. As workaround for now we force emulation"
134 #warning "of ExAll() if any of matchstring/matchfunc is set."
135 #warning "It would be better to pass ExAllControl structure to filesystems."
136 #warning "Ie. change filesystem API. Also because of eac_LastKey!!!"
138 iofs
.io_DosError
= ERROR_ACTION_NOT_KNOWN
;
142 /* Prepare I/O request. */
143 InitIOFS(&iofs
, FSA_EXAMINE_ALL
, DOSBase
);
145 iofs
.IOFS
.io_Device
= fh
->fh_Device
;
146 iofs
.IOFS
.io_Unit
= fh
->fh_Unit
;
148 iofs
.io_Union
.io_EXAMINE_ALL
.io_ead
= buffer
;
149 iofs
.io_Union
.io_EXAMINE_ALL
.io_eac
= control
;
150 iofs
.io_Union
.io_EXAMINE_ALL
.io_Size
= size
;
151 iofs
.io_Union
.io_EXAMINE_ALL
.io_Mode
= data
;
153 /* Send the request. */
159 iofs
.io_DosError
== ERROR_NOT_IMPLEMENTED
||
160 iofs
.io_DosError
== ERROR_ACTION_NOT_KNOWN
163 /* Try to emulate it */
164 STRPTR end
= (STRPTR
)buffer
+ size
;
167 struct ExAllData
*last
= buffer
, *curr
= buffer
;
169 struct InternalExAllControl
*icontrol
= (struct InternalExAllControl
*)control
;
171 static const ULONG sizes
[]=
174 offsetof(struct ExAllData
,ed_Type
),
175 offsetof(struct ExAllData
,ed_Size
),
176 offsetof(struct ExAllData
,ed_Prot
),
177 offsetof(struct ExAllData
,ed_Days
),
178 offsetof(struct ExAllData
,ed_Comment
),
179 offsetof(struct ExAllData
,ed_OwnerUID
),
180 sizeof(struct ExAllData
)
183 /* No errors for now. */
184 iofs
.io_DosError
= 0;
186 /* Allocate the FIB structure, if not allocated yet. It will be deallocated
187 by DeleteDosObject(). */
190 icontrol
->fib
= AllocDosObject(DOS_FIB
, NULL
);
193 iofs
.io_DosError
== IoErr();
198 /* No entries found as of now yet. */
199 control
->eac_Entries
= 0;
201 /* If LastKey == 0 it means this is the first time we're getting called,
202 in which case we need to initialize the FIB structure and a few other things.
203 A "nice" side effect of this, is that if one wants to restart the scanning,
204 he/she just has to set LastKey to 0. */
205 if (control
->eac_LastKey
== 0)
207 if (!Examine(lock
, icontrol
->fib
))
209 iofs
.io_DosError
== IoErr();
212 if (icontrol
->fib
->fib_DirEntryType
<= 0)
214 iofs
.io_DosError
= ERROR_OBJECT_WRONG_TYPE
;
219 /* Macro used when the data doesn't fit in the provided buffer.
220 In case not even one element fit in the buffer, return a buffer
221 overflow error, so that the user knows he/she has to increase the
223 #define ReturnOverflow() \
226 iofs.io_DosError = ERROR_BUFFER_OVERFLOW; \
228 icontrol->fib->fib_DiskKey = control->eac_LastKey; \
232 /* Copy a string pointer by _source into the buffer provided
233 to the ExAll function. This macro gracefully handles buffer
235 #define CopyStringSafe(_source) \
237 STRPTR source = _source; \
243 if (!(*next++ = *source++)) \
250 /* We don't have that many fields to fill in... */
251 iofs
.io_DosError
= ERROR_BAD_NUMBER
;
256 ExNext(lock
, icontrol
->fib
);
257 /* Record the latest DiskKey into LastKey so that we can roll back to it
258 in case of a buffer overflow and when getting called again. */
259 control
->eac_LastKey
= icontrol
->fib
->fib_DiskKey
262 /* Try to match the filename, if required. */
263 if (control
->eac_MatchString
&&
264 !MatchPatternNoCase(control
->eac_MatchString
,
265 icontrol
->fib
->fib_FileName
))
268 next
= (STRPTR
)curr
+ sizes
[data
];
270 /* Oops, the buffer is full. */
274 /* Switch over the requested fields and fill them as appropriate. */
278 curr
->ed_OwnerUID
= icontrol
->fib
->fib_OwnerUID
;
279 curr
->ed_OwnerGID
= icontrol
->fib
->fib_OwnerGID
;
283 curr
->ed_Comment
= next
;
284 CopyStringSafe(icontrol
->fib
->fib_Comment
);
288 curr
->ed_Days
= icontrol
->fib
->fib_Date
.ds_Days
;
289 curr
->ed_Mins
= icontrol
->fib
->fib_Date
.ds_Minute
;
290 curr
->ed_Ticks
= icontrol
->fib
->fib_Date
.ds_Tick
;
294 curr
->ed_Prot
= icontrol
->fib
->fib_Protection
;
298 curr
->ed_Size
= icontrol
->fib
->fib_Size
;
302 curr
->ed_Type
= icontrol
->fib
->fib_DirEntryType
;
306 curr
->ed_Name
= next
;
307 CopyStringSafe(icontrol
->fib
->fib_FileName
);
311 curr
->ed_Next
= (struct ExAllData
*)(((IPTR
)next
+ AROS_PTRALIGN
- 1) & ~(AROS_PTRALIGN
- 1));
314 /* Do some more matching... */
315 if (control
->eac_MatchFunc
&&
316 !AROS_UFC3(LONG
, control
->eac_MatchFunc
,
317 AROS_UFCA(struct Hook
*, control
->eac_MatchFunc
, A0
),
318 AROS_UFCA(struct ExAllData
*, curr
, A2
),
319 AROS_UFCA(LONG
*, &data
, A1
)))
322 /* Finally go to the next entry in the buffer. */
324 curr
= curr
->ed_Next
;
325 control
->eac_Entries
++;
327 iofs
.io_DosError
= IoErr();
330 /* This is the last one, after it there's nothing. */
331 last
->ed_Next
= NULL
;
334 /* Set error code and return */
335 SetIoErr(iofs
.io_DosError
);
336 return (iofs
.io_DosError
== 0) ? DOSTRUE
: DOSFALSE
;