Home | History | Annotate | Download | only in files
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef BASE_FILES_DIR_READER_LINUX_H_
      6 #define BASE_FILES_DIR_READER_LINUX_H_
      7 
      8 #include <errno.h>
      9 #include <fcntl.h>
     10 #include <stddef.h>
     11 #include <stdint.h>
     12 #include <sys/syscall.h>
     13 #include <unistd.h>
     14 
     15 #include "base/logging.h"
     16 #include "base/macros.h"
     17 #include "base/posix/eintr_wrapper.h"
     18 
     19 // See the comments in dir_reader_posix.h about this.
     20 
     21 namespace base {
     22 
     23 struct linux_dirent {
     24   uint64_t        d_ino;
     25   int64_t         d_off;
     26   unsigned short  d_reclen;
     27   unsigned char   d_type;
     28   char            d_name[0];
     29 };
     30 
     31 class DirReaderLinux {
     32  public:
     33   explicit DirReaderLinux(const char* directory_path)
     34       : fd_(open(directory_path, O_RDONLY | O_DIRECTORY)),
     35         offset_(0),
     36         size_(0) {
     37     memset(buf_, 0, sizeof(buf_));
     38   }
     39 
     40   ~DirReaderLinux() {
     41     if (fd_ >= 0) {
     42       if (IGNORE_EINTR(close(fd_)))
     43         RAW_LOG(ERROR, "Failed to close directory handle");
     44     }
     45   }
     46 
     47   bool IsValid() const {
     48     return fd_ >= 0;
     49   }
     50 
     51   // Move to the next entry returning false if the iteration is complete.
     52   bool Next() {
     53     if (size_) {
     54       linux_dirent* dirent = reinterpret_cast<linux_dirent*>(&buf_[offset_]);
     55       offset_ += dirent->d_reclen;
     56     }
     57 
     58     if (offset_ != size_)
     59       return true;
     60 
     61     const int r = syscall(__NR_getdents64, fd_, buf_, sizeof(buf_));
     62     if (r == 0)
     63       return false;
     64     if (r == -1) {
     65       DPLOG(FATAL) << "getdents64 returned an error: " << errno;
     66       return false;
     67     }
     68     size_ = r;
     69     offset_ = 0;
     70     return true;
     71   }
     72 
     73   const char* name() const {
     74     if (!size_)
     75       return nullptr;
     76 
     77     const linux_dirent* dirent =
     78         reinterpret_cast<const linux_dirent*>(&buf_[offset_]);
     79     return dirent->d_name;
     80   }
     81 
     82   int fd() const {
     83     return fd_;
     84   }
     85 
     86   static bool IsFallback() {
     87     return false;
     88   }
     89 
     90  private:
     91   const int fd_;
     92   unsigned char buf_[512];
     93   size_t offset_;
     94   size_t size_;
     95 
     96   DISALLOW_COPY_AND_ASSIGN(DirReaderLinux);
     97 };
     98 
     99 }  // namespace base
    100 
    101 #endif  // BASE_FILES_DIR_READER_LINUX_H_
    102