Fix for the (stupid) case of app (always) passing
[tangerine.git] / rom / dos / exall.c
blobf023be79efcf1ae7cc0029f4a65eaa0a1253b48d
1 /*
2 Copyright © 1995-2001, 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
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
128 handler. */
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;
141 else
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. */
155 DosDoIO(&iofs.IOFS);
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;
166 STRPTR next;
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(). */
189 if (!icontrol->fib)
191 icontrol->fib = AllocDosObject(DOS_FIB, NULL);
192 if (!icontrol->fib)
194 iofs.io_DosError == IoErr();
195 goto end;
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();
211 goto end;
213 if (icontrol->fib->fib_DirEntryType <= 0)
215 iofs.io_DosError = ERROR_OBJECT_WRONG_TYPE;
216 goto end;
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
223 buffer. */
224 #define ReturnOverflow() \
225 do { \
226 if (last == curr) \
227 iofs.io_DosError = ERROR_BUFFER_OVERFLOW; \
229 icontrol->fib->fib_DiskKey = control->eac_LastKey; \
230 goto end; \
231 } while (0)
233 /* Copy a string pointer by _source into the buffer provided
234 to the ExAll function. This macro gracefully handles buffer
235 overflows. */
236 #define CopyStringSafe(_source) \
237 do { \
238 STRPTR source = _source; \
240 for (;;) \
242 if (next >= end) \
243 ReturnOverflow(); \
244 if (!(*next++ = *source++)) \
245 break; \
247 } while (0)
250 if (data > ED_OWNER)
251 /* We don't have that many fields to fill in... */
252 iofs.io_DosError = ERROR_BAD_NUMBER;
253 else
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))
267 continue;
269 next = (STRPTR)curr + sizes[data];
271 /* Oops, the buffer is full. */
272 if (next > end)
273 ReturnOverflow();
275 /* Switch over the requested fields and fill them as appropriate. */
276 switch(data)
278 case ED_OWNER:
279 curr->ed_OwnerUID = icontrol->fib->fib_OwnerUID;
280 curr->ed_OwnerGID = icontrol->fib->fib_OwnerGID;
282 /* Fall through */
283 case ED_COMMENT:
284 curr->ed_Comment = next;
285 CopyStringSafe(icontrol->fib->fib_Comment);
287 /* Fall through */
288 case ED_DATE:
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;
293 /* Fall through */
294 case ED_PROTECTION:
295 curr->ed_Prot = icontrol->fib->fib_Protection;
297 /* Fall through */
298 case ED_SIZE:
299 curr->ed_Size = icontrol->fib->fib_Size;
301 /* Fall through */
302 case ED_TYPE:
303 curr->ed_Type = icontrol->fib->fib_DirEntryType;
305 /* Fall through */
306 case ED_NAME:
307 curr->ed_Name = next;
308 CopyStringSafe(icontrol->fib->fib_FileName);
310 /* Fall through */
311 case 0:
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)))
321 continue;
323 /* Finally go to the next entry in the buffer. */
324 last = curr;
325 curr = curr->ed_Next;
326 control->eac_Entries++;
328 iofs.io_DosError = IoErr();
330 end:
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;
339 AROS_LIBFUNC_EXIT
340 } /* ExAll */