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