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