// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef BASE_FILES_DIR_READER_LINUX_H_ #define BASE_FILES_DIR_READER_LINUX_H_ #include <errno.h> #include <fcntl.h> #include <stddef.h> #include <stdint.h> #include <sys/syscall.h> #include <unistd.h> #include "base/logging.h" #include "base/macros.h" #include "base/posix/eintr_wrapper.h" // See the comments in dir_reader_posix.h about this. namespace base { struct linux_dirent { uint64_t d_ino; int64_t d_off; unsigned short d_reclen; unsigned char d_type; char d_name[0]; }; class DirReaderLinux { public: explicit DirReaderLinux(const char* directory_path) : fd_(open(directory_path, O_RDONLY | O_DIRECTORY)), offset_(0), size_(0) { memset(buf_, 0, sizeof(buf_)); } ~DirReaderLinux() { if (fd_ >= 0) { if (IGNORE_EINTR(close(fd_))) RAW_LOG(ERROR, "Failed to close directory handle"); } } bool IsValid() const { return fd_ >= 0; } // Move to the next entry returning false if the iteration is complete. bool Next() { if (size_) { linux_dirent* dirent = reinterpret_cast<linux_dirent*>(&buf_[offset_]); offset_ += dirent->d_reclen; } if (offset_ != size_) return true; const int r = syscall(__NR_getdents64, fd_, buf_, sizeof(buf_)); if (r == 0) return false; if (r == -1) { DPLOG(FATAL) << "getdents64 returned an error: " << errno; return false; } size_ = r; offset_ = 0; return true; } const char* name() const { if (!size_) return nullptr; const linux_dirent* dirent = reinterpret_cast<const linux_dirent*>(&buf_[offset_]); return dirent->d_name; } int fd() const { return fd_; } static bool IsFallback() { return false; } private: const int fd_; unsigned char buf_[512]; size_t offset_; size_t size_; DISALLOW_COPY_AND_ASSIGN(DirReaderLinux); }; } // namespace base #endif // BASE_FILES_DIR_READER_LINUX_H_