Workaround for includes conflict that stopped compilation with GCC 3.
[cake.git] / rom / dos / exall.c
blob777018423a003effa212b7af0ed02f830df84f0d
1 /*
2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Examine a directory.
6 Lang: English
7 */
8 #include <exec/memory.h>
9 #include <proto/exec.h>
10 #include <dos/filesystem.h>
11 #include <dos/exall.h>
12 #include <stddef.h>
13 #include "dos_intern.h"
14 #include <aros/asmcall.h>
15 #include <aros/debug.h>
17 /*****************************************************************************
19 NAME */
20 #include <proto/dos.h>
22 AROS_LH5(BOOL, ExAll,
24 /* SYNOPSIS */
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),
31 /* LOCATION */
32 struct DosLibrary *, DOSBase, 72, Dos)
34 /* FUNCTION
36 Examine an entire directory.
38 INPUTS
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
43 (see NOTES)
44 size -- size of 'buffer' in bytes
45 type -- type of the data to be returned
46 control -- a control structure allocated by AllocDosObject()
48 RESULT
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.
55 NOTES
57 The following information is essential information on the ExAllData
58 structure:
60 ead_type :
62 ED_NAME -- filename
63 ED_TYPE -- type
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
76 be returned.
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
89 first time.
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
95 ParsePatternNoCase()!
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
100 follows
102 BOOL = MatchFunc(hook, data, typeptr)
104 EXAMPLE
106 BUGS
108 SEE ALSO
110 Examine(), ExNext(), MatchPatternNoCase(), ParsePatternNoCase(),
111 AllocDosObject(), ExAllEnd()
113 INTERNALS
115 *****************************************************************************/
117 AROS_LIBFUNC_INIT
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
127 handler. */
128 if (((struct InternalExAllControl *)control)->fib != NULL)
130 iofs.io_DosError = ERROR_ACTION_NOT_KNOWN;
132 else
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. */
146 DosDoIO(&iofs.IOFS);
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;
157 STRPTR next;
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(). */
180 if (!icontrol->fib)
182 icontrol->fib = AllocDosObject(DOS_FIB, NULL);
183 if (!icontrol->fib)
185 iofs.io_DosError = IoErr();
186 goto end;
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();
202 goto end;
204 if (icontrol->fib->fib_DirEntryType <= 0)
206 iofs.io_DosError = ERROR_OBJECT_WRONG_TYPE;
207 goto end;
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
214 buffer. */
215 #define ReturnOverflow() \
216 do { \
217 if (last == curr) \
218 iofs.io_DosError = ERROR_BUFFER_OVERFLOW; \
220 icontrol->fib->fib_DiskKey = control->eac_LastKey; \
221 goto end; \
222 } while (0)
224 /* Copy a string pointer by _source into the buffer provided
225 to the ExAll function. This macro gracefully handles buffer
226 overflows. */
227 #define CopyStringSafe(_source) \
228 do { \
229 STRPTR source = _source; \
231 for (;;) \
233 if (next >= end) \
234 ReturnOverflow(); \
235 if (!(*next++ = *source++)) \
236 break; \
238 } while (0)
241 if (data > ED_OWNER)
242 /* We don't have that many fields to fill in... */
243 iofs.io_DosError = ERROR_BAD_NUMBER;
244 else
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))
258 continue;
260 next = (STRPTR)curr + sizes[data];
262 /* Oops, the buffer is full. */
263 if (next > end)
264 ReturnOverflow();
266 /* Switch over the requested fields and fill them as appropriate. */
267 switch(data)
269 case ED_OWNER:
270 curr->ed_OwnerUID = icontrol->fib->fib_OwnerUID;
271 curr->ed_OwnerGID = icontrol->fib->fib_OwnerGID;
273 /* Fall through */
274 case ED_COMMENT:
275 curr->ed_Comment = next;
276 CopyStringSafe(icontrol->fib->fib_Comment);
278 /* Fall through */
279 case ED_DATE:
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;
284 /* Fall through */
285 case ED_PROTECTION:
286 curr->ed_Prot = icontrol->fib->fib_Protection;
288 /* Fall through */
289 case ED_SIZE:
290 curr->ed_Size = icontrol->fib->fib_Size;
292 /* Fall through */
293 case ED_TYPE:
294 curr->ed_Type = icontrol->fib->fib_DirEntryType;
296 /* Fall through */
297 case ED_NAME:
298 curr->ed_Name = next;
299 CopyStringSafe(icontrol->fib->fib_FileName);
301 /* Fall through */
302 case 0:
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))
308 continue;
310 /* Finally go to the next entry in the buffer. */
311 last = curr;
312 curr = curr->ed_Next;
313 control->eac_Entries++;
315 iofs.io_DosError = IoErr();
317 end:
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;
326 AROS_LIBFUNC_EXIT
327 } /* ExAll */