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
)
130 iofs
.io_DosError
= ERROR_ACTION_NOT_KNOWN
;
134 /* Prepare I/O request. */
135 InitIOFS(&iofs
, FSA_EXAMINE_ALL
, DOSBase
);
137 iofs
.IOFS
.io_Device
= fh
->fh_Device
;
138 iofs
.IOFS
.io_Unit
= fh
->fh_Unit
;
140 iofs
.io_Union
.io_EXAMINE_ALL
.io_ead
= buffer
;
141 iofs
.io_Union
.io_EXAMINE_ALL
.io_eac
= control
;
142 iofs
.io_Union
.io_EXAMINE_ALL
.io_Size
= size
;
143 iofs
.io_Union
.io_EXAMINE_ALL
.io_Mode
= data
;
145 /* Send the request. */
151 iofs
.io_DosError
== ERROR_NOT_IMPLEMENTED
||
152 iofs
.io_DosError
== ERROR_ACTION_NOT_KNOWN
155 /* Try to emulate it */
156 STRPTR end
= (STRPTR
)buffer
+ size
;
159 struct ExAllData
*last
= buffer
, *curr
= buffer
;
161 struct InternalExAllControl
*icontrol
= (struct InternalExAllControl
*)control
;
163 static const ULONG sizes
[]=
166 offsetof(struct ExAllData
,ed_Type
),
167 offsetof(struct ExAllData
,ed_Size
),
168 offsetof(struct ExAllData
,ed_Prot
),
169 offsetof(struct ExAllData
,ed_Days
),
170 offsetof(struct ExAllData
,ed_Comment
),
171 offsetof(struct ExAllData
,ed_OwnerUID
),
172 sizeof(struct ExAllData
)
175 /* No errors for now. */
176 iofs
.io_DosError
= 0;
178 /* Allocate the FIB structure, if not allocated yet. It will be deallocated
179 by DeleteDosObject(). */
182 icontrol
->fib
= AllocDosObject(DOS_FIB
, NULL
);
185 iofs
.io_DosError
== IoErr();
190 /* No entries found as of now yet. */
191 control
->eac_Entries
= 0;
193 /* If LastKey == 0 it means this is the first time we're getting called,
194 in which case we need to initialize the FIB structure and a few other things.
195 A "nice" side effect of this, is that if one wants to restart the scanning,
196 he/she just has to set LastKey to 0. */
197 if (control
->eac_LastKey
== 0)
199 if (!Examine(lock
, icontrol
->fib
))
201 iofs
.io_DosError
== IoErr();
204 if (icontrol
->fib
->fib_DirEntryType
<= 0)
206 iofs
.io_DosError
= ERROR_OBJECT_WRONG_TYPE
;
211 /* Macro used when the data doesn't fit in the provided buffer.
212 In case not even one element fit in the buffer, return a buffer
213 overflow error, so that the user knows he/she has to increase the
215 #define ReturnOverflow() \
218 iofs.io_DosError = ERROR_BUFFER_OVERFLOW; \
220 icontrol->fib->fib_DiskKey = control->eac_LastKey; \
224 /* Copy a string pointer by _source into the buffer provided
225 to the ExAll function. This macro gracefully handles buffer
227 #define CopyStringSafe(_source) \
229 STRPTR source = _source; \
235 if (!(*next++ = *source++)) \
242 /* We don't have that many fields to fill in... */
243 iofs
.io_DosError
= ERROR_BAD_NUMBER
;
248 ExNext(lock
, icontrol
->fib
);
249 /* Record the latest DiskKey into LastKey so that we can roll back to it
250 in case of a buffer overflow and when getting called again. */
251 control
->eac_LastKey
= icontrol
->fib
->fib_DiskKey
254 /* Try to match the filename, if required. */
255 if (control
->eac_MatchString
&&
256 !MatchPatternNoCase(control
->eac_MatchString
,
257 icontrol
->fib
->fib_FileName
))
260 next
= (STRPTR
)curr
+ sizes
[data
];
262 /* Oops, the buffer is full. */
266 /* Switch over the requested fields and fill them as appropriate. */
270 curr
->ed_OwnerUID
= icontrol
->fib
->fib_OwnerUID
;
271 curr
->ed_OwnerGID
= icontrol
->fib
->fib_OwnerGID
;
275 curr
->ed_Comment
= next
;
276 CopyStringSafe(icontrol
->fib
->fib_Comment
);
280 curr
->ed_Days
= icontrol
->fib
->fib_Date
.ds_Days
;
281 curr
->ed_Mins
= icontrol
->fib
->fib_Date
.ds_Minute
;
282 curr
->ed_Ticks
= icontrol
->fib
->fib_Date
.ds_Tick
;
286 curr
->ed_Prot
= icontrol
->fib
->fib_Protection
;
290 curr
->ed_Size
= icontrol
->fib
->fib_Size
;
294 curr
->ed_Type
= icontrol
->fib
->fib_DirEntryType
;
298 curr
->ed_Name
= next
;
299 CopyStringSafe(icontrol
->fib
->fib_FileName
);
303 curr
->ed_Next
= (struct ExAllData
*)(((IPTR
)next
+ AROS_PTRALIGN
- 1) & ~(AROS_PTRALIGN
- 1));
306 /* Do some more matching... */
307 if (control
->eac_MatchFunc
&& !CALLHOOKPKT(control
->eac_MatchFunc
, curr
, &data
))
310 /* Finally go to the next entry in the buffer. */
312 curr
= curr
->ed_Next
;
313 control
->eac_Entries
++;
315 iofs
.io_DosError
= IoErr();
318 /* This is the last one, after it there's nothing. */
319 last
->ed_Next
= NULL
;
322 /* Set error code and return */
323 SetIoErr(iofs
.io_DosError
);
324 return (iofs
.io_DosError
== 0) ? DOSTRUE
: DOSFALSE
;