diff options
-rw-r--r-- | libc/bionic/dirent.cpp | 19 | ||||
-rw-r--r-- | libc/include/dirent.h | 2 | ||||
-rw-r--r-- | tests/dirent_test.cpp | 47 | ||||
-rw-r--r-- | tests/stdio_test.cpp | 2 |
4 files changed, 69 insertions, 1 deletions
diff --git a/libc/bionic/dirent.cpp b/libc/bionic/dirent.cpp index 5e1c7a5..6d87097 100644 --- a/libc/bionic/dirent.cpp +++ b/libc/bionic/dirent.cpp @@ -43,6 +43,7 @@ struct DIR { int fd_; size_t available_bytes_; dirent* next_; + long current_pos_; pthread_mutex_t mutex_; dirent buff_[15]; }; @@ -55,6 +56,7 @@ static DIR* __allocate_DIR(int fd) { d->fd_ = fd; d->available_bytes_ = 0; d->next_ = NULL; + d->current_pos_ = 0L; pthread_mutex_init(&d->mutex_, NULL); return d; } @@ -100,6 +102,9 @@ static dirent* __readdir_locked(DIR* d) { dirent* entry = d->next_; d->next_ = reinterpret_cast<dirent*>(reinterpret_cast<char*>(entry) + entry->d_reclen); d->available_bytes_ -= entry->d_reclen; + // The directory entry offset uses 0, 1, 2 instead of real file offset, + // so the value range of long type is enough. + d->current_pos_ = static_cast<long>(entry->d_off); return entry; } @@ -146,6 +151,20 @@ void rewinddir(DIR* d) { ScopedPthreadMutexLocker locker(&d->mutex_); lseek(d->fd_, 0, SEEK_SET); d->available_bytes_ = 0; + d->current_pos_ = 0L; +} + +void seekdir(DIR* d, long offset) { + ScopedPthreadMutexLocker locker(&d->mutex_); + off_t ret = lseek(d->fd_, offset, SEEK_SET); + if (ret != -1L) { + d->available_bytes_ = 0; + d->current_pos_ = ret; + } +} + +long telldir(DIR* d) { + return d->current_pos_; } int alphasort(const dirent** a, const dirent** b) { diff --git a/libc/include/dirent.h b/libc/include/dirent.h index 4ca3a7d..63716a4 100644 --- a/libc/include/dirent.h +++ b/libc/include/dirent.h @@ -76,6 +76,8 @@ extern int readdir_r(DIR*, struct dirent*, struct dirent**); extern int readdir64_r(DIR*, struct dirent64*, struct dirent64**); extern int closedir(DIR*); extern void rewinddir(DIR*); +extern void seekdir(DIR*, long); +extern long telldir(DIR*); extern int dirfd(DIR*); extern int alphasort(const struct dirent**, const struct dirent**); extern int alphasort64(const struct dirent64**, const struct dirent64**); diff --git a/tests/dirent_test.cpp b/tests/dirent_test.cpp index 6aadb37..214dd78 100644 --- a/tests/dirent_test.cpp +++ b/tests/dirent_test.cpp @@ -231,3 +231,50 @@ TEST(dirent, rewinddir) { ASSERT_EQ(pass1[i], pass2[i]); } } + +TEST(dirent, seekdir_telldir) { + DIR* d = opendir("/proc/self"); + ASSERT_TRUE(d != NULL); + std::vector<long> offset_list; + std::vector<std::string> name_list; + dirent* e = NULL; + + offset_list.push_back(telldir(d)); + ASSERT_EQ(0L, offset_list.back()); + + while ((e = readdir(d)) != NULL) { + name_list.push_back(e->d_name); + offset_list.push_back(telldir(d)); + // Make sure telldir() point to the next entry. + ASSERT_EQ(e->d_off, offset_list.back()); + } + + long end_offset = telldir(d); + // telldir() should not pass the end of the file. + ASSERT_EQ(offset_list.back(), end_offset); + offset_list.pop_back(); + + for (size_t i = 0; i < offset_list.size(); ++i) { + seekdir(d, offset_list[i]); + ASSERT_EQ(offset_list[i], telldir(d)); + e = readdir(d); + ASSERT_TRUE(e != NULL); + ASSERT_STREQ(name_list[i].c_str(), e->d_name); + } + for (int i = static_cast<int>(offset_list.size()) - 1; i >= 0; --i) { + seekdir(d, offset_list[i]); + ASSERT_EQ(offset_list[i], telldir(d)); + e = readdir(d); + ASSERT_TRUE(e != NULL); + ASSERT_STREQ(name_list[i].c_str(), e->d_name); + } + + // Seek to the end, read NULL. + seekdir(d, end_offset); + ASSERT_EQ(end_offset, telldir(d)); + errno = 0; + ASSERT_EQ(NULL, readdir(d)); + ASSERT_EQ(0, errno); + + ASSERT_EQ(0, closedir(d)); +} diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp index 549792e..6be372c 100644 --- a/tests/stdio_test.cpp +++ b/tests/stdio_test.cpp @@ -77,7 +77,7 @@ TEST(stdio, dprintf) { int rc = dprintf(tf.fd, "hello\n"); ASSERT_EQ(rc, 6); - lseek(tf.fd, SEEK_SET, 0); + lseek(tf.fd, 0, SEEK_SET); FILE* tfile = fdopen(tf.fd, "r"); ASSERT_TRUE(tfile != NULL); |