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 <stdint.h>
     11 #include <sys/syscall.h>
     12 #include <unistd.h>
     13 
     14 #include "base/logging.h"
     15 #include "base/posix/eintr_wrapper.h"
     16 
     17 // See the comments in dir_reader_posix.h about this.
     18 
     19 namespace base {
     20 
     21 struct linux_dirent {
     22   uint64_t        d_ino;
     23   int64_t         d_off;
     24   unsigned short  d_reclen;
     25   unsigned char   d_type;
     26   char            d_name[0];
     27 };
     28 
     29 class DirReaderLinux {
     30  public:
     31   explicit DirReaderLinux(const char* directory_path)
     32       : fd_(open(directory_path, O_RDONLY | O_DIRECTORY)),
     33         offset_(0),
     34         size_(0) {
     35     memset(buf_, 0, sizeof(buf_));
     36   }
     37 
     38   ~DirReaderLinux() {
     39     if (fd_ >= 0) {
     40       if (IGNORE_EINTR(close(fd_)))
     41         RAW_LOG(ERROR, "Failed to close directory handle");
     42     }
     43   }
     44 
     45   bool IsValid() const {
     46     return fd_ >= 0;
     47   }
     48 
     49   // Move to the next entry returning false if the iteration is complete.
     50   bool Next() {
     51     if (size_) {
     52       linux_dirent* dirent = reinterpret_cast<linux_dirent*>(&buf_[offset_]);
     53       offset_ += dirent->d_reclen;
     54     }
     55 
     56     if (offset_ != size_)
     57       return true;
     58 
     59     const int r = syscall(__NR_getdents64, fd_, buf_, sizeof(buf_));
     60     if (r == 0)
     61       return false;
     62     if (r == -1) {
     63       DPLOG(FATAL) << "getdents64 returned an error: " << errno;
     64       return false;
     65     }
     66     size_ = r;
     67     offset_ = 0;
     68     return true;
     69   }
     70 
     71   const char* name() const {
     72     if (!size_)
     73       return NULL;
     74 
     75     const linux_dirent* dirent =
     76         reinterpret_cast<const linux_dirent*>(&buf_[offset_]);
     77     return dirent->d_name;
     78   }
     79 
     80   int fd() const {
     81     return fd_;
     82   }
     83 
     84   static bool IsFallback() {
     85     return false;
     86   }
     87 
     88  private:
     89   const int fd_;
     90   unsigned char buf_[512];
     91   size_t offset_, size_;
     92 
     93   DISALLOW_COPY_AND_ASSIGN(DirReaderLinux);
     94 };
     95 
     96 }  // namespace base
     97 
     98 #endif // BASE_FILES_DIR_READER_LINUX_H_
     99