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