1*1a96fba6SXin Li // Copyright 2014 The Chromium OS Authors. All rights reserved.
2*1a96fba6SXin Li // Use of this source code is governed by a BSD-style license that can be
3*1a96fba6SXin Li // found in the LICENSE file.
4*1a96fba6SXin Li
5*1a96fba6SXin Li #include "brillo/file_utils.h"
6*1a96fba6SXin Li
7*1a96fba6SXin Li #include <fcntl.h>
8*1a96fba6SXin Li #include <unistd.h>
9*1a96fba6SXin Li
10*1a96fba6SXin Li #include <limits>
11*1a96fba6SXin Li #include <utility>
12*1a96fba6SXin Li #include <vector>
13*1a96fba6SXin Li
14*1a96fba6SXin Li #include <base/files/file_enumerator.h>
15*1a96fba6SXin Li #include <base/files/file_path.h>
16*1a96fba6SXin Li #include <base/files/file_util.h>
17*1a96fba6SXin Li #include <base/logging.h>
18*1a96fba6SXin Li #include <base/posix/eintr_wrapper.h>
19*1a96fba6SXin Li #include <base/rand_util.h>
20*1a96fba6SXin Li #include <base/stl_util.h>
21*1a96fba6SXin Li #include <base/strings/string_number_conversions.h>
22*1a96fba6SXin Li #include <base/strings/stringprintf.h>
23*1a96fba6SXin Li #include <base/time/time.h>
24*1a96fba6SXin Li
25*1a96fba6SXin Li namespace brillo {
26*1a96fba6SXin Li
27*1a96fba6SXin Li namespace {
28*1a96fba6SXin Li
29*1a96fba6SXin Li // Log sync(), fsync(), etc. calls that take this many seconds or longer.
30*1a96fba6SXin Li constexpr const base::TimeDelta kLongSync = base::TimeDelta::FromSeconds(10);
31*1a96fba6SXin Li
32*1a96fba6SXin Li enum {
33*1a96fba6SXin Li kPermissions600 = S_IRUSR | S_IWUSR,
34*1a96fba6SXin Li kPermissions777 = S_IRWXU | S_IRWXG | S_IRWXO,
35*1a96fba6SXin Li kPermissions755 = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH
36*1a96fba6SXin Li };
37*1a96fba6SXin Li
38*1a96fba6SXin Li // Verify that base file permission enums are compatible with S_Ixxx. If these
39*1a96fba6SXin Li // asserts ever fail, we'll need to ensure that users of these functions switch
40*1a96fba6SXin Li // away from using base permission enums and add a note to the function comments
41*1a96fba6SXin Li // indicating that base enums can not be used.
42*1a96fba6SXin Li static_assert(base::FILE_PERMISSION_READ_BY_USER == S_IRUSR,
43*1a96fba6SXin Li "base file permissions don't match unistd.h permissions");
44*1a96fba6SXin Li static_assert(base::FILE_PERMISSION_WRITE_BY_USER == S_IWUSR,
45*1a96fba6SXin Li "base file permissions don't match unistd.h permissions");
46*1a96fba6SXin Li static_assert(base::FILE_PERMISSION_EXECUTE_BY_USER == S_IXUSR,
47*1a96fba6SXin Li "base file permissions don't match unistd.h permissions");
48*1a96fba6SXin Li static_assert(base::FILE_PERMISSION_READ_BY_GROUP == S_IRGRP,
49*1a96fba6SXin Li "base file permissions don't match unistd.h permissions");
50*1a96fba6SXin Li static_assert(base::FILE_PERMISSION_WRITE_BY_GROUP == S_IWGRP,
51*1a96fba6SXin Li "base file permissions don't match unistd.h permissions");
52*1a96fba6SXin Li static_assert(base::FILE_PERMISSION_EXECUTE_BY_GROUP == S_IXGRP,
53*1a96fba6SXin Li "base file permissions don't match unistd.h permissions");
54*1a96fba6SXin Li static_assert(base::FILE_PERMISSION_READ_BY_OTHERS == S_IROTH,
55*1a96fba6SXin Li "base file permissions don't match unistd.h permissions");
56*1a96fba6SXin Li static_assert(base::FILE_PERMISSION_WRITE_BY_OTHERS == S_IWOTH,
57*1a96fba6SXin Li "base file permissions don't match unistd.h permissions");
58*1a96fba6SXin Li static_assert(base::FILE_PERMISSION_EXECUTE_BY_OTHERS == S_IXOTH,
59*1a96fba6SXin Li "base file permissions don't match unistd.h permissions");
60*1a96fba6SXin Li
61*1a96fba6SXin Li enum RegularFileOrDeleteResult {
62*1a96fba6SXin Li kFailure = 0, // Failed to delete whatever was at the path.
63*1a96fba6SXin Li kRegularFile = 1, // Regular file existed and was unchanged.
64*1a96fba6SXin Li kEmpty = 2 // Anything that was at the path has been deleted.
65*1a96fba6SXin Li };
66*1a96fba6SXin Li
67*1a96fba6SXin Li // Checks if a regular file owned by |uid| and |gid| exists at |path|, otherwise
68*1a96fba6SXin Li // deletes anything that might be at |path|. Returns a RegularFileOrDeleteResult
69*1a96fba6SXin Li // enum indicating what is at |path| after the function finishes.
RegularFileOrDelete(const base::FilePath & path,uid_t uid,gid_t gid)70*1a96fba6SXin Li RegularFileOrDeleteResult RegularFileOrDelete(const base::FilePath& path,
71*1a96fba6SXin Li uid_t uid,
72*1a96fba6SXin Li gid_t gid) {
73*1a96fba6SXin Li // Check for symlinks by setting O_NOFOLLOW and checking for ELOOP. This lets
74*1a96fba6SXin Li // us use the safer fstat() instead of having to use lstat().
75*1a96fba6SXin Li base::ScopedFD scoped_fd(HANDLE_EINTR(openat(
76*1a96fba6SXin Li AT_FDCWD, path.value().c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW)));
77*1a96fba6SXin Li bool path_not_empty = (errno == ELOOP || scoped_fd != -1);
78*1a96fba6SXin Li
79*1a96fba6SXin Li // If there is a file/directory at |path|, see if it matches our criteria.
80*1a96fba6SXin Li if (scoped_fd != -1) {
81*1a96fba6SXin Li struct stat file_stat;
82*1a96fba6SXin Li if (fstat(scoped_fd.get(), &file_stat) != -1 &&
83*1a96fba6SXin Li S_ISREG(file_stat.st_mode) && file_stat.st_uid == uid &&
84*1a96fba6SXin Li file_stat.st_gid == gid) {
85*1a96fba6SXin Li return kRegularFile;
86*1a96fba6SXin Li }
87*1a96fba6SXin Li }
88*1a96fba6SXin Li
89*1a96fba6SXin Li // If we get here and anything was at |path|, try to delete it so we can put
90*1a96fba6SXin Li // our file there.
91*1a96fba6SXin Li if (path_not_empty) {
92*1a96fba6SXin Li if (!base::DeleteFile(path, true)) {
93*1a96fba6SXin Li PLOG(WARNING) << "Failed to delete entity at \"" << path.value() << '"';
94*1a96fba6SXin Li return kFailure;
95*1a96fba6SXin Li }
96*1a96fba6SXin Li }
97*1a96fba6SXin Li
98*1a96fba6SXin Li return kEmpty;
99*1a96fba6SXin Li }
100*1a96fba6SXin Li
101*1a96fba6SXin Li // Handles common touch functionality but also provides an optional |fd_out|
102*1a96fba6SXin Li // so that any further modifications to the file (e.g. permissions) can safely
103*1a96fba6SXin Li // use the fd rather than the path. |fd_out| will only be set if a new file
104*1a96fba6SXin Li // is created, otherwise it will be unchanged.
105*1a96fba6SXin Li // If |fd_out| is null, this function will close the file, otherwise it's
106*1a96fba6SXin Li // expected that |fd_out| will close the file when it goes out of scope.
TouchFileInternal(const base::FilePath & path,uid_t uid,gid_t gid,base::ScopedFD * fd_out)107*1a96fba6SXin Li bool TouchFileInternal(const base::FilePath& path,
108*1a96fba6SXin Li uid_t uid,
109*1a96fba6SXin Li gid_t gid,
110*1a96fba6SXin Li base::ScopedFD* fd_out) {
111*1a96fba6SXin Li RegularFileOrDeleteResult result = RegularFileOrDelete(path, uid, gid);
112*1a96fba6SXin Li switch (result) {
113*1a96fba6SXin Li case kFailure:
114*1a96fba6SXin Li return false;
115*1a96fba6SXin Li case kRegularFile:
116*1a96fba6SXin Li return true;
117*1a96fba6SXin Li case kEmpty:
118*1a96fba6SXin Li break;
119*1a96fba6SXin Li }
120*1a96fba6SXin Li
121*1a96fba6SXin Li // base::CreateDirectory() returns true if the directory already existed.
122*1a96fba6SXin Li if (!base::CreateDirectory(path.DirName())) {
123*1a96fba6SXin Li PLOG(WARNING) << "Failed to create directory for \"" << path.value() << '"';
124*1a96fba6SXin Li return false;
125*1a96fba6SXin Li }
126*1a96fba6SXin Li
127*1a96fba6SXin Li // Create the file as owner-only initially.
128*1a96fba6SXin Li base::ScopedFD scoped_fd(HANDLE_EINTR(openat(
129*1a96fba6SXin Li AT_FDCWD, path.value().c_str(),
130*1a96fba6SXin Li O_RDONLY | O_NOFOLLOW | O_CREAT | O_EXCL | O_CLOEXEC, kPermissions600)));
131*1a96fba6SXin Li if (scoped_fd == -1) {
132*1a96fba6SXin Li PLOG(WARNING) << "Failed to create file \"" << path.value() << '"';
133*1a96fba6SXin Li return false;
134*1a96fba6SXin Li }
135*1a96fba6SXin Li
136*1a96fba6SXin Li if (fd_out) {
137*1a96fba6SXin Li fd_out->swap(scoped_fd);
138*1a96fba6SXin Li }
139*1a96fba6SXin Li return true;
140*1a96fba6SXin Li }
141*1a96fba6SXin Li
GetRandomSuffix()142*1a96fba6SXin Li std::string GetRandomSuffix() {
143*1a96fba6SXin Li const int kBufferSize = 6;
144*1a96fba6SXin Li unsigned char buffer[kBufferSize];
145*1a96fba6SXin Li base::RandBytes(buffer, base::size(buffer));
146*1a96fba6SXin Li std::string suffix;
147*1a96fba6SXin Li for (int i = 0; i < kBufferSize; ++i) {
148*1a96fba6SXin Li int random_value = buffer[i] % (2 * 26 + 10);
149*1a96fba6SXin Li if (random_value < 26) {
150*1a96fba6SXin Li suffix.push_back('a' + random_value);
151*1a96fba6SXin Li } else if (random_value < 2 * 26) {
152*1a96fba6SXin Li suffix.push_back('A' + random_value - 26);
153*1a96fba6SXin Li } else {
154*1a96fba6SXin Li suffix.push_back('0' + random_value - 2 * 26);
155*1a96fba6SXin Li }
156*1a96fba6SXin Li }
157*1a96fba6SXin Li return suffix;
158*1a96fba6SXin Li }
159*1a96fba6SXin Li
OpenPathComponentInternal(int parent_fd,const std::string & file,int flags,mode_t mode)160*1a96fba6SXin Li base::ScopedFD OpenPathComponentInternal(int parent_fd,
161*1a96fba6SXin Li const std::string& file,
162*1a96fba6SXin Li int flags,
163*1a96fba6SXin Li mode_t mode) {
164*1a96fba6SXin Li DCHECK(file == "/" || file.find("/") == std::string::npos);
165*1a96fba6SXin Li base::ScopedFD fd;
166*1a96fba6SXin Li
167*1a96fba6SXin Li // O_NONBLOCK is used to avoid hanging on edge cases (e.g. a serial port with
168*1a96fba6SXin Li // flow control, or a FIFO without a writer).
169*1a96fba6SXin Li if (parent_fd >= 0 || parent_fd == AT_FDCWD) {
170*1a96fba6SXin Li fd.reset(HANDLE_EINTR(openat(parent_fd, file.c_str(),
171*1a96fba6SXin Li flags | O_NONBLOCK | O_NOFOLLOW | O_CLOEXEC,
172*1a96fba6SXin Li mode)));
173*1a96fba6SXin Li } else if (file == "/") {
174*1a96fba6SXin Li fd.reset(HANDLE_EINTR(open(
175*1a96fba6SXin Li file.c_str(),
176*1a96fba6SXin Li flags | O_RDONLY | O_DIRECTORY | O_NONBLOCK | O_NOFOLLOW | O_CLOEXEC,
177*1a96fba6SXin Li mode)));
178*1a96fba6SXin Li }
179*1a96fba6SXin Li
180*1a96fba6SXin Li if (!fd.is_valid()) {
181*1a96fba6SXin Li // open(2) fails with ELOOP when the last component of the |path| is a
182*1a96fba6SXin Li // symlink. It fails with ENXIO when |path| is a FIFO and |flags| is for
183*1a96fba6SXin Li // writing because of the O_NONBLOCK flag added above.
184*1a96fba6SXin Li if (errno == ELOOP || errno == ENXIO) {
185*1a96fba6SXin Li PLOG(WARNING) << "Failed to open " << file << " safely.";
186*1a96fba6SXin Li } else {
187*1a96fba6SXin Li PLOG(WARNING) << "Failed to open " << file << ".";
188*1a96fba6SXin Li }
189*1a96fba6SXin Li return base::ScopedFD();
190*1a96fba6SXin Li }
191*1a96fba6SXin Li
192*1a96fba6SXin Li // Remove the O_NONBLOCK flag unless the original |flags| have it.
193*1a96fba6SXin Li if ((flags & O_NONBLOCK) == 0) {
194*1a96fba6SXin Li flags = fcntl(fd.get(), F_GETFL);
195*1a96fba6SXin Li if (flags == -1) {
196*1a96fba6SXin Li PLOG(ERROR) << "Failed to get fd flags for " << file;
197*1a96fba6SXin Li return base::ScopedFD();
198*1a96fba6SXin Li }
199*1a96fba6SXin Li if (fcntl(fd.get(), F_SETFL, flags & ~O_NONBLOCK)) {
200*1a96fba6SXin Li PLOG(ERROR) << "Failed to set fd flags for " << file;
201*1a96fba6SXin Li return base::ScopedFD();
202*1a96fba6SXin Li }
203*1a96fba6SXin Li }
204*1a96fba6SXin Li
205*1a96fba6SXin Li return fd;
206*1a96fba6SXin Li }
207*1a96fba6SXin Li
OpenSafelyInternal(int parent_fd,const base::FilePath & path,int flags,mode_t mode)208*1a96fba6SXin Li base::ScopedFD OpenSafelyInternal(int parent_fd,
209*1a96fba6SXin Li const base::FilePath& path,
210*1a96fba6SXin Li int flags,
211*1a96fba6SXin Li mode_t mode) {
212*1a96fba6SXin Li std::vector<std::string> components;
213*1a96fba6SXin Li path.GetComponents(&components);
214*1a96fba6SXin Li
215*1a96fba6SXin Li auto itr = components.begin();
216*1a96fba6SXin Li if (itr == components.end()) {
217*1a96fba6SXin Li LOG(ERROR) << "A path is required.";
218*1a96fba6SXin Li return base::ScopedFD(); // This is an invalid fd.
219*1a96fba6SXin Li }
220*1a96fba6SXin Li
221*1a96fba6SXin Li base::ScopedFD child_fd;
222*1a96fba6SXin Li int parent_flags = flags | O_NONBLOCK | O_RDONLY | O_DIRECTORY | O_PATH;
223*1a96fba6SXin Li for (; itr + 1 != components.end(); ++itr) {
224*1a96fba6SXin Li child_fd = OpenPathComponentInternal(parent_fd, *itr, parent_flags, 0);
225*1a96fba6SXin Li if (!child_fd.is_valid()) {
226*1a96fba6SXin Li return base::ScopedFD();
227*1a96fba6SXin Li }
228*1a96fba6SXin Li parent_fd = child_fd.get();
229*1a96fba6SXin Li }
230*1a96fba6SXin Li
231*1a96fba6SXin Li return OpenPathComponentInternal(parent_fd, *itr, flags, mode);
232*1a96fba6SXin Li }
233*1a96fba6SXin Li
234*1a96fba6SXin Li } // namespace
235*1a96fba6SXin Li
TouchFile(const base::FilePath & path,int new_file_permissions,uid_t uid,gid_t gid)236*1a96fba6SXin Li bool TouchFile(const base::FilePath& path,
237*1a96fba6SXin Li int new_file_permissions,
238*1a96fba6SXin Li uid_t uid,
239*1a96fba6SXin Li gid_t gid) {
240*1a96fba6SXin Li // Make sure |permissions| doesn't have any out-of-range bits.
241*1a96fba6SXin Li if (new_file_permissions & ~kPermissions777) {
242*1a96fba6SXin Li LOG(WARNING) << "Illegal permissions: " << new_file_permissions;
243*1a96fba6SXin Li return false;
244*1a96fba6SXin Li }
245*1a96fba6SXin Li
246*1a96fba6SXin Li base::ScopedFD scoped_fd;
247*1a96fba6SXin Li if (!TouchFileInternal(path, uid, gid, &scoped_fd)) {
248*1a96fba6SXin Li return false;
249*1a96fba6SXin Li }
250*1a96fba6SXin Li
251*1a96fba6SXin Li // scoped_fd is valid only if a new file was created.
252*1a96fba6SXin Li if (scoped_fd != -1 &&
253*1a96fba6SXin Li HANDLE_EINTR(fchmod(scoped_fd.get(), new_file_permissions)) == -1) {
254*1a96fba6SXin Li PLOG(WARNING) << "Failed to set permissions for \"" << path.value() << '"';
255*1a96fba6SXin Li base::DeleteFile(path, false);
256*1a96fba6SXin Li return false;
257*1a96fba6SXin Li }
258*1a96fba6SXin Li
259*1a96fba6SXin Li return true;
260*1a96fba6SXin Li }
261*1a96fba6SXin Li
TouchFile(const base::FilePath & path)262*1a96fba6SXin Li bool TouchFile(const base::FilePath& path) {
263*1a96fba6SXin Li // Use TouchFile() instead of TouchFileInternal() to explicitly set
264*1a96fba6SXin Li // permissions to 600 in case umask is set strangely.
265*1a96fba6SXin Li return TouchFile(path, kPermissions600, geteuid(), getegid());
266*1a96fba6SXin Li }
267*1a96fba6SXin Li
OpenSafely(const base::FilePath & path,int flags,mode_t mode)268*1a96fba6SXin Li base::ScopedFD OpenSafely(const base::FilePath& path, int flags, mode_t mode) {
269*1a96fba6SXin Li if (!path.IsAbsolute()) {
270*1a96fba6SXin Li LOG(ERROR) << "An absolute path is required.";
271*1a96fba6SXin Li return base::ScopedFD(); // This is an invalid fd.
272*1a96fba6SXin Li }
273*1a96fba6SXin Li
274*1a96fba6SXin Li base::ScopedFD fd(OpenSafelyInternal(-1, path, flags, mode));
275*1a96fba6SXin Li if (!fd.is_valid())
276*1a96fba6SXin Li return base::ScopedFD();
277*1a96fba6SXin Li
278*1a96fba6SXin Li // Ensure the opened file is a regular file or directory.
279*1a96fba6SXin Li struct stat st;
280*1a96fba6SXin Li if (fstat(fd.get(), &st) < 0) {
281*1a96fba6SXin Li PLOG(ERROR) << "Failed to fstat " << path.value();
282*1a96fba6SXin Li return base::ScopedFD();
283*1a96fba6SXin Li }
284*1a96fba6SXin Li
285*1a96fba6SXin Li // This detects a FIFO opened for reading, for example.
286*1a96fba6SXin Li if (flags & O_DIRECTORY) {
287*1a96fba6SXin Li if (!S_ISDIR(st.st_mode)) {
288*1a96fba6SXin Li LOG(ERROR) << path.value() << " is not a directory: " << st.st_mode;
289*1a96fba6SXin Li return base::ScopedFD();
290*1a96fba6SXin Li }
291*1a96fba6SXin Li } else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) {
292*1a96fba6SXin Li LOG(ERROR) << path.value()
293*1a96fba6SXin Li << " is not a regular file or directory: " << st.st_mode;
294*1a96fba6SXin Li return base::ScopedFD();
295*1a96fba6SXin Li }
296*1a96fba6SXin Li
297*1a96fba6SXin Li return fd;
298*1a96fba6SXin Li }
299*1a96fba6SXin Li
OpenAtSafely(int parent_fd,const base::FilePath & path,int flags,mode_t mode)300*1a96fba6SXin Li base::ScopedFD OpenAtSafely(int parent_fd,
301*1a96fba6SXin Li const base::FilePath& path,
302*1a96fba6SXin Li int flags,
303*1a96fba6SXin Li mode_t mode) {
304*1a96fba6SXin Li base::ScopedFD fd(OpenSafelyInternal(parent_fd, path, flags, mode));
305*1a96fba6SXin Li if (!fd.is_valid())
306*1a96fba6SXin Li return base::ScopedFD();
307*1a96fba6SXin Li
308*1a96fba6SXin Li // Ensure the opened file is a regular file or directory.
309*1a96fba6SXin Li struct stat st;
310*1a96fba6SXin Li if (fstat(fd.get(), &st) < 0) {
311*1a96fba6SXin Li PLOG(ERROR) << "Failed to fstat " << path.value();
312*1a96fba6SXin Li return base::ScopedFD();
313*1a96fba6SXin Li }
314*1a96fba6SXin Li
315*1a96fba6SXin Li // This detects a FIFO opened for reading, for example.
316*1a96fba6SXin Li if (flags & O_DIRECTORY) {
317*1a96fba6SXin Li if (!S_ISDIR(st.st_mode)) {
318*1a96fba6SXin Li LOG(ERROR) << path.value() << " is not a directory: " << st.st_mode;
319*1a96fba6SXin Li return base::ScopedFD();
320*1a96fba6SXin Li }
321*1a96fba6SXin Li } else if (!S_ISREG(st.st_mode)) {
322*1a96fba6SXin Li LOG(ERROR) << path.value() << " is not a regular file: " << st.st_mode;
323*1a96fba6SXin Li return base::ScopedFD();
324*1a96fba6SXin Li }
325*1a96fba6SXin Li
326*1a96fba6SXin Li return fd;
327*1a96fba6SXin Li }
328*1a96fba6SXin Li
OpenFifoSafely(const base::FilePath & path,int flags,mode_t mode)329*1a96fba6SXin Li base::ScopedFD OpenFifoSafely(const base::FilePath& path,
330*1a96fba6SXin Li int flags,
331*1a96fba6SXin Li mode_t mode) {
332*1a96fba6SXin Li if (!path.IsAbsolute()) {
333*1a96fba6SXin Li LOG(ERROR) << "An absolute path is required.";
334*1a96fba6SXin Li return base::ScopedFD(); // This is an invalid fd.
335*1a96fba6SXin Li }
336*1a96fba6SXin Li
337*1a96fba6SXin Li base::ScopedFD fd(OpenSafelyInternal(-1, path, flags, mode));
338*1a96fba6SXin Li if (!fd.is_valid())
339*1a96fba6SXin Li return base::ScopedFD();
340*1a96fba6SXin Li
341*1a96fba6SXin Li // Ensure the opened file is a FIFO.
342*1a96fba6SXin Li struct stat st;
343*1a96fba6SXin Li if (fstat(fd.get(), &st) < 0) {
344*1a96fba6SXin Li PLOG(ERROR) << "Failed to fstat " << path.value();
345*1a96fba6SXin Li return base::ScopedFD();
346*1a96fba6SXin Li }
347*1a96fba6SXin Li
348*1a96fba6SXin Li if (!S_ISFIFO(st.st_mode)) {
349*1a96fba6SXin Li LOG(ERROR) << path.value() << " is not a FIFO: " << st.st_mode;
350*1a96fba6SXin Li return base::ScopedFD();
351*1a96fba6SXin Li }
352*1a96fba6SXin Li
353*1a96fba6SXin Li return fd;
354*1a96fba6SXin Li }
355*1a96fba6SXin Li
MkdirRecursively(const base::FilePath & full_path,mode_t mode)356*1a96fba6SXin Li base::ScopedFD MkdirRecursively(const base::FilePath& full_path, mode_t mode) {
357*1a96fba6SXin Li std::vector<std::string> components;
358*1a96fba6SXin Li full_path.GetComponents(&components);
359*1a96fba6SXin Li
360*1a96fba6SXin Li auto itr = components.begin();
361*1a96fba6SXin Li if (!full_path.IsAbsolute() || itr == components.end()) {
362*1a96fba6SXin Li LOG(ERROR) << "An absolute path is required.";
363*1a96fba6SXin Li return base::ScopedFD(); // This is an invalid fd.
364*1a96fba6SXin Li }
365*1a96fba6SXin Li
366*1a96fba6SXin Li base::ScopedFD parent_fd;
367*1a96fba6SXin Li int parent_flags = O_NONBLOCK | O_RDONLY | O_DIRECTORY | O_PATH;
368*1a96fba6SXin Li while (itr + 1 != components.end()) {
369*1a96fba6SXin Li base::ScopedFD child(
370*1a96fba6SXin Li OpenPathComponentInternal(parent_fd.get(), *itr, parent_flags, 0));
371*1a96fba6SXin Li if (!child.is_valid()) {
372*1a96fba6SXin Li return base::ScopedFD();
373*1a96fba6SXin Li }
374*1a96fba6SXin Li parent_fd = std::move(child);
375*1a96fba6SXin Li
376*1a96fba6SXin Li ++itr;
377*1a96fba6SXin Li
378*1a96fba6SXin Li // Try to create the directory. Note that Chromium's MkdirRecursively() uses
379*1a96fba6SXin Li // 0700, but we use 0755.
380*1a96fba6SXin Li if (mkdirat(parent_fd.get(), itr->c_str(), mode) != 0) {
381*1a96fba6SXin Li if (errno != EEXIST) {
382*1a96fba6SXin Li PLOG(ERROR) << "Failed to mkdirat " << *itr
383*1a96fba6SXin Li << ": full_path=" << full_path.value();
384*1a96fba6SXin Li return base::ScopedFD();
385*1a96fba6SXin Li }
386*1a96fba6SXin Li }
387*1a96fba6SXin Li }
388*1a96fba6SXin Li
389*1a96fba6SXin Li return OpenPathComponentInternal(parent_fd.get(), *itr,
390*1a96fba6SXin Li O_RDONLY | O_DIRECTORY, 0);
391*1a96fba6SXin Li }
392*1a96fba6SXin Li
WriteStringToFile(const base::FilePath & path,const std::string & data)393*1a96fba6SXin Li bool WriteStringToFile(const base::FilePath& path, const std::string& data) {
394*1a96fba6SXin Li return WriteToFile(path, data.data(), data.size());
395*1a96fba6SXin Li }
396*1a96fba6SXin Li
WriteToFile(const base::FilePath & path,const char * data,size_t size)397*1a96fba6SXin Li bool WriteToFile(const base::FilePath& path, const char* data, size_t size) {
398*1a96fba6SXin Li if (!base::DirectoryExists(path.DirName())) {
399*1a96fba6SXin Li if (!base::CreateDirectory(path.DirName())) {
400*1a96fba6SXin Li LOG(ERROR) << "Cannot create directory: " << path.DirName().value();
401*1a96fba6SXin Li return false;
402*1a96fba6SXin Li }
403*1a96fba6SXin Li }
404*1a96fba6SXin Li // base::WriteFile takes an int size.
405*1a96fba6SXin Li if (size > std::numeric_limits<int>::max()) {
406*1a96fba6SXin Li LOG(ERROR) << "Cannot write to " << path.value()
407*1a96fba6SXin Li << ". Data is too large: " << size << " bytes.";
408*1a96fba6SXin Li return false;
409*1a96fba6SXin Li }
410*1a96fba6SXin Li
411*1a96fba6SXin Li int data_written = base::WriteFile(path, data, size);
412*1a96fba6SXin Li return data_written == static_cast<int>(size);
413*1a96fba6SXin Li }
414*1a96fba6SXin Li
SyncFileOrDirectory(const base::FilePath & path,bool is_directory,bool data_sync)415*1a96fba6SXin Li bool SyncFileOrDirectory(const base::FilePath& path,
416*1a96fba6SXin Li bool is_directory,
417*1a96fba6SXin Li bool data_sync) {
418*1a96fba6SXin Li const base::TimeTicks start = base::TimeTicks::Now();
419*1a96fba6SXin Li data_sync = data_sync && !is_directory;
420*1a96fba6SXin Li
421*1a96fba6SXin Li int flags = (is_directory ? O_RDONLY | O_DIRECTORY : O_WRONLY);
422*1a96fba6SXin Li int fd = HANDLE_EINTR(open(path.value().c_str(), flags));
423*1a96fba6SXin Li if (fd < 0) {
424*1a96fba6SXin Li PLOG(WARNING) << "Could not open " << path.value() << " for syncing";
425*1a96fba6SXin Li return false;
426*1a96fba6SXin Li }
427*1a96fba6SXin Li // POSIX specifies EINTR as a possible return value of fsync() but not for
428*1a96fba6SXin Li // fdatasync(). To be on the safe side, it is handled in both cases.
429*1a96fba6SXin Li int result =
430*1a96fba6SXin Li (data_sync ? HANDLE_EINTR(fdatasync(fd)) : HANDLE_EINTR(fsync(fd)));
431*1a96fba6SXin Li if (result < 0) {
432*1a96fba6SXin Li PLOG(WARNING) << "Failed to sync " << path.value();
433*1a96fba6SXin Li close(fd);
434*1a96fba6SXin Li return false;
435*1a96fba6SXin Li }
436*1a96fba6SXin Li // close() may not be retried on error.
437*1a96fba6SXin Li result = IGNORE_EINTR(close(fd));
438*1a96fba6SXin Li if (result < 0) {
439*1a96fba6SXin Li PLOG(WARNING) << "Failed to close after sync " << path.value();
440*1a96fba6SXin Li return false;
441*1a96fba6SXin Li }
442*1a96fba6SXin Li
443*1a96fba6SXin Li const base::TimeDelta delta = base::TimeTicks::Now() - start;
444*1a96fba6SXin Li if (delta > kLongSync) {
445*1a96fba6SXin Li LOG(WARNING) << "Long " << (data_sync ? "fdatasync" : "fsync") << "() of "
446*1a96fba6SXin Li << path.value() << ": " << delta.InSeconds() << " seconds";
447*1a96fba6SXin Li }
448*1a96fba6SXin Li
449*1a96fba6SXin Li return true;
450*1a96fba6SXin Li }
451*1a96fba6SXin Li
WriteToFileAtomic(const base::FilePath & path,const char * data,size_t size,mode_t mode)452*1a96fba6SXin Li bool WriteToFileAtomic(const base::FilePath& path,
453*1a96fba6SXin Li const char* data,
454*1a96fba6SXin Li size_t size,
455*1a96fba6SXin Li mode_t mode) {
456*1a96fba6SXin Li if (!base::DirectoryExists(path.DirName())) {
457*1a96fba6SXin Li if (!base::CreateDirectory(path.DirName())) {
458*1a96fba6SXin Li LOG(ERROR) << "Cannot create directory: " << path.DirName().value();
459*1a96fba6SXin Li return false;
460*1a96fba6SXin Li }
461*1a96fba6SXin Li }
462*1a96fba6SXin Li std::string random_suffix = GetRandomSuffix();
463*1a96fba6SXin Li if (random_suffix.empty()) {
464*1a96fba6SXin Li PLOG(WARNING) << "Could not compute random suffix";
465*1a96fba6SXin Li return false;
466*1a96fba6SXin Li }
467*1a96fba6SXin Li std::string temp_name = path.AddExtension(random_suffix).value();
468*1a96fba6SXin Li int fd =
469*1a96fba6SXin Li HANDLE_EINTR(open(temp_name.c_str(), O_CREAT | O_EXCL | O_WRONLY, mode));
470*1a96fba6SXin Li if (fd < 0) {
471*1a96fba6SXin Li PLOG(WARNING) << "Could not open " << temp_name << " for atomic write";
472*1a96fba6SXin Li unlink(temp_name.c_str());
473*1a96fba6SXin Li return false;
474*1a96fba6SXin Li }
475*1a96fba6SXin Li
476*1a96fba6SXin Li size_t position = 0;
477*1a96fba6SXin Li while (position < size) {
478*1a96fba6SXin Li ssize_t bytes_written =
479*1a96fba6SXin Li HANDLE_EINTR(write(fd, data + position, size - position));
480*1a96fba6SXin Li if (bytes_written < 0) {
481*1a96fba6SXin Li PLOG(WARNING) << "Could not write " << temp_name;
482*1a96fba6SXin Li close(fd);
483*1a96fba6SXin Li unlink(temp_name.c_str());
484*1a96fba6SXin Li return false;
485*1a96fba6SXin Li }
486*1a96fba6SXin Li position += bytes_written;
487*1a96fba6SXin Li }
488*1a96fba6SXin Li
489*1a96fba6SXin Li if (HANDLE_EINTR(fdatasync(fd)) < 0) {
490*1a96fba6SXin Li PLOG(WARNING) << "Could not fsync " << temp_name;
491*1a96fba6SXin Li close(fd);
492*1a96fba6SXin Li unlink(temp_name.c_str());
493*1a96fba6SXin Li return false;
494*1a96fba6SXin Li }
495*1a96fba6SXin Li if (close(fd) < 0) {
496*1a96fba6SXin Li PLOG(WARNING) << "Could not close " << temp_name;
497*1a96fba6SXin Li unlink(temp_name.c_str());
498*1a96fba6SXin Li return false;
499*1a96fba6SXin Li }
500*1a96fba6SXin Li
501*1a96fba6SXin Li if (rename(temp_name.c_str(), path.value().c_str()) < 0) {
502*1a96fba6SXin Li PLOG(WARNING) << "Could not close " << temp_name;
503*1a96fba6SXin Li unlink(temp_name.c_str());
504*1a96fba6SXin Li return false;
505*1a96fba6SXin Li }
506*1a96fba6SXin Li
507*1a96fba6SXin Li return true;
508*1a96fba6SXin Li }
509*1a96fba6SXin Li
ComputeDirectoryDiskUsage(const base::FilePath & root_path)510*1a96fba6SXin Li int64_t ComputeDirectoryDiskUsage(const base::FilePath& root_path) {
511*1a96fba6SXin Li constexpr size_t S_BLKSIZE = 512;
512*1a96fba6SXin Li int64_t running_blocks = 0;
513*1a96fba6SXin Li base::FileEnumerator file_iter(root_path, true,
514*1a96fba6SXin Li base::FileEnumerator::FILES |
515*1a96fba6SXin Li base::FileEnumerator::DIRECTORIES |
516*1a96fba6SXin Li base::FileEnumerator::SHOW_SYM_LINKS);
517*1a96fba6SXin Li while (!file_iter.Next().empty()) {
518*1a96fba6SXin Li // st_blocks in struct stat is the number of S_BLKSIZE (512) bytes sized
519*1a96fba6SXin Li // blocks occupied by this file.
520*1a96fba6SXin Li running_blocks += file_iter.GetInfo().stat().st_blocks;
521*1a96fba6SXin Li }
522*1a96fba6SXin Li // Each block is S_BLKSIZE (512) bytes so *S_BLKSIZE.
523*1a96fba6SXin Li return running_blocks * S_BLKSIZE;
524*1a96fba6SXin Li }
525*1a96fba6SXin Li
526*1a96fba6SXin Li } // namespace brillo
527