• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 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 #include "net/disk_cache/simple/simple_file_enumerator.h"
6 
7 #include "base/files/file.h"
8 #include "base/files/file_util.h"
9 #include "base/logging.h"
10 
11 // We have an optimized implementation for POSIX, and a fallback
12 // implementation for other platforms.
13 
14 namespace disk_cache {
15 
16 #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
17 
SimpleFileEnumerator(const base::FilePath & path)18 SimpleFileEnumerator::SimpleFileEnumerator(const base::FilePath& path)
19     : path_(path), dir_(opendir(path.value().c_str())), has_error_(!dir_) {
20   if (has_error_) {
21     PLOG(ERROR) << "opendir " << path;
22   }
23 }
24 SimpleFileEnumerator::~SimpleFileEnumerator() = default;
25 
HasError() const26 bool SimpleFileEnumerator::HasError() const {
27   return has_error_;
28 }
29 
Next()30 absl::optional<SimpleFileEnumerator::Entry> SimpleFileEnumerator::Next() {
31   if (!dir_) {
32     return absl::nullopt;
33   }
34   while (true) {
35     // errno must be set to 0 before every readdir() call to detect errors.
36     errno = 0;
37     dirent* entry = readdir(dir_.get());
38     if (!entry) {
39       // Some implementations of readdir() (particularly older versions of
40       // Android Bionic) may leave errno set to EINTR even after they handle
41       // this case internally. It's safe to ignore EINTR in that case.
42       if (errno && errno != EINTR) {
43         PLOG(ERROR) << "readdir " << path_;
44         has_error_ = true;
45         dir_ = nullptr;
46         return absl::nullopt;
47       }
48       break;
49     }
50 
51     const std::string filename(entry->d_name);
52     if (filename == "." || filename == "..") {
53       continue;
54     }
55     base::FilePath path = path_.Append(base::FilePath(filename));
56     base::File::Info file_info;
57     if (!base::GetFileInfo(path, &file_info)) {
58       LOG(ERROR) << "Could not get file info for " << path;
59       continue;
60     }
61     if (file_info.is_directory) {
62       continue;
63     }
64     return absl::make_optional<Entry>(std::move(path), file_info.size,
65                                       file_info.last_accessed,
66                                       file_info.last_modified);
67   }
68   dir_ = nullptr;
69   return absl::nullopt;
70 }
71 
72 #else
73 SimpleFileEnumerator::SimpleFileEnumerator(const base::FilePath& path)
74     : enumerator_(path,
75                   /*recursive=*/false,
76                   base::FileEnumerator::FILES) {}
77 SimpleFileEnumerator::~SimpleFileEnumerator() = default;
78 
79 bool SimpleFileEnumerator::HasError() const {
80   return enumerator_.GetError() != base::File::FILE_OK;
81 }
82 
83 absl::optional<SimpleFileEnumerator::Entry> SimpleFileEnumerator::Next() {
84   base::FilePath path = enumerator_.Next();
85   if (path.empty()) {
86     return absl::nullopt;
87   }
88   base::FileEnumerator::FileInfo info = enumerator_.GetInfo();
89   return absl::make_optional<Entry>(std::move(path), info.GetSize(),
90                                     /*last_accessed=*/base::Time(),
91                                     info.GetLastModifiedTime());
92 }
93 #endif  // BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
94 
95 }  // namespace disk_cache
96