finish migrating from arosmesa to mesa3dgl
[AROS.git] / rom / dos / exall.c
blob7e0abfc5eedf35d14f75bd4df88054685c5dc266
1 /*
2 Copyright © 1995-2013, 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
34 Examine an entire directory.
36 INPUTS
37 lock - lock on the directory to be examined
38 buffer - buffer for the data that is returned (must be aligned)
39 which is filled with (partial) ExAllData structures
40 (see NOTES)
41 size - size of 'buffer' in bytes
42 data - type of the data to be returned
43 control - a control structure allocated by AllocDosObject()
45 RESULT
46 An indicator of whether ExAll() is finished. If FALSE is returned,
47 either ExAll() has completed, in which case IoErr() is
48 ERROR_NO_MORE_ENTRIES, or an error occurred. If a non-zero value is
49 returned, ExAll() must be called again until it returns FALSE.
51 NOTES
52 The following information is essential information in the ExAllData
53 structure:
55 ed_Type:
57 ED_NAME - filename
58 ED_TYPE - type
59 ED_SIZE - size in bytes
60 ED_PROTECTION - protection bits
61 ED_DATE - date information (3 longwords)
62 ED_COMMENT - file comment (NULL if no comment exists)
63 ED_OWNER - owner user and group id
65 This is an incremental list, meaning that if you specify ED_OWNER
66 you will get ALL attributes!
68 Filesystems that support ExAll() must support at least up to
69 ED_COMMENT. If a filesystem doesn't support a particular type,
70 ERROR_BAD_NUMBER must be returned.
72 ed_Next: pointer to the next entry in the buffer. The last entry
73 has a NULL value for ed_Next.
75 The control structure have the following fields:
77 eac_Entries: the number of entries in the buffer after a call to
78 ExAll(). Make sure that your code handles the case when
79 eac_Entries is 0 and ExAll() returns TRUE.
81 eac_LastKey: must be initialized to 0 before calling ExAll() for the
82 first time.
84 eac_MatchString: if NULL then information on all files will be returned.
85 If non-NULL it's interpreted as a pointer to a string
86 used for pattern matching which files to return
87 information on. This string must have been parsed by
88 ParsePatternNoCase()!
90 eac_MatchFunc: pointer to a hook that will be called to decide if an
91 entry should be included in the buffer. If NULL, no
92 matching function will be called. The hook is called as
93 follows:
95 BOOL = MatchFunc(hook, data, typeptr)
97 EXAMPLE
99 BUGS
101 SEE ALSO
102 Examine(), ExNext(), MatchPatternNoCase(), ParsePatternNoCase(),
103 AllocDosObject(), ExAllEnd()
105 INTERNALS
107 *****************************************************************************/
109 AROS_LIBFUNC_INIT
111 /* Get pointer to filehandle */
112 struct FileLock *fl = BADDR(lock);
113 LONG status = 0;
114 SIPTR err = 0;
116 /* If fib != NULL it means we've already been called and found out that
117 we needed to emulate ExAll, thus don't waste time sending messages to the
118 handler. */
119 if (((struct InternalExAllControl *)control)->fib != NULL)
121 err = ERROR_ACTION_NOT_KNOWN;
123 else
125 status = dopacket5(DOSBase, &err, fl->fl_Task, ACTION_EXAMINE_ALL, (SIPTR)lock, (IPTR)buffer, (IPTR)size, (IPTR)data, (IPTR)control);
126 if (status != DOSFALSE)
127 err = RETURN_OK;
132 err == ERROR_NOT_IMPLEMENTED ||
133 err == ERROR_ACTION_NOT_KNOWN
136 /* Try to emulate it */
137 STRPTR end = (STRPTR)buffer + size;
138 STRPTR next;
140 struct ExAllData *last = buffer, *curr = buffer;
142 struct InternalExAllControl *icontrol = (struct InternalExAllControl *)control;
144 static const ULONG sizes[]=
147 offsetof(struct ExAllData,ed_Type),
148 offsetof(struct ExAllData,ed_Size),
149 offsetof(struct ExAllData,ed_Prot),
150 offsetof(struct ExAllData,ed_Days),
151 offsetof(struct ExAllData,ed_Comment),
152 offsetof(struct ExAllData,ed_OwnerUID),
153 sizeof(struct ExAllData)
156 /* Reset the 'fake' error */
157 err = 0;
159 /* Allocate the FIB structure, if not allocated yet. It will be deallocated
160 by DeleteDosObject(). */
161 if (!icontrol->fib)
163 icontrol->fib = AllocDosObject(DOS_FIB, NULL);
164 if (!icontrol->fib)
166 err = IoErr();
167 goto end;
171 /* No entries found as of now yet. */
172 control->eac_Entries = 0;
174 /* If LastKey == 0 it means this is the first time we're getting called,
175 in which case we need to initialize the FIB structure and a few other things.
176 A "nice" side effect of this, is that if one wants to restart the scanning,
177 he/she just has to set LastKey to 0. */
178 if (control->eac_LastKey == 0)
180 if (!Examine(lock, icontrol->fib))
182 err = IoErr();
183 goto end;
185 if (icontrol->fib->fib_DirEntryType <= 0)
187 err = ERROR_OBJECT_WRONG_TYPE;
188 goto end;
192 /* Macro used when the data doesn't fit in the provided buffer.
193 In case not even one element fit in the buffer, return a buffer
194 overflow error, so that the user knows he/she has to increase the
195 buffer. */
196 #define ReturnOverflow() \
197 do { \
198 if (last == curr) \
199 err = ERROR_BUFFER_OVERFLOW; \
201 icontrol->fib->fib_DiskKey = control->eac_LastKey; \
202 goto end; \
203 } while (0)
205 /* Copy a string pointer by _source into the buffer provided
206 to the ExAll function. This macro gracefully handles buffer
207 overflows. */
208 #define CopyStringSafe(_source) \
209 do { \
210 STRPTR source = _source; \
212 for (;;) \
214 if (next >= end) \
215 ReturnOverflow(); \
216 if (!(*next++ = *source++)) \
217 break; \
219 } while (0)
222 if (data > ED_OWNER)
223 /* We don't have that many fields to fill in... */
224 err = ERROR_BAD_NUMBER;
225 else
229 ExNext(lock, icontrol->fib);
230 /* Record the latest DiskKey into LastKey so that we can roll back to it
231 in case of a buffer overflow and when getting called again. */
232 control->eac_LastKey = icontrol->fib->fib_DiskKey
235 /* Try to match the filename, if required. */
236 if (control->eac_MatchString &&
237 !MatchPatternNoCase(control->eac_MatchString,
238 icontrol->fib->fib_FileName))
239 continue;
241 next = (STRPTR)curr + sizes[data];
243 /* Oops, the buffer is full. */
244 if (next > end)
245 ReturnOverflow();
247 /* Switch over the requested fields and fill them as appropriate. */
248 switch(data)
250 case ED_OWNER:
251 curr->ed_OwnerUID = icontrol->fib->fib_OwnerUID;
252 curr->ed_OwnerGID = icontrol->fib->fib_OwnerGID;
254 /* Fall through */
255 case ED_COMMENT:
256 curr->ed_Comment = next;
257 CopyStringSafe(icontrol->fib->fib_Comment);
259 /* Fall through */
260 case ED_DATE:
261 curr->ed_Days = icontrol->fib->fib_Date.ds_Days;
262 curr->ed_Mins = icontrol->fib->fib_Date.ds_Minute;
263 curr->ed_Ticks = icontrol->fib->fib_Date.ds_Tick;
265 /* Fall through */
266 case ED_PROTECTION:
267 curr->ed_Prot = icontrol->fib->fib_Protection;
269 /* Fall through */
270 case ED_SIZE:
271 curr->ed_Size = icontrol->fib->fib_Size;
273 /* Fall through */
274 case ED_TYPE:
275 curr->ed_Type = icontrol->fib->fib_DirEntryType;
277 /* Fall through */
278 case ED_NAME:
279 curr->ed_Name = next;
280 CopyStringSafe(icontrol->fib->fib_FileName);
282 /* Fall through */
283 case 0:
284 curr->ed_Next = (struct ExAllData *)(((IPTR)next + AROS_PTRALIGN - 1) & ~(AROS_PTRALIGN - 1));
287 /* Do some more matching... */
288 if (control->eac_MatchFunc && !CALLHOOKPKT(control->eac_MatchFunc, curr, &data))
289 continue;
291 /* Finally go to the next entry in the buffer. */
292 last = curr;
293 curr = curr->ed_Next;
294 control->eac_Entries++;
296 err = IoErr();
298 end:
299 /* This is the last one, after it there's nothing. */
300 last->ed_Next = NULL;
303 /* Set error code and return */
304 SetIoErr(err);
305 return (err == 0) ? DOSTRUE : DOSFALSE;
307 AROS_LIBFUNC_EXIT
308 } /* ExAll */