From b02c147c052fb3c7672e8ba8c15975c31d56a066 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Tue, 25 Aug 2009 22:16:40 +0000 Subject: [PATCH] Implemented seekdir() and telldir(). They were declared in already. So either +alphabranch or remove the declarations from . git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@32679 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/libroot/dirent_private.h | 2 + src/system/libroot/posix/dirent.c | 105 ++++++++++++++++++++--- 2 files changed, 96 insertions(+), 11 deletions(-) diff --git a/headers/private/libroot/dirent_private.h b/headers/private/libroot/dirent_private.h index 785549bac4..5e39f7b994 100644 --- a/headers/private/libroot/dirent_private.h +++ b/headers/private/libroot/dirent_private.h @@ -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; }; diff --git a/src/system/libroot/posix/dirent.c b/src/system/libroot/posix/dirent.c index 5274d9e246..cee73ff75a 100644 --- a/src/system/libroot/posix/dirent.c +++ b/src/system/libroot/posix/dirent.c @@ -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 #include +#include -#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; }