Implemented seekdir() and telldir(). They were declared in <dirent.h> already.

So either +alphabranch or remove the declarations from <dirent.h>.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@32679 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2009-08-25 22:16:40 +00:00
parent 28563f792b
commit b02c147c05
2 changed files with 96 additions and 11 deletions

View File

@ -16,6 +16,8 @@ struct __DIR {
int fd;
short next_entry;
unsigned short entries_left;
long seek_position;
long current_position;
struct dirent first_entry;
};

View File

@ -1,4 +1,5 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Copyright 2004-2008, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*/
@ -11,14 +12,75 @@
#include <dirent_private.h>
#include <syscalls.h>
#include <syscall_utils.h>
#define RETURN_AND_SET_ERRNO(err) \
if (err < 0) { \
errno = err; \
return -1; \
} \
return err;
static int
do_seek_dir(DIR* dir)
{
if (dir->seek_position == dir->current_position)
return 0;
// If the seek position lies before the current position (the usual case),
// rewind to the beginning.
if (dir->seek_position < dir->current_position) {
status_t status = _kern_rewind_dir(dir->fd);
if (status < 0) {
errno = status;
return -1;
}
dir->current_position = 0;
dir->entries_left = 0;
}
// Now skip entries until we have reached seek_position.
while (dir->seek_position > dir->current_position) {
ssize_t count;
long toSkip = dir->seek_position - dir->current_position;
if (toSkip == dir->entries_left) {
// we have to skip exactly all of the currently buffered entries
dir->current_position = dir->seek_position;
dir->entries_left = 0;
return 0;
}
if (toSkip < dir->entries_left) {
// we have to skip only some of the buffered entries
for (; toSkip > 0; toSkip--) {
struct dirent* entry = (struct dirent*)
((uint8*)&dir->first_entry + dir->next_entry);
dir->entries_left--;
dir->next_entry += entry->d_reclen;
}
dir->current_position = dir->seek_position;
return 0;
}
// we have to skip more than the currently buffered entries
dir->current_position += dir->entries_left;
dir->entries_left = 0;
count = _kern_read_dir(dir->fd, &dir->first_entry, DIRENT_BUFFER_SIZE,
USHRT_MAX);
if (count <= 0) {
if (count < 0)
errno = count;
// end of directory
return -1;
}
dir->next_entry = 0;
dir->entries_left = count;
}
return 0;
}
// #pragma mark -
DIR *
@ -41,6 +103,8 @@ opendir(const char *path)
dir->fd = fd;
dir->entries_left = 0;
dir->seek_position = 0;
dir->current_position = 0;
return dir;
}
@ -62,12 +126,19 @@ readdir(DIR *dir)
{
ssize_t count;
if (dir->seek_position != dir->current_position) {
if (do_seek_dir(dir) != 0)
return NULL;
}
if (dir->entries_left > 0) {
struct dirent *dirent
= (struct dirent *)((uint8 *)&dir->first_entry + dir->next_entry);
dir->entries_left--;
dir->next_entry += dirent->d_reclen;
dir->seek_position++;
dir->current_position++;
return dirent;
}
@ -86,6 +157,8 @@ readdir(DIR *dir)
dir->entries_left = count - 1;
dir->next_entry = dir->first_entry.d_reclen;
dir->seek_position++;
dir->current_position++;
return &dir->first_entry;
}
@ -112,11 +185,21 @@ readdir_r(DIR *dir, struct dirent *entry, struct dirent **_result)
void
rewinddir(DIR *dir)
{
status_t status = _kern_rewind_dir(dir->fd);
if (status < 0)
errno = status;
else
dir->entries_left = 0;
dir->seek_position = 0;
}
void
seekdir(DIR* dir, long int position)
{
dir->seek_position = position;
}
long int
telldir(DIR* dir)
{
return dir->seek_position;
}