LCOV - code coverage report
Current view: top level - source/common/filesystem/posix - directory_iterator_impl.cc (source / functions) Hit Total Coverage
Test: coverage.dat Lines: 47 65 72.3 %
Date: 2024-01-05 06:35:25 Functions: 6 6 100.0 %

          Line data    Source code
       1             : #include "envoy/common/exception.h"
       2             : 
       3             : #include "source/common/common/fmt.h"
       4             : #include "source/common/common/utility.h"
       5             : #include "source/common/filesystem/directory_iterator_impl.h"
       6             : 
       7             : #include "absl/strings/strip.h"
       8             : 
       9             : namespace Envoy {
      10             : namespace Filesystem {
      11             : 
      12             : DirectoryIteratorImpl::DirectoryIteratorImpl(const std::string& directory_path)
      13             :     : directory_path_(absl::StripSuffix(directory_path, "/")),
      14          37 :       os_sys_calls_(Api::OsSysCallsSingleton::get()) {
      15          37 :   openDirectory();
      16          37 :   if (status_.ok()) {
      17          37 :     nextEntry();
      18          37 :   } else {
      19           0 :     entry_ = {"", FileType::Other, absl::nullopt};
      20           0 :   }
      21          37 : }
      22             : 
      23          74 : DirectoryIteratorImpl::~DirectoryIteratorImpl() {
      24          74 :   if (dir_ != nullptr) {
      25          37 :     ::closedir(dir_);
      26          37 :   }
      27          74 : }
      28             : 
      29         111 : DirectoryIteratorImpl& DirectoryIteratorImpl::operator++() {
      30         111 :   nextEntry();
      31         111 :   return *this;
      32         111 : }
      33             : 
      34          37 : void DirectoryIteratorImpl::openDirectory() {
      35          37 :   DIR* temp_dir = ::opendir(directory_path_.c_str());
      36          37 :   dir_ = temp_dir;
      37          37 :   if (!dir_) {
      38           0 :     status_ = absl::ErrnoToStatus(errno, fmt::format("unable to open directory {}: {}",
      39           0 :                                                      directory_path_, errorDetails(errno)));
      40           0 :   }
      41          37 : }
      42             : 
      43         148 : void DirectoryIteratorImpl::nextEntry() {
      44         148 :   errno = 0;
      45         148 :   dirent* entry = ::readdir(dir_);
      46             : 
      47         148 :   if (entry == nullptr) {
      48          37 :     entry_ = {"", FileType::Other, absl::nullopt};
      49          37 :     if (errno != 0) {
      50           0 :       status_ = absl::ErrnoToStatus(errno, fmt::format("unable to iterate directory {}: {}",
      51           0 :                                                        directory_path_, errorDetails(errno)));
      52           0 :     }
      53         111 :   } else {
      54         111 :     auto result = makeEntry(entry->d_name);
      55         111 :     status_ = result.status();
      56         111 :     if (!status_.ok()) {
      57             :       // If we failed to stat one file it might have just been deleted,
      58             :       // keep iterating over the rest of the dir.
      59           0 :       return nextEntry();
      60         111 :     } else {
      61         111 :       entry_ = result.value();
      62         111 :     }
      63         111 :   }
      64         148 : }
      65             : 
      66         111 : absl::StatusOr<DirectoryEntry> DirectoryIteratorImpl::makeEntry(absl::string_view filename) const {
      67         111 :   const std::string full_path = absl::StrCat(directory_path_, "/", filename);
      68         111 :   struct stat stat_buf;
      69         111 :   const Api::SysCallIntResult result = os_sys_calls_.stat(full_path.c_str(), &stat_buf);
      70         111 :   if (result.return_value_ != 0) {
      71           0 :     if (result.errno_ == ENOENT) {
      72             :       // Special case. This directory entity is likely to be a symlink,
      73             :       // but the reference is broken as the target could not be stat()'ed.
      74             :       // If we confirm this with an lstat, treat this file entity as
      75             :       // a regular file, which may be unlink()'ed.
      76           0 :       if (::lstat(full_path.c_str(), &stat_buf) == 0 && S_ISLNK(stat_buf.st_mode)) {
      77           0 :         return DirectoryEntry{std::string{filename}, FileType::Regular, absl::nullopt};
      78           0 :       }
      79           0 :     }
      80           0 :     return absl::ErrnoToStatus(
      81           0 :         result.errno_, fmt::format("unable to stat file: '{}' ({})", full_path, result.errno_));
      82         111 :   } else if (S_ISDIR(stat_buf.st_mode)) {
      83          74 :     return DirectoryEntry{std::string{filename}, FileType::Directory, absl::nullopt};
      84          74 :   } else if (S_ISREG(stat_buf.st_mode)) {
      85          37 :     return DirectoryEntry{std::string{filename}, FileType::Regular,
      86          37 :                           static_cast<uint64_t>(stat_buf.st_size)};
      87          37 :   } else {
      88           0 :     return DirectoryEntry{std::string{filename}, FileType::Other, absl::nullopt};
      89           0 :   }
      90         111 : }
      91             : 
      92             : } // namespace Filesystem
      93             : } // namespace Envoy

Generated by: LCOV version 1.15