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