Minor fixes to comments.
[AROS.git] / rom / dos / exall.c
blobbfef36de8dcef6350551ebc2ceeaa405d8c17bda
1 /*
2 Copyright © 1995-2012, 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/exall.h>
11 #include <stddef.h>
12 #include "dos_intern.h"
13 #include <aros/asmcall.h>
14 #include <aros/debug.h>
16 /*****************************************************************************
18 NAME */
19 #include <proto/dos.h>
21 AROS_LH5(BOOL, ExAll,
23 /* SYNOPSIS */
24 AROS_LHA(BPTR, lock, D1),
25 AROS_LHA(struct ExAllData *, buffer, D2),
26 AROS_LHA(LONG, size, D3),
27 AROS_LHA(LONG, data, D4),
28 AROS_LHA(struct ExAllControl *, control, D5),
30 /* LOCATION */
31 struct DosLibrary *, DOSBase, 72, Dos)
33 /* FUNCTION
35 Examine an entire directory.
37 INPUTS
39 lock -- lock on the directory to be examined
40 buffer -- buffer for the data that is returned (must be aligned)
41 which is filled with (partial) ExAllData structures
42 (see NOTES)
43 size -- size of 'buffer' in bytes
44 data -- type of the data to be returned
45 control -- a control structure allocated by AllocDosObject()
47 RESULT
49 An indicator of if ExAll() is done. If FALSE is returned, either ExAll()
50 has completed in which case IoErr() is ERROR_NO_MORE_ENTRIES or an
51 error occurred. If a non-zero value is returned ExAll() must be called
52 again until it returns FALSE.
54 NOTES
56 The following information is essential information on the ExAllData
57 structure:
59 ed_Type:
61 ED_NAME -- filename
62 ED_TYPE -- type
63 ED_SIZE -- size in bytes
64 ED_PROTECTION -- protection bits
65 ED_DATE -- date information (3 longwords)
66 ED_COMMENT -- file comment (NULL if no comment exists)
67 ED_OWNER -- owner user and group id
69 This is an incremental list meaning that if you specify ED_OWNER you
70 will get ALL attributes!
73 Filesystems that support ExAll() must support at least up to ED_COMMENT.
74 If a filesystem doesn't support a particular type, ERROR_BAD_NUMBER must
75 be returned.
77 ed_Next : pointer to the next entry in the buffer. The last entry
78 has a NULL value for ed_Next.
81 The control structure have the following fields.
83 eac_Entries : the number of entries in the buffer after a call to ExAll().
84 Make sure that your code handles the case when eac_Entries
85 is 0 and ExAll() returns TRUE.
87 eac_LastKey : must be initialized to 0 before calling ExAll() for the
88 first time.
90 eac_MatchString : if NULL then information on all files will be returned.
91 If non-NULL it's interpreted as a pointer to a string
92 used for pattern matching which files to return
93 information on. This string must have been parsed by
94 ParsePatternNoCase()!
96 eac_MatchFunc : pointer to a hook that will be called to decide if an
97 entry should be included in the buffer. If NULL, no
98 matching function will be called. The hook is called as
99 follows
101 BOOL = MatchFunc(hook, data, typeptr)
103 EXAMPLE
105 BUGS
107 SEE ALSO
109 Examine(), ExNext(), MatchPatternNoCase(), ParsePatternNoCase(),
110 AllocDosObject(), ExAllEnd()
112 INTERNALS
114 *****************************************************************************/
116 AROS_LIBFUNC_INIT
118 /* Get pointer to filehandle */
119 struct FileLock *fl = BADDR(lock);
120 LONG status = 0;
121 SIPTR err = 0;
123 /* If fib != NULL it means we've already been called and found out that
124 we needed to emulate ExAll, thus don't waste time sending messages to the
125 handler. */
126 if (((struct InternalExAllControl *)control)->fib != NULL)
128 err = ERROR_ACTION_NOT_KNOWN;
130 else
132 status = dopacket5(DOSBase, &err, fl->fl_Task, ACTION_EXAMINE_ALL, (SIPTR)lock, (IPTR)buffer, (IPTR)size, (IPTR)data, (IPTR)control);
133 if (status != DOSFALSE)
134 err = RETURN_OK;
139 err == ERROR_NOT_IMPLEMENTED ||
140 err == ERROR_ACTION_NOT_KNOWN
143 /* Try to emulate it */
144 STRPTR end = (STRPTR)buffer + size;
145 STRPTR next;
147 struct ExAllData *last = buffer, *curr = buffer;
149 struct InternalExAllControl *icontrol = (struct InternalExAllControl *)control;
151 static const ULONG sizes[]=
154 offsetof(struct ExAllData,ed_Type),
155 offsetof(struct ExAllData,ed_Size),
156 offsetof(struct ExAllData,ed_Prot),
157 offsetof(struct ExAllData,ed_Days),
158 offsetof(struct ExAllData,ed_Comment),
159 offsetof(struct ExAllData,ed_OwnerUID),
160 sizeof(struct ExAllData)
163 /* Reset the 'fake' error */
164 err = 0;
166 /* Allocate the FIB structure, if not allocated yet. It will be deallocated
167 by DeleteDosObject(). */
168 if (!icontrol->fib)
170 icontrol->fib = AllocDosObject(DOS_FIB, NULL);
171 if (!icontrol->fib)
173 err = IoErr();
174 goto end;
178 /* No entries found as of now yet. */
179 control->eac_Entries = 0;
181 /* If LastKey == 0 it means this is the first time we're getting called,
182 in which case we need to initialize the FIB structure and a few other things.
183 A "nice" side effect of this, is that if one wants to restart the scanning,
184 he/she just has to set LastKey to 0. */
185 if (control->eac_LastKey == 0)
187 if (!Examine(lock, icontrol->fib))
189 err = IoErr();
190 goto end;
192 if (icontrol->fib->fib_DirEntryType <= 0)
194 err = ERROR_OBJECT_WRONG_TYPE;
195 goto end;
199 /* Macro used when the data doesn't fit in the provided buffer.
200 In case not even one element fit in the buffer, return a buffer
201 overflow error, so that the user knows he/she has to increase the
202 buffer. */
203 #define ReturnOverflow() \
204 do { \
205 if (last == curr) \
206 err = ERROR_BUFFER_OVERFLOW; \
208 icontrol->fib->fib_DiskKey = control->eac_LastKey; \
209 goto end; \
210 } while (0)
212 /* Copy a string pointer by _source into the buffer provided
213 to the ExAll function. This macro gracefully handles buffer
214 overflows. */
215 #define CopyStringSafe(_source) \
216 do { \
217 STRPTR source = _source; \
219 for (;;) \
221 if (next >= end) \
222 ReturnOverflow(); \
223 if (!(*next++ = *source++)) \
224 break; \
226 } while (0)
229 if (data > ED_OWNER)
230 /* We don't have that many fields to fill in... */
231 err = ERROR_BAD_NUMBER;
232 else
236 ExNext(lock, icontrol->fib);
237 /* Record the latest DiskKey into LastKey so that we can roll back to it
238 in case of a buffer overflow and when getting called again. */
239 control->eac_LastKey = icontrol->fib->fib_DiskKey
242 /* Try to match the filename, if required. */
243 if (control->eac_MatchString &&
244 !MatchPatternNoCase(control->eac_MatchString,
245 icontrol->fib->fib_FileName))
246 continue;
248 next = (STRPTR)curr + sizes[data];
250 /* Oops, the buffer is full. */
251 if (next > end)
252 ReturnOverflow();
254 /* Switch over the requested fields and fill them as appropriate. */
255 switch(data)
257 case ED_OWNER:
258 curr->ed_OwnerUID = icontrol->fib->fib_OwnerUID;
259 curr->ed_OwnerGID = icontrol->fib->fib_OwnerGID;
261 /* Fall through */
262 case ED_COMMENT:
263 curr->ed_Comment = next;
264 CopyStringSafe(icontrol->fib->fib_Comment);
266 /* Fall through */
267 case ED_DATE:
268 curr->ed_Days = icontrol->fib->fib_Date.ds_Days;
269 curr->ed_Mins = icontrol->fib->fib_Date.ds_Minute;
270 curr->ed_Ticks = icontrol->fib->fib_Date.ds_Tick;
272 /* Fall through */
273 case ED_PROTECTION:
274 curr->ed_Prot = icontrol->fib->fib_Protection;
276 /* Fall through */
277 case ED_SIZE:
278 curr->ed_Size = icontrol->fib->fib_Size;
280 /* Fall through */
281 case ED_TYPE:
282 curr->ed_Type = icontrol->fib->fib_DirEntryType;
284 /* Fall through */
285 case ED_NAME:
286 curr->ed_Name = next;
287 CopyStringSafe(icontrol->fib->fib_FileName);
289 /* Fall through */
290 case 0:
291 curr->ed_Next = (struct ExAllData *)(((IPTR)next + AROS_PTRALIGN - 1) & ~(AROS_PTRALIGN - 1));
294 /* Do some more matching... */
295 if (control->eac_MatchFunc && !CALLHOOKPKT(control->eac_MatchFunc, curr, &data))
296 continue;
298 /* Finally go to the next entry in the buffer. */
299 last = curr;
300 curr = curr->ed_Next;
301 control->eac_Entries++;
303 err = IoErr();
305 end:
306 /* This is the last one, after it there's nothing. */
307 last->ed_Next = NULL;
310 /* Set error code and return */
311 SetIoErr(err);
312 return (err == 0) ? DOSTRUE : DOSFALSE;
314 AROS_LIBFUNC_EXIT
315 } /* ExAll */