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