1*8b6cd535SAndroid Build Coastguard Worker // Copyright (C) 2019 Google LLC
2*8b6cd535SAndroid Build Coastguard Worker //
3*8b6cd535SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*8b6cd535SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*8b6cd535SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*8b6cd535SAndroid Build Coastguard Worker //
7*8b6cd535SAndroid Build Coastguard Worker // http://www.apache.org/licenses/LICENSE-2.0
8*8b6cd535SAndroid Build Coastguard Worker //
9*8b6cd535SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*8b6cd535SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*8b6cd535SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*8b6cd535SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*8b6cd535SAndroid Build Coastguard Worker // limitations under the License.
14*8b6cd535SAndroid Build Coastguard Worker
15*8b6cd535SAndroid Build Coastguard Worker #include "icing/file/filesystem.h"
16*8b6cd535SAndroid Build Coastguard Worker
17*8b6cd535SAndroid Build Coastguard Worker #include <dirent.h>
18*8b6cd535SAndroid Build Coastguard Worker #include <dlfcn.h>
19*8b6cd535SAndroid Build Coastguard Worker #include <fcntl.h>
20*8b6cd535SAndroid Build Coastguard Worker #include <fnmatch.h>
21*8b6cd535SAndroid Build Coastguard Worker #include <pthread.h>
22*8b6cd535SAndroid Build Coastguard Worker #include <sys/resource.h>
23*8b6cd535SAndroid Build Coastguard Worker #include <sys/stat.h>
24*8b6cd535SAndroid Build Coastguard Worker #include <sys/types.h>
25*8b6cd535SAndroid Build Coastguard Worker #include <unistd.h>
26*8b6cd535SAndroid Build Coastguard Worker
27*8b6cd535SAndroid Build Coastguard Worker #include <algorithm>
28*8b6cd535SAndroid Build Coastguard Worker #include <cerrno>
29*8b6cd535SAndroid Build Coastguard Worker #include <cstdint>
30*8b6cd535SAndroid Build Coastguard Worker #include <unordered_set>
31*8b6cd535SAndroid Build Coastguard Worker
32*8b6cd535SAndroid Build Coastguard Worker #include "icing/absl_ports/str_cat.h"
33*8b6cd535SAndroid Build Coastguard Worker #include "icing/legacy/core/icing-string-util.h"
34*8b6cd535SAndroid Build Coastguard Worker #include "icing/util/logging.h"
35*8b6cd535SAndroid Build Coastguard Worker
36*8b6cd535SAndroid Build Coastguard Worker using std::vector;
37*8b6cd535SAndroid Build Coastguard Worker
38*8b6cd535SAndroid Build Coastguard Worker namespace icing {
39*8b6cd535SAndroid Build Coastguard Worker namespace lib {
40*8b6cd535SAndroid Build Coastguard Worker
41*8b6cd535SAndroid Build Coastguard Worker namespace {
42*8b6cd535SAndroid Build Coastguard Worker
43*8b6cd535SAndroid Build Coastguard Worker // The size of the block for st_blksize returned by stat() and as a
44*8b6cd535SAndroid Build Coastguard Worker // consequence also the granularity of GetDiskUsage(). It seems that there is
45*8b6cd535SAndroid Build Coastguard Worker // no appropriate constant for this. See http://linux.die.net/man/2/stat
46*8b6cd535SAndroid Build Coastguard Worker constexpr int kStatBlockSize = 512;
47*8b6cd535SAndroid Build Coastguard Worker
48*8b6cd535SAndroid Build Coastguard Worker // Logs information about open file descriptors.
49*8b6cd535SAndroid Build Coastguard Worker //
50*8b6cd535SAndroid Build Coastguard Worker // This function uses getrlimit() to find the maximum number of file
51*8b6cd535SAndroid Build Coastguard Worker // descriptors, then calls readlink("/proc/self/fd/N") for each possible file
52*8b6cd535SAndroid Build Coastguard Worker // descriptor number to get a description of the open file from procfs.
53*8b6cd535SAndroid Build Coastguard Worker //
54*8b6cd535SAndroid Build Coastguard Worker // We don't use readdir() to list the contents of /proc/self/fd (which would be
55*8b6cd535SAndroid Build Coastguard Worker // the more obvious approach) because that would require a free file descriptor
56*8b6cd535SAndroid Build Coastguard Worker // to open the directory, while we call this function when all file descriptors
57*8b6cd535SAndroid Build Coastguard Worker // are in use.
LogOpenFileDescriptors()58*8b6cd535SAndroid Build Coastguard Worker void LogOpenFileDescriptors() {
59*8b6cd535SAndroid Build Coastguard Worker // Determine the limit on file descriptor numbers. RLIMIT_NOFILE should return
60*8b6cd535SAndroid Build Coastguard Worker // the maximum file descriptor + 1, which is 1024 on Android by default. We
61*8b6cd535SAndroid Build Coastguard Worker // restrict the limit to 4096 so we don't take too much time if the value
62*8b6cd535SAndroid Build Coastguard Worker // turns out to be much higher for some reason.
63*8b6cd535SAndroid Build Coastguard Worker constexpr int kMaxFileDescriptorsToStat = 4096;
64*8b6cd535SAndroid Build Coastguard Worker struct rlimit rlim = {0, 0};
65*8b6cd535SAndroid Build Coastguard Worker if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
66*8b6cd535SAndroid Build Coastguard Worker ICING_LOG(ERROR) << "getrlimit() failed (errno=" << errno << ")";
67*8b6cd535SAndroid Build Coastguard Worker return;
68*8b6cd535SAndroid Build Coastguard Worker }
69*8b6cd535SAndroid Build Coastguard Worker int fd_lim = rlim.rlim_cur;
70*8b6cd535SAndroid Build Coastguard Worker if (fd_lim > kMaxFileDescriptorsToStat) {
71*8b6cd535SAndroid Build Coastguard Worker ICING_LOG(ERROR) << "Maximum number of file descriptors (" << fd_lim
72*8b6cd535SAndroid Build Coastguard Worker << ") too large.";
73*8b6cd535SAndroid Build Coastguard Worker fd_lim = kMaxFileDescriptorsToStat;
74*8b6cd535SAndroid Build Coastguard Worker }
75*8b6cd535SAndroid Build Coastguard Worker ICING_LOG(INFO) << "Listing up to " << fd_lim << " file descriptors.";
76*8b6cd535SAndroid Build Coastguard Worker
77*8b6cd535SAndroid Build Coastguard Worker // Verify that /proc/self/fd is a directory. If not, procfs is not mounted or
78*8b6cd535SAndroid Build Coastguard Worker // inaccessible for some other reason. In that case, there's no point trying
79*8b6cd535SAndroid Build Coastguard Worker // to read from it.
80*8b6cd535SAndroid Build Coastguard Worker struct stat statbuf;
81*8b6cd535SAndroid Build Coastguard Worker if (stat("/proc/self/fd", &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) {
82*8b6cd535SAndroid Build Coastguard Worker ICING_LOG(ERROR) << "/proc/self/fd not available. Giving up.";
83*8b6cd535SAndroid Build Coastguard Worker return;
84*8b6cd535SAndroid Build Coastguard Worker }
85*8b6cd535SAndroid Build Coastguard Worker
86*8b6cd535SAndroid Build Coastguard Worker // Now read each link individually.
87*8b6cd535SAndroid Build Coastguard Worker const int path_size = 1024;
88*8b6cd535SAndroid Build Coastguard Worker char path[path_size];
89*8b6cd535SAndroid Build Coastguard Worker const int target_size = 1024;
90*8b6cd535SAndroid Build Coastguard Worker char target[target_size];
91*8b6cd535SAndroid Build Coastguard Worker for (int fd = 0; fd < fd_lim; ++fd) {
92*8b6cd535SAndroid Build Coastguard Worker snprintf(path, path_size, "/proc/self/fd/%d", fd);
93*8b6cd535SAndroid Build Coastguard Worker ssize_t len = readlink(path, target, target_size);
94*8b6cd535SAndroid Build Coastguard Worker if (len >= 0) {
95*8b6cd535SAndroid Build Coastguard Worker // Zero-terminate the buffer, because readlink() won't.
96*8b6cd535SAndroid Build Coastguard Worker target[len < target_size ? len : target_size - 1] = '\0';
97*8b6cd535SAndroid Build Coastguard Worker ICING_LOG(INFO) << "fd " << fd << " -> \"" << target << "\"";
98*8b6cd535SAndroid Build Coastguard Worker } else if (errno != ENOENT) {
99*8b6cd535SAndroid Build Coastguard Worker ICING_LOG(ERROR) << "fd " << fd << " -> ? (errno=" << errno << ")";
100*8b6cd535SAndroid Build Coastguard Worker }
101*8b6cd535SAndroid Build Coastguard Worker }
102*8b6cd535SAndroid Build Coastguard Worker ICING_LOG(INFO) << "File descriptor list complete.";
103*8b6cd535SAndroid Build Coastguard Worker }
104*8b6cd535SAndroid Build Coastguard Worker
105*8b6cd535SAndroid Build Coastguard Worker // Logs an error formatted as: desc1 + file_name + desc2 + strerror(errnum).
106*8b6cd535SAndroid Build Coastguard Worker //
107*8b6cd535SAndroid Build Coastguard Worker // If errnum == EMFILE (too many open files), then it also logs a list of open
108*8b6cd535SAndroid Build Coastguard Worker // file descriptors (see LogOpenFileDescriptors() above).
LogOpenError(const char * desc1,const char * file_name,const char * desc2,int errnum)109*8b6cd535SAndroid Build Coastguard Worker void LogOpenError(const char* desc1, const char* file_name, const char* desc2,
110*8b6cd535SAndroid Build Coastguard Worker int errnum) {
111*8b6cd535SAndroid Build Coastguard Worker if (errnum == ENOENT) {
112*8b6cd535SAndroid Build Coastguard Worker ICING_VLOG(1) << desc1 << file_name << desc2 << strerror(errnum);
113*8b6cd535SAndroid Build Coastguard Worker } else {
114*8b6cd535SAndroid Build Coastguard Worker ICING_LOG(ERROR) << desc1 << file_name << desc2 << strerror(errnum);
115*8b6cd535SAndroid Build Coastguard Worker }
116*8b6cd535SAndroid Build Coastguard Worker if (errnum == EMFILE) {
117*8b6cd535SAndroid Build Coastguard Worker LogOpenFileDescriptors();
118*8b6cd535SAndroid Build Coastguard Worker }
119*8b6cd535SAndroid Build Coastguard Worker }
120*8b6cd535SAndroid Build Coastguard Worker
121*8b6cd535SAndroid Build Coastguard Worker // Recursive implementation of ListDirectory. Prefix is used to prepend the
122*8b6cd535SAndroid Build Coastguard Worker // directory name during recursion.
123*8b6cd535SAndroid Build Coastguard Worker // We cannot use scandir due to a bug in old platform versions. See b/7339844.
ListDirectoryInternal(const char * dir_name,const std::unordered_set<std::string> & exclude,bool recursive,const char * prefix,std::vector<std::string> * entries)124*8b6cd535SAndroid Build Coastguard Worker bool ListDirectoryInternal(const char* dir_name,
125*8b6cd535SAndroid Build Coastguard Worker const std::unordered_set<std::string>& exclude,
126*8b6cd535SAndroid Build Coastguard Worker bool recursive, const char* prefix,
127*8b6cd535SAndroid Build Coastguard Worker std::vector<std::string>* entries) {
128*8b6cd535SAndroid Build Coastguard Worker DIR* dir = opendir(dir_name);
129*8b6cd535SAndroid Build Coastguard Worker if (!dir) {
130*8b6cd535SAndroid Build Coastguard Worker LogOpenError("Unable to open directory ", dir_name, ": ", errno);
131*8b6cd535SAndroid Build Coastguard Worker return false;
132*8b6cd535SAndroid Build Coastguard Worker }
133*8b6cd535SAndroid Build Coastguard Worker
134*8b6cd535SAndroid Build Coastguard Worker // According to linux man page
135*8b6cd535SAndroid Build Coastguard Worker // (https://man7.org/linux/man-pages/man3/readdir.3.html#RETURN_VALUE), dirent
136*8b6cd535SAndroid Build Coastguard Worker // may be statically allocated, so don't free it.
137*8b6cd535SAndroid Build Coastguard Worker dirent* p;
138*8b6cd535SAndroid Build Coastguard Worker // readdir's implementation seems to be thread safe.
139*8b6cd535SAndroid Build Coastguard Worker while ((p = readdir(dir)) != nullptr) {
140*8b6cd535SAndroid Build Coastguard Worker std::string file_name(p->d_name);
141*8b6cd535SAndroid Build Coastguard Worker if (file_name == "." || file_name == ".." ||
142*8b6cd535SAndroid Build Coastguard Worker exclude.find(file_name) != exclude.end()) {
143*8b6cd535SAndroid Build Coastguard Worker continue;
144*8b6cd535SAndroid Build Coastguard Worker }
145*8b6cd535SAndroid Build Coastguard Worker std::string relative_path = absl_ports::StrCat(prefix, p->d_name);
146*8b6cd535SAndroid Build Coastguard Worker entries->push_back(relative_path);
147*8b6cd535SAndroid Build Coastguard Worker // Recurse down directories, if requested.
148*8b6cd535SAndroid Build Coastguard Worker if (recursive && (p->d_type == DT_DIR)) {
149*8b6cd535SAndroid Build Coastguard Worker std::string sub_dir_name = absl_ports::StrCat(dir_name, "/", p->d_name);
150*8b6cd535SAndroid Build Coastguard Worker std::string relative_path_with_slash =
151*8b6cd535SAndroid Build Coastguard Worker absl_ports::StrCat(relative_path, "/");
152*8b6cd535SAndroid Build Coastguard Worker if (!ListDirectoryInternal(sub_dir_name.c_str(), exclude, recursive,
153*8b6cd535SAndroid Build Coastguard Worker relative_path_with_slash.c_str(), entries)) {
154*8b6cd535SAndroid Build Coastguard Worker return false;
155*8b6cd535SAndroid Build Coastguard Worker }
156*8b6cd535SAndroid Build Coastguard Worker }
157*8b6cd535SAndroid Build Coastguard Worker }
158*8b6cd535SAndroid Build Coastguard Worker if (closedir(dir) != 0) {
159*8b6cd535SAndroid Build Coastguard Worker ICING_LOG(ERROR) << "Error closing " << dir_name << " " << strerror(errno);
160*8b6cd535SAndroid Build Coastguard Worker }
161*8b6cd535SAndroid Build Coastguard Worker return true;
162*8b6cd535SAndroid Build Coastguard Worker }
163*8b6cd535SAndroid Build Coastguard Worker
164*8b6cd535SAndroid Build Coastguard Worker } // namespace
165*8b6cd535SAndroid Build Coastguard Worker
~ScopedFd()166*8b6cd535SAndroid Build Coastguard Worker ScopedFd::~ScopedFd() {
167*8b6cd535SAndroid Build Coastguard Worker if (fd_ >= 0) {
168*8b6cd535SAndroid Build Coastguard Worker close(fd_);
169*8b6cd535SAndroid Build Coastguard Worker }
170*8b6cd535SAndroid Build Coastguard Worker }
171*8b6cd535SAndroid Build Coastguard Worker
reset(int fd)172*8b6cd535SAndroid Build Coastguard Worker void ScopedFd::reset(int fd) {
173*8b6cd535SAndroid Build Coastguard Worker if (fd_ >= 0) {
174*8b6cd535SAndroid Build Coastguard Worker close(fd_);
175*8b6cd535SAndroid Build Coastguard Worker }
176*8b6cd535SAndroid Build Coastguard Worker fd_ = fd;
177*8b6cd535SAndroid Build Coastguard Worker }
178*8b6cd535SAndroid Build Coastguard Worker
179*8b6cd535SAndroid Build Coastguard Worker const int64_t Filesystem::kBadFileSize;
180*8b6cd535SAndroid Build Coastguard Worker
DeleteFile(const char * file_name) const181*8b6cd535SAndroid Build Coastguard Worker bool Filesystem::DeleteFile(const char* file_name) const {
182*8b6cd535SAndroid Build Coastguard Worker ICING_VLOG(1) << "Deleting file " << file_name;
183*8b6cd535SAndroid Build Coastguard Worker int ret = unlink(file_name);
184*8b6cd535SAndroid Build Coastguard Worker if (ret != 0 && errno != ENOENT) {
185*8b6cd535SAndroid Build Coastguard Worker ICING_LOG(ERROR) << "Deleting file " << file_name << " failed: " << strerror(errno);
186*8b6cd535SAndroid Build Coastguard Worker return false;
187*8b6cd535SAndroid Build Coastguard Worker }
188*8b6cd535SAndroid Build Coastguard Worker return true;
189*8b6cd535SAndroid Build Coastguard Worker }
190*8b6cd535SAndroid Build Coastguard Worker
DeleteDirectory(const char * dir_name) const191*8b6cd535SAndroid Build Coastguard Worker bool Filesystem::DeleteDirectory(const char* dir_name) const {
192*8b6cd535SAndroid Build Coastguard Worker int ret = rmdir(dir_name);
193*8b6cd535SAndroid Build Coastguard Worker if (ret != 0 && errno != ENOENT) {
194*8b6cd535SAndroid Build Coastguard Worker ICING_LOG(ERROR) << "Deleting directory " << dir_name << " failed: " << strerror(errno);
195*8b6cd535SAndroid Build Coastguard Worker return false;
196*8b6cd535SAndroid Build Coastguard Worker }
197*8b6cd535SAndroid Build Coastguard Worker return true;
198*8b6cd535SAndroid Build Coastguard Worker }
199*8b6cd535SAndroid Build Coastguard Worker
DeleteDirectoryRecursively(const char * dir_name) const200*8b6cd535SAndroid Build Coastguard Worker bool Filesystem::DeleteDirectoryRecursively(const char* dir_name) const {
201*8b6cd535SAndroid Build Coastguard Worker // Ensure the dir_name really is a directory and exists.
202*8b6cd535SAndroid Build Coastguard Worker struct stat st;
203*8b6cd535SAndroid Build Coastguard Worker if (stat(dir_name, &st) < 0) {
204*8b6cd535SAndroid Build Coastguard Worker if (errno == ENOENT) {
205*8b6cd535SAndroid Build Coastguard Worker return true; // If directory didn't exist, this was successful.
206*8b6cd535SAndroid Build Coastguard Worker }
207*8b6cd535SAndroid Build Coastguard Worker ICING_LOG(ERROR) << "Stat " << dir_name << " failed: " << strerror(errno);
208*8b6cd535SAndroid Build Coastguard Worker return false;
209*8b6cd535SAndroid Build Coastguard Worker }
210*8b6cd535SAndroid Build Coastguard Worker vector<std::string> entries;
211*8b6cd535SAndroid Build Coastguard Worker if (!ListDirectory(dir_name, &entries)) {
212*8b6cd535SAndroid Build Coastguard Worker return false;
213*8b6cd535SAndroid Build Coastguard Worker }
214*8b6cd535SAndroid Build Coastguard Worker
215*8b6cd535SAndroid Build Coastguard Worker bool success = true;
216*8b6cd535SAndroid Build Coastguard Worker for (vector<std::string>::iterator i = entries.begin(); i != entries.end();
217*8b6cd535SAndroid Build Coastguard Worker ++i) {
218*8b6cd535SAndroid Build Coastguard Worker std::string filename = std::string(dir_name) + '/' + *i;
219*8b6cd535SAndroid Build Coastguard Worker if (stat(filename.c_str(), &st) < 0) {
220*8b6cd535SAndroid Build Coastguard Worker ICING_LOG(ERROR) << "Stat " << filename << " failed: " << strerror(errno);
221*8b6cd535SAndroid Build Coastguard Worker success = false;
222*8b6cd535SAndroid Build Coastguard Worker } else if (S_ISDIR(st.st_mode)) {
223*8b6cd535SAndroid Build Coastguard Worker success = DeleteDirectoryRecursively(filename.c_str()) && success;
224*8b6cd535SAndroid Build Coastguard Worker } else {
225*8b6cd535SAndroid Build Coastguard Worker success = DeleteFile(filename.c_str()) && success;
226*8b6cd535SAndroid Build Coastguard Worker }
227*8b6cd535SAndroid Build Coastguard Worker }
228*8b6cd535SAndroid Build Coastguard Worker
229*8b6cd535SAndroid Build Coastguard Worker if (success) {
230*8b6cd535SAndroid Build Coastguard Worker success = DeleteDirectory(dir_name);
231*8b6cd535SAndroid Build Coastguard Worker }
232*8b6cd535SAndroid Build Coastguard Worker
233*8b6cd535SAndroid Build Coastguard Worker return success;
234*8b6cd535SAndroid Build Coastguard Worker }
235*8b6cd535SAndroid Build Coastguard Worker
FileExists(const char * file_name) const236*8b6cd535SAndroid Build Coastguard Worker bool Filesystem::FileExists(const char* file_name) const {
237*8b6cd535SAndroid Build Coastguard Worker bool exists = false;
238*8b6cd535SAndroid Build Coastguard Worker struct stat st;
239*8b6cd535SAndroid Build Coastguard Worker if (stat(file_name, &st) == 0) {
240*8b6cd535SAndroid Build Coastguard Worker exists = S_ISREG(st.st_mode) != 0;
241*8b6cd535SAndroid Build Coastguard Worker } else {
242*8b6cd535SAndroid Build Coastguard Worker if (errno != ENOENT) {
243*8b6cd535SAndroid Build Coastguard Worker ICING_LOG(ERROR) << "Unable to stat file " << file_name << ": " << strerror(errno);
244*8b6cd535SAndroid Build Coastguard Worker }
245*8b6cd535SAndroid Build Coastguard Worker exists = false;
246*8b6cd535SAndroid Build Coastguard Worker }
247*8b6cd535SAndroid Build Coastguard Worker return exists;
248*8b6cd535SAndroid Build Coastguard Worker }
249*8b6cd535SAndroid Build Coastguard Worker
DirectoryExists(const char * dir_name) const250*8b6cd535SAndroid Build Coastguard Worker bool Filesystem::DirectoryExists(const char* dir_name) const {
251*8b6cd535SAndroid Build Coastguard Worker bool exists = false;
252*8b6cd535SAndroid Build Coastguard Worker struct stat st;
253*8b6cd535SAndroid Build Coastguard Worker if (stat(dir_name, &st) == 0) {
254*8b6cd535SAndroid Build Coastguard Worker exists = S_ISDIR(st.st_mode) != 0;
255*8b6cd535SAndroid Build Coastguard Worker } else {
256*8b6cd535SAndroid Build Coastguard Worker if (errno != ENOENT) {
257*8b6cd535SAndroid Build Coastguard Worker ICING_LOG(ERROR) << "Unable to stat directory " << dir_name << ": " << strerror(errno);
258*8b6cd535SAndroid Build Coastguard Worker }
259*8b6cd535SAndroid Build Coastguard Worker exists = false;
260*8b6cd535SAndroid Build Coastguard Worker }
261*8b6cd535SAndroid Build Coastguard Worker return exists;
262*8b6cd535SAndroid Build Coastguard Worker }
263*8b6cd535SAndroid Build Coastguard Worker
GetBasenameIndex(const char * file_name) const264*8b6cd535SAndroid Build Coastguard Worker int Filesystem::GetBasenameIndex(const char* file_name) const {
265*8b6cd535SAndroid Build Coastguard Worker // Find final slash.
266*8b6cd535SAndroid Build Coastguard Worker const char* last_slash = strrchr(file_name, '/');
267*8b6cd535SAndroid Build Coastguard Worker if (!last_slash) {
268*8b6cd535SAndroid Build Coastguard Worker // file_name is just basename.
269*8b6cd535SAndroid Build Coastguard Worker return 0;
270*8b6cd535SAndroid Build Coastguard Worker }
271*8b6cd535SAndroid Build Coastguard Worker
272*8b6cd535SAndroid Build Coastguard Worker // Skip slash.
273*8b6cd535SAndroid Build Coastguard Worker return last_slash + 1 - file_name;
274*8b6cd535SAndroid Build Coastguard Worker }
275*8b6cd535SAndroid Build Coastguard Worker
GetBasename(const char * file_name) const276*8b6cd535SAndroid Build Coastguard Worker std::string Filesystem::GetBasename(const char* file_name) const {
277*8b6cd535SAndroid Build Coastguard Worker size_t len = strlen(file_name);
278*8b6cd535SAndroid Build Coastguard Worker int idx = GetBasenameIndex(file_name);
279*8b6cd535SAndroid Build Coastguard Worker return std::string(file_name + idx, len - idx);
280*8b6cd535SAndroid Build Coastguard Worker }
281*8b6cd535SAndroid Build Coastguard Worker
GetDirname(const char * file_name) const282*8b6cd535SAndroid Build Coastguard Worker std::string Filesystem::GetDirname(const char* file_name) const {
283*8b6cd535SAndroid Build Coastguard Worker int idx = GetBasenameIndex(file_name);
284*8b6cd535SAndroid Build Coastguard Worker // Remove the trailing slash
285*8b6cd535SAndroid Build Coastguard Worker if (idx > 0) {
286*8b6cd535SAndroid Build Coastguard Worker idx -= 1;
287*8b6cd535SAndroid Build Coastguard Worker }
288*8b6cd535SAndroid Build Coastguard Worker return std::string(file_name, idx);
289*8b6cd535SAndroid Build Coastguard Worker }
290*8b6cd535SAndroid Build Coastguard Worker
ListDirectory(const char * dir_name,vector<std::string> * entries) const291*8b6cd535SAndroid Build Coastguard Worker bool Filesystem::ListDirectory(const char* dir_name,
292*8b6cd535SAndroid Build Coastguard Worker vector<std::string>* entries) const {
293*8b6cd535SAndroid Build Coastguard Worker entries->clear();
294*8b6cd535SAndroid Build Coastguard Worker return ListDirectory(dir_name, /*exclude=*/{}, /*recursive=*/false, entries);
295*8b6cd535SAndroid Build Coastguard Worker }
296*8b6cd535SAndroid Build Coastguard Worker
ListDirectory(const char * dir_name,const std::unordered_set<std::string> & exclude,bool recursive,std::vector<std::string> * entries) const297*8b6cd535SAndroid Build Coastguard Worker bool Filesystem::ListDirectory(const char* dir_name,
298*8b6cd535SAndroid Build Coastguard Worker const std::unordered_set<std::string>& exclude,
299*8b6cd535SAndroid Build Coastguard Worker bool recursive,
300*8b6cd535SAndroid Build Coastguard Worker std::vector<std::string>* entries) const {
301*8b6cd535SAndroid Build Coastguard Worker return ListDirectoryInternal(dir_name, exclude, recursive, /*prefix=*/"",
302*8b6cd535SAndroid Build Coastguard Worker entries);
303*8b6cd535SAndroid Build Coastguard Worker }
304*8b6cd535SAndroid Build Coastguard Worker
GetMatchingFiles(const char * glob,vector<std::string> * matches) const305*8b6cd535SAndroid Build Coastguard Worker bool Filesystem::GetMatchingFiles(const char* glob,
306*8b6cd535SAndroid Build Coastguard Worker vector<std::string>* matches) const {
307*8b6cd535SAndroid Build Coastguard Worker matches->clear();
308*8b6cd535SAndroid Build Coastguard Worker
309*8b6cd535SAndroid Build Coastguard Worker // Split dirname/basename.
310*8b6cd535SAndroid Build Coastguard Worker int basename_idx = GetBasenameIndex(glob);
311*8b6cd535SAndroid Build Coastguard Worker if (basename_idx == 0) {
312*8b6cd535SAndroid Build Coastguard Worker // We need a directory.
313*8b6cd535SAndroid Build Coastguard Worker ICING_VLOG(1) << "Expected directory, no matching files for: " << glob;
314*8b6cd535SAndroid Build Coastguard Worker return true;
315*8b6cd535SAndroid Build Coastguard Worker }
316*8b6cd535SAndroid Build Coastguard Worker const char* basename_glob = glob + basename_idx;
317*8b6cd535SAndroid Build Coastguard Worker std::string dirname(glob, basename_idx);
318*8b6cd535SAndroid Build Coastguard Worker vector<std::string> entries;
319*8b6cd535SAndroid Build Coastguard Worker if (!ListDirectory(dirname.c_str(), &entries) && errno != ENOENT) {
320*8b6cd535SAndroid Build Coastguard Worker return false;
321*8b6cd535SAndroid Build Coastguard Worker }
322*8b6cd535SAndroid Build Coastguard Worker
323*8b6cd535SAndroid Build Coastguard Worker for (vector<std::string>::iterator i = entries.begin(); i != entries.end();
324*8b6cd535SAndroid Build Coastguard Worker ++i) {
325*8b6cd535SAndroid Build Coastguard Worker // The filename needs to match glob following last_slash.
326*8b6cd535SAndroid Build Coastguard Worker if (!fnmatch(basename_glob, i->c_str(), FNM_PATHNAME)) {
327*8b6cd535SAndroid Build Coastguard Worker // Add it to the list.
328*8b6cd535SAndroid Build Coastguard Worker matches->push_back(dirname + *i);
329*8b6cd535SAndroid Build Coastguard Worker }
330*8b6cd535SAndroid Build Coastguard Worker }
331*8b6cd535SAndroid Build Coastguard Worker return true;
332*8b6cd535SAndroid Build Coastguard Worker }
333*8b6cd535SAndroid Build Coastguard Worker
OpenForWrite(const char * file_name) const334*8b6cd535SAndroid Build Coastguard Worker int Filesystem::OpenForWrite(const char* file_name) const {
335*8b6cd535SAndroid Build Coastguard Worker int fd = open(file_name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
336*8b6cd535SAndroid Build Coastguard Worker if (fd < 0) {
337*8b6cd535SAndroid Build Coastguard Worker LogOpenError("Opening file ", file_name, " for write failed: ", errno);
338*8b6cd535SAndroid Build Coastguard Worker }
339*8b6cd535SAndroid Build Coastguard Worker return fd;
340*8b6cd535SAndroid Build Coastguard Worker }
341*8b6cd535SAndroid Build Coastguard Worker
OpenForAppend(const char * file_name) const342*8b6cd535SAndroid Build Coastguard Worker int Filesystem::OpenForAppend(const char* file_name) const {
343*8b6cd535SAndroid Build Coastguard Worker // Don't use the O_APPEND flag because, although it opens for
344*8b6cd535SAndroid Build Coastguard Worker // append, it doesn't set the file cursor to at the end until
345*8b6cd535SAndroid Build Coastguard Worker // first write occurs. This can be confusing if you expect
346*8b6cd535SAndroid Build Coastguard Worker // the file position at the end. Instead, explicitly
347*8b6cd535SAndroid Build Coastguard Worker // seek to end after opening.
348*8b6cd535SAndroid Build Coastguard Worker int fd = open(file_name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
349*8b6cd535SAndroid Build Coastguard Worker if (fd < 0) {
350*8b6cd535SAndroid Build Coastguard Worker LogOpenError("Opening file ", file_name, " for write failed: ", errno);
351*8b6cd535SAndroid Build Coastguard Worker } else {
352*8b6cd535SAndroid Build Coastguard Worker lseek(fd, 0, SEEK_END);
353*8b6cd535SAndroid Build Coastguard Worker }
354*8b6cd535SAndroid Build Coastguard Worker return fd;
355*8b6cd535SAndroid Build Coastguard Worker }
356*8b6cd535SAndroid Build Coastguard Worker
OpenForRead(const char * file_name) const357*8b6cd535SAndroid Build Coastguard Worker int Filesystem::OpenForRead(const char* file_name) const {
358*8b6cd535SAndroid Build Coastguard Worker int fd = open(file_name, O_RDONLY);
359*8b6cd535SAndroid Build Coastguard Worker if (fd < 0) {
360*8b6cd535SAndroid Build Coastguard Worker LogOpenError("Opening file ", file_name, " for read failed: ", errno);
361*8b6cd535SAndroid Build Coastguard Worker }
362*8b6cd535SAndroid Build Coastguard Worker return fd;
363*8b6cd535SAndroid Build Coastguard Worker }
364*8b6cd535SAndroid Build Coastguard Worker
GetFileSize(int fd) const365*8b6cd535SAndroid Build Coastguard Worker int64_t Filesystem::GetFileSize(int fd) const {
366*8b6cd535SAndroid Build Coastguard Worker struct stat st;
367*8b6cd535SAndroid Build Coastguard Worker if (fstat(fd, &st) < 0) {
368*8b6cd535SAndroid Build Coastguard Worker if (errno == ENOENT) {
369*8b6cd535SAndroid Build Coastguard Worker ICING_VLOG(1) << "Unable to stat file: " << strerror(errno);
370*8b6cd535SAndroid Build Coastguard Worker } else {
371*8b6cd535SAndroid Build Coastguard Worker ICING_LOG(WARNING) << "Unable to stat file: " << strerror(errno);
372*8b6cd535SAndroid Build Coastguard Worker }
373*8b6cd535SAndroid Build Coastguard Worker return kBadFileSize;
374*8b6cd535SAndroid Build Coastguard Worker }
375*8b6cd535SAndroid Build Coastguard Worker return st.st_size;
376*8b6cd535SAndroid Build Coastguard Worker }
377*8b6cd535SAndroid Build Coastguard Worker
GetFileSize(const char * filename) const378*8b6cd535SAndroid Build Coastguard Worker int64_t Filesystem::GetFileSize(const char* filename) const {
379*8b6cd535SAndroid Build Coastguard Worker struct stat st;
380*8b6cd535SAndroid Build Coastguard Worker if (stat(filename, &st) < 0) {
381*8b6cd535SAndroid Build Coastguard Worker if (errno == ENOENT) {
382*8b6cd535SAndroid Build Coastguard Worker ICING_VLOG(1) << "Unable to stat file " << filename << ": " << strerror(errno);
383*8b6cd535SAndroid Build Coastguard Worker } else {
384*8b6cd535SAndroid Build Coastguard Worker ICING_LOG(WARNING) << "Unable to stat file " << filename << ": " << strerror(errno);
385*8b6cd535SAndroid Build Coastguard Worker }
386*8b6cd535SAndroid Build Coastguard Worker return kBadFileSize;
387*8b6cd535SAndroid Build Coastguard Worker }
388*8b6cd535SAndroid Build Coastguard Worker return st.st_size;
389*8b6cd535SAndroid Build Coastguard Worker }
390*8b6cd535SAndroid Build Coastguard Worker
Truncate(int fd,int64_t new_size) const391*8b6cd535SAndroid Build Coastguard Worker bool Filesystem::Truncate(int fd, int64_t new_size) const {
392*8b6cd535SAndroid Build Coastguard Worker if (ftruncate(fd, new_size) != 0) {
393*8b6cd535SAndroid Build Coastguard Worker ICING_LOG(ERROR) << "Unable to truncate file: " << strerror(errno);
394*8b6cd535SAndroid Build Coastguard Worker return false;
395*8b6cd535SAndroid Build Coastguard Worker }
396*8b6cd535SAndroid Build Coastguard Worker lseek(fd, new_size, SEEK_SET);
397*8b6cd535SAndroid Build Coastguard Worker return true;
398*8b6cd535SAndroid Build Coastguard Worker }
399*8b6cd535SAndroid Build Coastguard Worker
Truncate(const char * filename,int64_t new_size) const400*8b6cd535SAndroid Build Coastguard Worker bool Filesystem::Truncate(const char* filename, int64_t new_size) const {
401*8b6cd535SAndroid Build Coastguard Worker int fd = OpenForAppend(filename);
402*8b6cd535SAndroid Build Coastguard Worker if (fd == -1) {
403*8b6cd535SAndroid Build Coastguard Worker return false;
404*8b6cd535SAndroid Build Coastguard Worker }
405*8b6cd535SAndroid Build Coastguard Worker bool success = Truncate(fd, new_size);
406*8b6cd535SAndroid Build Coastguard Worker close(fd);
407*8b6cd535SAndroid Build Coastguard Worker return success;
408*8b6cd535SAndroid Build Coastguard Worker }
409*8b6cd535SAndroid Build Coastguard Worker
Grow(int fd,int64_t new_size) const410*8b6cd535SAndroid Build Coastguard Worker bool Filesystem::Grow(int fd, int64_t new_size) const {
411*8b6cd535SAndroid Build Coastguard Worker if (ftruncate(fd, new_size) != 0) {
412*8b6cd535SAndroid Build Coastguard Worker ICING_LOG(ERROR) << "Unable to grow file: " << strerror(errno);
413*8b6cd535SAndroid Build Coastguard Worker return false;
414*8b6cd535SAndroid Build Coastguard Worker }
415*8b6cd535SAndroid Build Coastguard Worker
416*8b6cd535SAndroid Build Coastguard Worker return true;
417*8b6cd535SAndroid Build Coastguard Worker }
418*8b6cd535SAndroid Build Coastguard Worker
Grow(const char * filename,int64_t new_size) const419*8b6cd535SAndroid Build Coastguard Worker bool Filesystem::Grow(const char* filename, int64_t new_size) const {
420*8b6cd535SAndroid Build Coastguard Worker int fd = OpenForAppend(filename);
421*8b6cd535SAndroid Build Coastguard Worker if (fd == -1) {
422*8b6cd535SAndroid Build Coastguard Worker return false;
423*8b6cd535SAndroid Build Coastguard Worker }
424*8b6cd535SAndroid Build Coastguard Worker
425*8b6cd535SAndroid Build Coastguard Worker bool grew = Grow(fd, new_size);
426*8b6cd535SAndroid Build Coastguard Worker close(fd);
427*8b6cd535SAndroid Build Coastguard Worker return grew;
428*8b6cd535SAndroid Build Coastguard Worker }
429*8b6cd535SAndroid Build Coastguard Worker
Write(int fd,const void * data,size_t data_size) const430*8b6cd535SAndroid Build Coastguard Worker bool Filesystem::Write(int fd, const void* data, size_t data_size) const {
431*8b6cd535SAndroid Build Coastguard Worker size_t write_len = data_size;
432*8b6cd535SAndroid Build Coastguard Worker do {
433*8b6cd535SAndroid Build Coastguard Worker // Don't try to write too much at once.
434*8b6cd535SAndroid Build Coastguard Worker size_t chunk_size = std::min<size_t>(write_len, 64u * 1024);
435*8b6cd535SAndroid Build Coastguard Worker ssize_t wrote = write(fd, data, chunk_size);
436*8b6cd535SAndroid Build Coastguard Worker if (wrote < 0) {
437*8b6cd535SAndroid Build Coastguard Worker ICING_LOG(ERROR) << "Bad write: " << strerror(errno);
438*8b6cd535SAndroid Build Coastguard Worker return false;
439*8b6cd535SAndroid Build Coastguard Worker }
440*8b6cd535SAndroid Build Coastguard Worker data = static_cast<const uint8_t*>(data) + wrote;
441*8b6cd535SAndroid Build Coastguard Worker write_len -= wrote;
442*8b6cd535SAndroid Build Coastguard Worker } while (write_len > 0);
443*8b6cd535SAndroid Build Coastguard Worker return true;
444*8b6cd535SAndroid Build Coastguard Worker }
445*8b6cd535SAndroid Build Coastguard Worker
Write(const char * filename,const void * data,size_t data_size) const446*8b6cd535SAndroid Build Coastguard Worker bool Filesystem::Write(const char* filename, const void* data,
447*8b6cd535SAndroid Build Coastguard Worker size_t data_size) const {
448*8b6cd535SAndroid Build Coastguard Worker int fd = OpenForWrite(filename);
449*8b6cd535SAndroid Build Coastguard Worker if (fd == -1) {
450*8b6cd535SAndroid Build Coastguard Worker return false;
451*8b6cd535SAndroid Build Coastguard Worker }
452*8b6cd535SAndroid Build Coastguard Worker
453*8b6cd535SAndroid Build Coastguard Worker bool success = Write(fd, data, data_size);
454*8b6cd535SAndroid Build Coastguard Worker close(fd);
455*8b6cd535SAndroid Build Coastguard Worker return success;
456*8b6cd535SAndroid Build Coastguard Worker }
457*8b6cd535SAndroid Build Coastguard Worker
CopyFile(const char * src,const char * dst) const458*8b6cd535SAndroid Build Coastguard Worker bool Filesystem::CopyFile(const char* src, const char* dst) const {
459*8b6cd535SAndroid Build Coastguard Worker ScopedFd src_fd(OpenForRead(src));
460*8b6cd535SAndroid Build Coastguard Worker
461*8b6cd535SAndroid Build Coastguard Worker std::string dir = GetDirname(dst);
462*8b6cd535SAndroid Build Coastguard Worker if (!CreateDirectoryRecursively(dir.c_str())) {
463*8b6cd535SAndroid Build Coastguard Worker return false;
464*8b6cd535SAndroid Build Coastguard Worker }
465*8b6cd535SAndroid Build Coastguard Worker ScopedFd dst_fd(OpenForWrite(dst));
466*8b6cd535SAndroid Build Coastguard Worker
467*8b6cd535SAndroid Build Coastguard Worker if (!src_fd.is_valid() || !dst_fd.is_valid()) {
468*8b6cd535SAndroid Build Coastguard Worker return false;
469*8b6cd535SAndroid Build Coastguard Worker }
470*8b6cd535SAndroid Build Coastguard Worker uint64_t size = GetFileSize(*src_fd);
471*8b6cd535SAndroid Build Coastguard Worker std::unique_ptr<uint8_t[]> buf = std::make_unique<uint8_t[]>(size);
472*8b6cd535SAndroid Build Coastguard Worker if (!Read(*src_fd, buf.get(), size)) {
473*8b6cd535SAndroid Build Coastguard Worker return false;
474*8b6cd535SAndroid Build Coastguard Worker }
475*8b6cd535SAndroid Build Coastguard Worker return Write(*dst_fd, buf.get(), size);
476*8b6cd535SAndroid Build Coastguard Worker }
477*8b6cd535SAndroid Build Coastguard Worker
CopyDirectory(const char * src_dir,const char * dst_dir,bool recursive) const478*8b6cd535SAndroid Build Coastguard Worker bool Filesystem::CopyDirectory(const char* src_dir, const char* dst_dir,
479*8b6cd535SAndroid Build Coastguard Worker bool recursive) const {
480*8b6cd535SAndroid Build Coastguard Worker DIR* dir = opendir(src_dir);
481*8b6cd535SAndroid Build Coastguard Worker if (!dir) {
482*8b6cd535SAndroid Build Coastguard Worker LogOpenError("Unable to open directory ", src_dir, ": ", errno);
483*8b6cd535SAndroid Build Coastguard Worker return false;
484*8b6cd535SAndroid Build Coastguard Worker }
485*8b6cd535SAndroid Build Coastguard Worker
486*8b6cd535SAndroid Build Coastguard Worker dirent* p;
487*8b6cd535SAndroid Build Coastguard Worker // readdir's implementation seems to be thread safe.
488*8b6cd535SAndroid Build Coastguard Worker while ((p = readdir(dir)) != nullptr) {
489*8b6cd535SAndroid Build Coastguard Worker std::string file_name(p->d_name);
490*8b6cd535SAndroid Build Coastguard Worker if (file_name == "." || file_name == "..") {
491*8b6cd535SAndroid Build Coastguard Worker continue;
492*8b6cd535SAndroid Build Coastguard Worker }
493*8b6cd535SAndroid Build Coastguard Worker
494*8b6cd535SAndroid Build Coastguard Worker std::string full_src_path = absl_ports::StrCat(src_dir, "/", p->d_name);
495*8b6cd535SAndroid Build Coastguard Worker std::string full_dst_path = absl_ports::StrCat(dst_dir, "/", p->d_name);
496*8b6cd535SAndroid Build Coastguard Worker
497*8b6cd535SAndroid Build Coastguard Worker // Directories are copied when writing a non-directory file, so no
498*8b6cd535SAndroid Build Coastguard Worker // explicit copying of a directory is required.
499*8b6cd535SAndroid Build Coastguard Worker if (p->d_type != DT_DIR) {
500*8b6cd535SAndroid Build Coastguard Worker if (!CopyFile(full_src_path.c_str(), full_dst_path.c_str())) {
501*8b6cd535SAndroid Build Coastguard Worker return false;
502*8b6cd535SAndroid Build Coastguard Worker }
503*8b6cd535SAndroid Build Coastguard Worker }
504*8b6cd535SAndroid Build Coastguard Worker
505*8b6cd535SAndroid Build Coastguard Worker // Recurse down directories, if requested.
506*8b6cd535SAndroid Build Coastguard Worker if (recursive && (p->d_type == DT_DIR)) {
507*8b6cd535SAndroid Build Coastguard Worker std::string src_sub_dir = absl_ports::StrCat(src_dir, "/", p->d_name);
508*8b6cd535SAndroid Build Coastguard Worker std::string dst_sub_dir = absl_ports::StrCat(dst_dir, "/", p->d_name);
509*8b6cd535SAndroid Build Coastguard Worker if (!CopyDirectory(src_sub_dir.c_str(), dst_sub_dir.c_str(), recursive)) {
510*8b6cd535SAndroid Build Coastguard Worker return false;
511*8b6cd535SAndroid Build Coastguard Worker }
512*8b6cd535SAndroid Build Coastguard Worker }
513*8b6cd535SAndroid Build Coastguard Worker }
514*8b6cd535SAndroid Build Coastguard Worker if (closedir(dir) != 0) {
515*8b6cd535SAndroid Build Coastguard Worker ICING_LOG(ERROR) << "Error closing " << src_dir << ": " << strerror(errno);
516*8b6cd535SAndroid Build Coastguard Worker }
517*8b6cd535SAndroid Build Coastguard Worker return true;
518*8b6cd535SAndroid Build Coastguard Worker }
519*8b6cd535SAndroid Build Coastguard Worker
PWrite(int fd,off_t offset,const void * data,size_t data_size) const520*8b6cd535SAndroid Build Coastguard Worker bool Filesystem::PWrite(int fd, off_t offset, const void* data,
521*8b6cd535SAndroid Build Coastguard Worker size_t data_size) const {
522*8b6cd535SAndroid Build Coastguard Worker size_t write_len = data_size;
523*8b6cd535SAndroid Build Coastguard Worker do {
524*8b6cd535SAndroid Build Coastguard Worker // Don't try to write too much at once.
525*8b6cd535SAndroid Build Coastguard Worker size_t chunk_size = std::min<size_t>(write_len, 64u * 1024);
526*8b6cd535SAndroid Build Coastguard Worker ssize_t wrote = pwrite(fd, data, chunk_size, offset);
527*8b6cd535SAndroid Build Coastguard Worker if (wrote < 0) {
528*8b6cd535SAndroid Build Coastguard Worker ICING_LOG(ERROR) << "Bad write: " << strerror(errno);
529*8b6cd535SAndroid Build Coastguard Worker return false;
530*8b6cd535SAndroid Build Coastguard Worker }
531*8b6cd535SAndroid Build Coastguard Worker data = static_cast<const uint8_t*>(data) + wrote;
532*8b6cd535SAndroid Build Coastguard Worker write_len -= wrote;
533*8b6cd535SAndroid Build Coastguard Worker offset += wrote;
534*8b6cd535SAndroid Build Coastguard Worker } while (write_len > 0);
535*8b6cd535SAndroid Build Coastguard Worker return true;
536*8b6cd535SAndroid Build Coastguard Worker }
537*8b6cd535SAndroid Build Coastguard Worker
PWrite(const char * filename,off_t offset,const void * data,size_t data_size) const538*8b6cd535SAndroid Build Coastguard Worker bool Filesystem::PWrite(const char* filename, off_t offset, const void* data,
539*8b6cd535SAndroid Build Coastguard Worker size_t data_size) const {
540*8b6cd535SAndroid Build Coastguard Worker int fd = OpenForWrite(filename);
541*8b6cd535SAndroid Build Coastguard Worker if (fd == -1) {
542*8b6cd535SAndroid Build Coastguard Worker return false;
543*8b6cd535SAndroid Build Coastguard Worker }
544*8b6cd535SAndroid Build Coastguard Worker
545*8b6cd535SAndroid Build Coastguard Worker bool success = PWrite(fd, offset, data, data_size);
546*8b6cd535SAndroid Build Coastguard Worker close(fd);
547*8b6cd535SAndroid Build Coastguard Worker return success;
548*8b6cd535SAndroid Build Coastguard Worker }
549*8b6cd535SAndroid Build Coastguard Worker
Read(int fd,void * buf,size_t buf_size) const550*8b6cd535SAndroid Build Coastguard Worker bool Filesystem::Read(int fd, void* buf, size_t buf_size) const {
551*8b6cd535SAndroid Build Coastguard Worker ssize_t read_status = read(fd, buf, buf_size);
552*8b6cd535SAndroid Build Coastguard Worker if (read_status < 0) {
553*8b6cd535SAndroid Build Coastguard Worker ICING_LOG(ERROR) << "Bad read: " << strerror(errno);
554*8b6cd535SAndroid Build Coastguard Worker return false;
555*8b6cd535SAndroid Build Coastguard Worker }
556*8b6cd535SAndroid Build Coastguard Worker return true;
557*8b6cd535SAndroid Build Coastguard Worker }
558*8b6cd535SAndroid Build Coastguard Worker
Read(const char * filename,void * buf,size_t buf_size) const559*8b6cd535SAndroid Build Coastguard Worker bool Filesystem::Read(const char* filename, void* buf, size_t buf_size) const {
560*8b6cd535SAndroid Build Coastguard Worker int fd = OpenForRead(filename);
561*8b6cd535SAndroid Build Coastguard Worker if (fd == -1) {
562*8b6cd535SAndroid Build Coastguard Worker return false;
563*8b6cd535SAndroid Build Coastguard Worker }
564*8b6cd535SAndroid Build Coastguard Worker
565*8b6cd535SAndroid Build Coastguard Worker bool success = Read(fd, buf, buf_size);
566*8b6cd535SAndroid Build Coastguard Worker close(fd);
567*8b6cd535SAndroid Build Coastguard Worker return success;
568*8b6cd535SAndroid Build Coastguard Worker }
569*8b6cd535SAndroid Build Coastguard Worker
PRead(int fd,void * buf,size_t buf_size,off_t offset) const570*8b6cd535SAndroid Build Coastguard Worker bool Filesystem::PRead(int fd, void* buf, size_t buf_size, off_t offset) const {
571*8b6cd535SAndroid Build Coastguard Worker ssize_t read_status = pread(fd, buf, buf_size, offset);
572*8b6cd535SAndroid Build Coastguard Worker if (read_status < 0) {
573*8b6cd535SAndroid Build Coastguard Worker ICING_LOG(ERROR) << "Bad read: " << strerror(errno);
574*8b6cd535SAndroid Build Coastguard Worker return false;
575*8b6cd535SAndroid Build Coastguard Worker }
576*8b6cd535SAndroid Build Coastguard Worker return true;
577*8b6cd535SAndroid Build Coastguard Worker }
578*8b6cd535SAndroid Build Coastguard Worker
PRead(const char * filename,void * buf,size_t buf_size,off_t offset) const579*8b6cd535SAndroid Build Coastguard Worker bool Filesystem::PRead(const char* filename, void* buf, size_t buf_size,
580*8b6cd535SAndroid Build Coastguard Worker off_t offset) const {
581*8b6cd535SAndroid Build Coastguard Worker int fd = OpenForRead(filename);
582*8b6cd535SAndroid Build Coastguard Worker if (fd == -1) {
583*8b6cd535SAndroid Build Coastguard Worker return false;
584*8b6cd535SAndroid Build Coastguard Worker }
585*8b6cd535SAndroid Build Coastguard Worker
586*8b6cd535SAndroid Build Coastguard Worker bool success = PRead(fd, buf, buf_size, offset);
587*8b6cd535SAndroid Build Coastguard Worker close(fd);
588*8b6cd535SAndroid Build Coastguard Worker return success;
589*8b6cd535SAndroid Build Coastguard Worker }
590*8b6cd535SAndroid Build Coastguard Worker
DataSync(int fd) const591*8b6cd535SAndroid Build Coastguard Worker bool Filesystem::DataSync(int fd) const {
592*8b6cd535SAndroid Build Coastguard Worker #ifdef __APPLE__ // iOS has no fdatasync(), only fsync()
593*8b6cd535SAndroid Build Coastguard Worker int result = fsync(fd);
594*8b6cd535SAndroid Build Coastguard Worker #else
595*8b6cd535SAndroid Build Coastguard Worker int result = fdatasync(fd);
596*8b6cd535SAndroid Build Coastguard Worker #endif
597*8b6cd535SAndroid Build Coastguard Worker
598*8b6cd535SAndroid Build Coastguard Worker if (result < 0) {
599*8b6cd535SAndroid Build Coastguard Worker ICING_LOG(ERROR) << "Unable to sync data: " << strerror(errno);
600*8b6cd535SAndroid Build Coastguard Worker return false;
601*8b6cd535SAndroid Build Coastguard Worker }
602*8b6cd535SAndroid Build Coastguard Worker return true;
603*8b6cd535SAndroid Build Coastguard Worker }
604*8b6cd535SAndroid Build Coastguard Worker
RenameFile(const char * old_name,const char * new_name) const605*8b6cd535SAndroid Build Coastguard Worker bool Filesystem::RenameFile(const char* old_name, const char* new_name) const {
606*8b6cd535SAndroid Build Coastguard Worker if (rename(old_name, new_name) < 0) {
607*8b6cd535SAndroid Build Coastguard Worker ICING_LOG(ERROR) << "Unable to rename file " << old_name << " to " << new_name << ": " << strerror(errno);
608*8b6cd535SAndroid Build Coastguard Worker return false;
609*8b6cd535SAndroid Build Coastguard Worker }
610*8b6cd535SAndroid Build Coastguard Worker return true;
611*8b6cd535SAndroid Build Coastguard Worker }
612*8b6cd535SAndroid Build Coastguard Worker
SwapFiles(const char * one,const char * two) const613*8b6cd535SAndroid Build Coastguard Worker bool Filesystem::SwapFiles(const char* one, const char* two) const {
614*8b6cd535SAndroid Build Coastguard Worker std::string tmp_name = absl_ports::StrCat(one, ".tmp");
615*8b6cd535SAndroid Build Coastguard Worker const char* tmp_cstr = tmp_name.c_str();
616*8b6cd535SAndroid Build Coastguard Worker
617*8b6cd535SAndroid Build Coastguard Worker // Blow away a tmp file if it already exists
618*8b6cd535SAndroid Build Coastguard Worker if (FileExists(tmp_cstr) && !DeleteFile(tmp_cstr)) {
619*8b6cd535SAndroid Build Coastguard Worker return false;
620*8b6cd535SAndroid Build Coastguard Worker }
621*8b6cd535SAndroid Build Coastguard Worker if (DirectoryExists(tmp_cstr) && !DeleteDirectoryRecursively(tmp_cstr)) {
622*8b6cd535SAndroid Build Coastguard Worker return false;
623*8b6cd535SAndroid Build Coastguard Worker }
624*8b6cd535SAndroid Build Coastguard Worker
625*8b6cd535SAndroid Build Coastguard Worker // Perform the swap
626*8b6cd535SAndroid Build Coastguard Worker if (!RenameFile(one, tmp_cstr)) {
627*8b6cd535SAndroid Build Coastguard Worker return false;
628*8b6cd535SAndroid Build Coastguard Worker }
629*8b6cd535SAndroid Build Coastguard Worker if (!RenameFile(two, one)) {
630*8b6cd535SAndroid Build Coastguard Worker return false;
631*8b6cd535SAndroid Build Coastguard Worker }
632*8b6cd535SAndroid Build Coastguard Worker if (!RenameFile(tmp_cstr, two)) {
633*8b6cd535SAndroid Build Coastguard Worker return false;
634*8b6cd535SAndroid Build Coastguard Worker }
635*8b6cd535SAndroid Build Coastguard Worker
636*8b6cd535SAndroid Build Coastguard Worker return true;
637*8b6cd535SAndroid Build Coastguard Worker }
638*8b6cd535SAndroid Build Coastguard Worker
CreateDirectory(const char * dir_name) const639*8b6cd535SAndroid Build Coastguard Worker bool Filesystem::CreateDirectory(const char* dir_name) const {
640*8b6cd535SAndroid Build Coastguard Worker bool success = DirectoryExists(dir_name);
641*8b6cd535SAndroid Build Coastguard Worker if (!success) {
642*8b6cd535SAndroid Build Coastguard Worker if (mkdir(dir_name, S_IRUSR | S_IWUSR | S_IXUSR) == 0) {
643*8b6cd535SAndroid Build Coastguard Worker success = true;
644*8b6cd535SAndroid Build Coastguard Worker } else {
645*8b6cd535SAndroid Build Coastguard Worker ICING_LOG(ERROR) << "Creating directory " << dir_name << " failed: " << strerror(errno);
646*8b6cd535SAndroid Build Coastguard Worker }
647*8b6cd535SAndroid Build Coastguard Worker }
648*8b6cd535SAndroid Build Coastguard Worker return success;
649*8b6cd535SAndroid Build Coastguard Worker }
650*8b6cd535SAndroid Build Coastguard Worker
CreateDirectoryRecursively(const char * dir_name) const651*8b6cd535SAndroid Build Coastguard Worker bool Filesystem::CreateDirectoryRecursively(const char* dir_name) const {
652*8b6cd535SAndroid Build Coastguard Worker if ((strlen(dir_name) == 0) || DirectoryExists(dir_name)) {
653*8b6cd535SAndroid Build Coastguard Worker return true;
654*8b6cd535SAndroid Build Coastguard Worker }
655*8b6cd535SAndroid Build Coastguard Worker std::string path_before = GetDirname(dir_name);
656*8b6cd535SAndroid Build Coastguard Worker if (!CreateDirectoryRecursively(path_before.c_str())) {
657*8b6cd535SAndroid Build Coastguard Worker return false;
658*8b6cd535SAndroid Build Coastguard Worker }
659*8b6cd535SAndroid Build Coastguard Worker return CreateDirectory(dir_name);
660*8b6cd535SAndroid Build Coastguard Worker }
661*8b6cd535SAndroid Build Coastguard Worker
GetDiskUsage(int fd) const662*8b6cd535SAndroid Build Coastguard Worker int64_t Filesystem::GetDiskUsage(int fd) const {
663*8b6cd535SAndroid Build Coastguard Worker struct stat st;
664*8b6cd535SAndroid Build Coastguard Worker if (fstat(fd, &st) < 0) {
665*8b6cd535SAndroid Build Coastguard Worker ICING_LOG(ERROR) << "Unable to stat file: " << strerror(errno);
666*8b6cd535SAndroid Build Coastguard Worker return kBadFileSize;
667*8b6cd535SAndroid Build Coastguard Worker }
668*8b6cd535SAndroid Build Coastguard Worker return st.st_blocks * kStatBlockSize;
669*8b6cd535SAndroid Build Coastguard Worker }
670*8b6cd535SAndroid Build Coastguard Worker
GetFileDiskUsage(const char * path) const671*8b6cd535SAndroid Build Coastguard Worker int64_t Filesystem::GetFileDiskUsage(const char* path) const {
672*8b6cd535SAndroid Build Coastguard Worker struct stat st;
673*8b6cd535SAndroid Build Coastguard Worker if (stat(path, &st) != 0) {
674*8b6cd535SAndroid Build Coastguard Worker ICING_LOG(ERROR) << "Unable to stat " << path << ": " << strerror(errno);
675*8b6cd535SAndroid Build Coastguard Worker return kBadFileSize;
676*8b6cd535SAndroid Build Coastguard Worker }
677*8b6cd535SAndroid Build Coastguard Worker return st.st_blocks * kStatBlockSize;
678*8b6cd535SAndroid Build Coastguard Worker }
679*8b6cd535SAndroid Build Coastguard Worker
GetDiskUsage(const char * path) const680*8b6cd535SAndroid Build Coastguard Worker int64_t Filesystem::GetDiskUsage(const char* path) const {
681*8b6cd535SAndroid Build Coastguard Worker struct stat st;
682*8b6cd535SAndroid Build Coastguard Worker if (stat(path, &st) != 0) {
683*8b6cd535SAndroid Build Coastguard Worker ICING_LOG(ERROR) << "Unable to stat " << path << ": " << strerror(errno);
684*8b6cd535SAndroid Build Coastguard Worker return kBadFileSize;
685*8b6cd535SAndroid Build Coastguard Worker }
686*8b6cd535SAndroid Build Coastguard Worker int64_t result = st.st_blocks * kStatBlockSize;
687*8b6cd535SAndroid Build Coastguard Worker if (S_ISDIR(st.st_mode)) {
688*8b6cd535SAndroid Build Coastguard Worker vector<std::string> list;
689*8b6cd535SAndroid Build Coastguard Worker if (!ListDirectory(path, &list)) {
690*8b6cd535SAndroid Build Coastguard Worker return kBadFileSize;
691*8b6cd535SAndroid Build Coastguard Worker }
692*8b6cd535SAndroid Build Coastguard Worker for (vector<std::string>::iterator i = list.begin(); i != list.end(); ++i) {
693*8b6cd535SAndroid Build Coastguard Worker std::string sub_path = std::string(path) + '/' + *i;
694*8b6cd535SAndroid Build Coastguard Worker uint64_t sub_usage = GetDiskUsage(sub_path.c_str());
695*8b6cd535SAndroid Build Coastguard Worker if (sub_usage != kBadFileSize) {
696*8b6cd535SAndroid Build Coastguard Worker result += sub_usage;
697*8b6cd535SAndroid Build Coastguard Worker } // Else just ignore the failing entry.
698*8b6cd535SAndroid Build Coastguard Worker }
699*8b6cd535SAndroid Build Coastguard Worker }
700*8b6cd535SAndroid Build Coastguard Worker return result;
701*8b6cd535SAndroid Build Coastguard Worker }
702*8b6cd535SAndroid Build Coastguard Worker
GetCurrentPosition(int fd) const703*8b6cd535SAndroid Build Coastguard Worker int64_t Filesystem::GetCurrentPosition(int fd) const {
704*8b6cd535SAndroid Build Coastguard Worker return lseek(fd, 0, SEEK_CUR);
705*8b6cd535SAndroid Build Coastguard Worker }
706*8b6cd535SAndroid Build Coastguard Worker
SetPosition(int fd,int offset) const707*8b6cd535SAndroid Build Coastguard Worker int64_t Filesystem::SetPosition(int fd, int offset) const {
708*8b6cd535SAndroid Build Coastguard Worker return lseek(fd, offset, SEEK_SET);
709*8b6cd535SAndroid Build Coastguard Worker }
710*8b6cd535SAndroid Build Coastguard Worker
IncrementByOrSetInvalid(int64_t size,int64_t * to_increment)711*8b6cd535SAndroid Build Coastguard Worker void Filesystem::IncrementByOrSetInvalid(int64_t size, int64_t* to_increment) {
712*8b6cd535SAndroid Build Coastguard Worker if (*to_increment == kBadFileSize) {
713*8b6cd535SAndroid Build Coastguard Worker return;
714*8b6cd535SAndroid Build Coastguard Worker }
715*8b6cd535SAndroid Build Coastguard Worker if (size == kBadFileSize) {
716*8b6cd535SAndroid Build Coastguard Worker *to_increment = kBadFileSize;
717*8b6cd535SAndroid Build Coastguard Worker return;
718*8b6cd535SAndroid Build Coastguard Worker }
719*8b6cd535SAndroid Build Coastguard Worker *to_increment += size;
720*8b6cd535SAndroid Build Coastguard Worker }
721*8b6cd535SAndroid Build Coastguard Worker
722*8b6cd535SAndroid Build Coastguard Worker } // namespace lib
723*8b6cd535SAndroid Build Coastguard Worker } // namespace icing
724