| // 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_ |