2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2004-2010, Axel Dörfler, axeld@pinc-software.de.
4 * Distributed under the terms of the MIT License.
9 #include <dirent_private.h>
16 #include <errno_private.h>
18 #include <syscall_utils.h>
21 #define DIR_BUFFER_SIZE 4096
27 unsigned short entries_left
;
29 long current_position
;
30 struct dirent first_entry
;
37 if (dir
->seek_position
== dir
->current_position
)
40 // If the seek position lies before the current position (the usual case),
41 // rewind to the beginning.
42 if (dir
->seek_position
< dir
->current_position
) {
43 status_t status
= _kern_rewind_dir(dir
->fd
);
49 dir
->current_position
= 0;
50 dir
->entries_left
= 0;
53 // Now skip entries until we have reached seek_position.
54 while (dir
->seek_position
> dir
->current_position
) {
56 long toSkip
= dir
->seek_position
- dir
->current_position
;
57 if (toSkip
== dir
->entries_left
) {
58 // we have to skip exactly all of the currently buffered entries
59 dir
->current_position
= dir
->seek_position
;
60 dir
->entries_left
= 0;
64 if (toSkip
< dir
->entries_left
) {
65 // we have to skip only some of the buffered entries
66 for (; toSkip
> 0; toSkip
--) {
67 struct dirent
* entry
= (struct dirent
*)
68 ((uint8
*)&dir
->first_entry
+ dir
->next_entry
);
70 dir
->next_entry
+= entry
->d_reclen
;
73 dir
->current_position
= dir
->seek_position
;
77 // we have to skip more than the currently buffered entries
78 dir
->current_position
+= dir
->entries_left
;
79 dir
->entries_left
= 0;
81 count
= _kern_read_dir(dir
->fd
, &dir
->first_entry
,
82 (char*)dir
+ DIR_BUFFER_SIZE
- (char*)&dir
->first_entry
, USHRT_MAX
);
92 dir
->entries_left
= count
;
99 // #pragma mark - private API
103 __create_dir_struct(int fd
)
105 /* allocate the memory for the DIR structure */
107 DIR* dir
= (DIR*)malloc(DIR_BUFFER_SIZE
);
109 __set_errno(B_NO_MEMORY
);
114 dir
->entries_left
= 0;
115 dir
->seek_position
= 0;
116 dir
->current_position
= 0;
122 // #pragma mark - public API
130 // Since our standard file descriptors can't be used as directory file
131 // descriptors, we have to open a fresh one explicitly.
132 int dirFD
= _kern_open_dir(fd
, NULL
);
138 // Since applications are allowed to use the file descriptor after a call
139 // to fdopendir() without changing its state (like for other *at()
140 // functions), we cannot close it now.
141 // We dup2() the new FD to the previous location instead.
142 if (dup2(dirFD
, fd
) == -1)
147 fcntl(dirFD
, F_SETFD
, FD_CLOEXEC
);
148 // reset close-on-exec which is cleared by dup()
151 dir
= __create_dir_struct(dirFD
);
162 opendir(const char* path
)
166 int fd
= _kern_open_dir(-1, path
);
172 // allocate the DIR structure
173 if ((dir
= __create_dir_struct(fd
)) == NULL
) {
188 __set_errno(B_BAD_VALUE
);
192 status
= _kern_close(dir
->fd
);
196 RETURN_AND_SET_ERRNO(status
);
205 if (dir
->seek_position
!= dir
->current_position
) {
206 if (do_seek_dir(dir
) != 0)
210 if (dir
->entries_left
> 0) {
211 struct dirent
*dirent
212 = (struct dirent
*)((uint8
*)&dir
->first_entry
+ dir
->next_entry
);
215 dir
->next_entry
+= dirent
->d_reclen
;
216 dir
->seek_position
++;
217 dir
->current_position
++;
222 // we need to retrieve new entries
224 count
= _kern_read_dir(dir
->fd
, &dir
->first_entry
,
225 (char*)dir
+ DIR_BUFFER_SIZE
- (char*)&dir
->first_entry
, USHRT_MAX
);
234 dir
->entries_left
= count
- 1;
235 dir
->next_entry
= dir
->first_entry
.d_reclen
;
236 dir
->seek_position
++;
237 dir
->current_position
++;
239 return &dir
->first_entry
;
244 readdir_r(DIR* dir
, struct dirent
* entry
, struct dirent
** _result
)
248 if (dir
->seek_position
!= dir
->current_position
) {
249 if (do_seek_dir(dir
) != 0)
253 if (dir
->entries_left
> 0) {
255 = (struct dirent
*)((uint8
*)&dir
->first_entry
+ dir
->next_entry
);
258 dir
->next_entry
+= (*_result
)->d_reclen
;
259 dir
->seek_position
++;
260 dir
->current_position
++;
265 count
= _kern_read_dir(dir
->fd
, entry
, sizeof(struct dirent
)
266 + B_FILE_NAME_LENGTH
, 1);
275 dir
->entries_left
= count
- 1;
276 dir
->next_entry
= dir
->first_entry
.d_reclen
;
277 dir
->seek_position
++;
278 dir
->current_position
++;
288 dir
->seek_position
= 0;
293 seekdir(DIR* dir
, long int position
)
295 dir
->seek_position
= position
;
302 return dir
->seek_position
;
314 alphasort(const struct dirent
** entry1
, const struct dirent
** entry2
)
316 return strcmp((*entry1
)->d_name
, (*entry2
)->d_name
);
321 scandir(const char* path
, struct dirent
*** _entryArray
,
322 int (*selectFunc
)(const struct dirent
*),
323 int (*compareFunc
)(const struct dirent
** entry1
,
324 const struct dirent
** entry2
))
326 struct dirent
** array
= NULL
;
327 size_t arrayCapacity
= 0;
328 size_t arrayCount
= 0;
330 DIR* dir
= opendir(path
);
335 struct dirent
* copiedEntry
;
337 struct dirent
* entry
= readdir(dir
);
341 // Check whether or not we should include this entry
342 if (selectFunc
!= NULL
&& !selectFunc(entry
))
345 copiedEntry
= malloc(entry
->d_reclen
);
346 if (copiedEntry
== NULL
)
349 memcpy(copiedEntry
, entry
, entry
->d_reclen
);
351 // Put it into the array
353 if (arrayCount
== arrayCapacity
) {
354 struct dirent
** newArray
;
357 if (arrayCapacity
== 0)
362 newArray
= realloc(array
, arrayCapacity
* sizeof(void*));
363 if (newArray
== NULL
) {
371 array
[arrayCount
++] = copiedEntry
;
376 if (arrayCount
> 0 && compareFunc
!= NULL
) {
377 qsort(array
, arrayCount
, sizeof(void*),
378 (int (*)(const void*, const void*))compareFunc
);
381 *_entryArray
= array
;
387 while (arrayCount
-- > 0)
388 free(array
[arrayCount
]);