blob: 6100e10bc4fe8a8000a03750445c9828885e4662 [file] [log] [blame]
[email protected]011352fdf2012-03-10 00:18:311// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]b2e97292008-09-02 18:20:342// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/file_util.h"
6
[email protected]4b7743de2009-04-21 01:50:397#include <dirent.h>
[email protected]21dec3872008-09-18 19:15:548#include <errno.h>
[email protected]b2e97292008-09-02 18:20:349#include <fcntl.h>
10#include <fnmatch.h>
[email protected]b2e97292008-09-02 18:20:3411#include <libgen.h>
[email protected]e92dffe2010-05-12 21:36:3912#include <limits.h>
[email protected]836f1342008-10-01 17:40:1313#include <stdio.h>
[email protected]1c657852010-04-22 23:28:0514#include <stdlib.h>
[email protected]21dec3872008-09-18 19:15:5415#include <string.h>
[email protected]b2e97292008-09-02 18:20:3416#include <sys/errno.h>
[email protected]7856bb82008-12-12 23:43:0317#include <sys/mman.h>
[email protected]01e2a1f2010-05-12 15:13:5718#include <sys/param.h>
[email protected]b2e97292008-09-02 18:20:3419#include <sys/stat.h>
[email protected]ec3d1452010-02-18 10:02:2620#include <sys/time.h>
[email protected]4b7743de2009-04-21 01:50:3921#include <sys/types.h>
[email protected]b2e97292008-09-02 18:20:3422#include <time.h>
[email protected]4b7743de2009-04-21 01:50:3923#include <unistd.h>
[email protected]b2e97292008-09-02 18:20:3424
[email protected]3224dcd2009-09-16 17:31:2525#if defined(OS_MACOSX)
26#include <AvailabilityMacros.h>
[email protected]151c4a62011-04-22 04:15:1327#include "base/mac/foundation_util.h"
[email protected]f7d69972011-06-21 22:34:5028#elif !defined(OS_ANDROID)
[email protected]1c657852010-04-22 23:28:0529#include <glib.h>
[email protected]3224dcd2009-09-16 17:31:2530#endif
31
[email protected]b2e97292008-09-02 18:20:3432#include <fstream>
33
34#include "base/basictypes.h"
[email protected]157c61b2009-05-01 21:37:3135#include "base/eintr_wrapper.h"
[email protected]640517f2008-10-30 23:54:0436#include "base/file_path.h"
[email protected]b2e97292008-09-02 18:20:3437#include "base/logging.h"
[email protected]3b63f8f42011-03-28 01:54:1538#include "base/memory/scoped_ptr.h"
39#include "base/memory/singleton.h"
[email protected]0eae7eb2012-05-17 20:09:0640#include "base/path_service.h"
[email protected]7312f42a2011-10-17 21:30:2941#include "base/stl_util.h"
[email protected]b2e97292008-09-02 18:20:3442#include "base/string_util.h"
[email protected]151c4a62011-04-22 04:15:1343#include "base/stringprintf.h"
[email protected]807bc042009-07-15 01:32:0244#include "base/sys_string_conversions.h"
[email protected]34b99632011-01-01 01:01:0645#include "base/threading/thread_restrictions.h"
[email protected]4b7743de2009-04-21 01:50:3946#include "base/time.h"
[email protected]047a03f2009-10-07 02:10:2047#include "base/utf_string_conversions.h"
[email protected]172c5502009-06-24 03:29:2648
[email protected]f7d69972011-06-21 22:34:5049#if defined(OS_ANDROID)
50#include "base/os_compat_android.h"
51#endif
52
[email protected]4bd46792012-07-09 14:40:3953#if !defined(OS_IOS)
54#include <grp.h>
55#endif
56
[email protected]774727282012-08-06 09:14:4457#if defined(OS_CHROMEOS)
58#include "base/chromeos/chromeos_version.h"
59#endif
60
[email protected]b2e97292008-09-02 18:20:3461namespace file_util {
62
[email protected]6f5f4322010-06-09 22:56:4863namespace {
64
[email protected]07a35222012-07-19 22:24:0265#if defined(OS_BSD) || defined(OS_MACOSX)
[email protected]73e4c362011-09-22 14:47:1866typedef struct stat stat_wrapper_t;
67static int CallStat(const char *path, stat_wrapper_t *sb) {
68 base::ThreadRestrictions::AssertIOAllowed();
69 return stat(path, sb);
70}
71static int CallLstat(const char *path, stat_wrapper_t *sb) {
72 base::ThreadRestrictions::AssertIOAllowed();
73 return lstat(path, sb);
74}
75#else
76typedef struct stat64 stat_wrapper_t;
77static int CallStat(const char *path, stat_wrapper_t *sb) {
78 base::ThreadRestrictions::AssertIOAllowed();
79 return stat64(path, sb);
80}
81static int CallLstat(const char *path, stat_wrapper_t *sb) {
82 base::ThreadRestrictions::AssertIOAllowed();
83 return lstat64(path, sb);
84}
85#endif
86
[email protected]6f5f4322010-06-09 22:56:4887// Helper for NormalizeFilePath(), defined below.
88bool RealPath(const FilePath& path, FilePath* real_path) {
[email protected]ba74b0d22010-10-23 05:19:2089 base::ThreadRestrictions::AssertIOAllowed(); // For realpath().
[email protected]6f5f4322010-06-09 22:56:4890 FilePath::CharType buf[PATH_MAX];
91 if (!realpath(path.value().c_str(), buf))
92 return false;
93
94 *real_path = FilePath(buf);
95 return true;
96}
97
[email protected]73e4c362011-09-22 14:47:1898// Helper for VerifyPathControlledByUser.
99bool VerifySpecificPathControlledByUser(const FilePath& path,
100 uid_t owner_uid,
[email protected]7312f42a2011-10-17 21:30:29101 const std::set<gid_t>& group_gids) {
[email protected]73e4c362011-09-22 14:47:18102 stat_wrapper_t stat_info;
103 if (CallLstat(path.value().c_str(), &stat_info) != 0) {
[email protected]a42d4632011-10-26 21:48:00104 DPLOG(ERROR) << "Failed to get information on path "
105 << path.value();
[email protected]73e4c362011-09-22 14:47:18106 return false;
107 }
[email protected]6f5f4322010-06-09 22:56:48108
[email protected]73e4c362011-09-22 14:47:18109 if (S_ISLNK(stat_info.st_mode)) {
[email protected]a42d4632011-10-26 21:48:00110 DLOG(ERROR) << "Path " << path.value()
[email protected]73e4c362011-09-22 14:47:18111 << " is a symbolic link.";
112 return false;
113 }
114
115 if (stat_info.st_uid != owner_uid) {
[email protected]a42d4632011-10-26 21:48:00116 DLOG(ERROR) << "Path " << path.value()
117 << " is owned by the wrong user.";
[email protected]73e4c362011-09-22 14:47:18118 return false;
119 }
120
[email protected]7312f42a2011-10-17 21:30:29121 if ((stat_info.st_mode & S_IWGRP) &&
122 !ContainsKey(group_gids, stat_info.st_gid)) {
[email protected]a42d4632011-10-26 21:48:00123 DLOG(ERROR) << "Path " << path.value()
124 << " is writable by an unprivileged group.";
[email protected]73e4c362011-09-22 14:47:18125 return false;
126 }
127
128 if (stat_info.st_mode & S_IWOTH) {
[email protected]a42d4632011-10-26 21:48:00129 DLOG(ERROR) << "Path " << path.value()
130 << " is writable by any user.";
[email protected]73e4c362011-09-22 14:47:18131 return false;
132 }
133
134 return true;
[email protected]fb66f9d2009-09-07 16:39:46135}
[email protected]73e4c362011-09-22 14:47:18136
137} // namespace
[email protected]fb66f9d2009-09-07 16:39:46138
[email protected]151c4a62011-04-22 04:15:13139static std::string TempFileName() {
140#if defined(OS_MACOSX)
141 return StringPrintf(".%s.XXXXXX", base::mac::BaseBundleID());
142#endif
[email protected]fb66f9d2009-09-07 16:39:46143
[email protected]22a087f2009-03-17 19:17:43144#if defined(GOOGLE_CHROME_BUILD)
[email protected]151c4a62011-04-22 04:15:13145 return std::string(".com.google.Chrome.XXXXXX");
[email protected]22a087f2009-03-17 19:17:43146#else
[email protected]151c4a62011-04-22 04:15:13147 return std::string(".org.chromium.Chromium.XXXXXX");
[email protected]22a087f2009-03-17 19:17:43148#endif
[email protected]151c4a62011-04-22 04:15:13149}
[email protected]778e8c52008-09-11 17:36:23150
[email protected]640517f2008-10-30 23:54:04151bool AbsolutePath(FilePath* path) {
[email protected]ba74b0d22010-10-23 05:19:20152 base::ThreadRestrictions::AssertIOAllowed(); // For realpath().
[email protected]b2e97292008-09-02 18:20:34153 char full_path[PATH_MAX];
[email protected]640517f2008-10-30 23:54:04154 if (realpath(path->value().c_str(), full_path) == NULL)
[email protected]b2e97292008-09-02 18:20:34155 return false;
[email protected]640517f2008-10-30 23:54:04156 *path = FilePath(full_path);
[email protected]b2e97292008-09-02 18:20:34157 return true;
158}
159
[email protected]4b7743de2009-04-21 01:50:39160int CountFilesCreatedAfter(const FilePath& path,
161 const base::Time& comparison_time) {
[email protected]ba74b0d22010-10-23 05:19:20162 base::ThreadRestrictions::AssertIOAllowed();
[email protected]4b7743de2009-04-21 01:50:39163 int file_count = 0;
164
165 DIR* dir = opendir(path.value().c_str());
166 if (dir) {
[email protected]e37e88a2011-11-15 00:06:16167#if !defined(OS_LINUX) && !defined(OS_MACOSX) && !defined(OS_BSD) && \
168 !defined(OS_SOLARIS) && !defined(OS_ANDROID)
[email protected]e43eddf12009-12-29 00:32:52169 #error Port warning: depending on the definition of struct dirent, \
170 additional space for pathname may be needed
[email protected]49930c3a2009-08-06 21:23:07171#endif
[email protected]2126577b2009-04-23 15:05:19172 struct dirent ent_buf;
[email protected]4b7743de2009-04-21 01:50:39173 struct dirent* ent;
[email protected]2126577b2009-04-23 15:05:19174 while (readdir_r(dir, &ent_buf, &ent) == 0 && ent) {
[email protected]4b7743de2009-04-21 01:50:39175 if ((strcmp(ent->d_name, ".") == 0) ||
176 (strcmp(ent->d_name, "..") == 0))
177 continue;
178
[email protected]fb66f9d2009-09-07 16:39:46179 stat_wrapper_t st;
180 int test = CallStat(path.Append(ent->d_name).value().c_str(), &st);
[email protected]4b7743de2009-04-21 01:50:39181 if (test != 0) {
[email protected]a42d4632011-10-26 21:48:00182 DPLOG(ERROR) << "stat64 failed";
[email protected]4b7743de2009-04-21 01:50:39183 continue;
184 }
[email protected]2126577b2009-04-23 15:05:19185 // Here, we use Time::TimeT(), which discards microseconds. This
186 // means that files which are newer than |comparison_time| may
187 // be considered older. If we don't discard microseconds, it
188 // introduces another issue. Suppose the following case:
189 //
190 // 1. Get |comparison_time| by Time::Now() and the value is 10.1 (secs).
191 // 2. Create a file and the current time is 10.3 (secs).
192 //
193 // As POSIX doesn't have microsecond precision for |st_ctime|,
194 // the creation time of the file created in the step 2 is 10 and
195 // the file is considered older than |comparison_time|. After
196 // all, we may have to accept either of the two issues: 1. files
197 // which are older than |comparison_time| are considered newer
198 // (current implementation) 2. files newer than
199 // |comparison_time| are considered older.
[email protected]e9ad4352010-11-17 11:19:15200 if (static_cast<time_t>(st.st_ctime) >= comparison_time.ToTimeT())
[email protected]4b7743de2009-04-21 01:50:39201 ++file_count;
202 }
203 closedir(dir);
204 }
205 return file_count;
206}
207
[email protected]b2e97292008-09-02 18:20:34208// TODO(erikkay): The Windows version of this accepts paths like "foo/bar/*"
209// which works both with and without the recursive flag. I'm not sure we need
210// that functionality. If not, remove from file_util_win.cc, otherwise add it
211// here.
[email protected]640517f2008-10-30 23:54:04212bool Delete(const FilePath& path, bool recursive) {
[email protected]ba74b0d22010-10-23 05:19:20213 base::ThreadRestrictions::AssertIOAllowed();
[email protected]640517f2008-10-30 23:54:04214 const char* path_str = path.value().c_str();
[email protected]fb66f9d2009-09-07 16:39:46215 stat_wrapper_t file_info;
[email protected]7122db22012-06-30 05:26:59216 int test = CallLstat(path_str, &file_info);
[email protected]b2e97292008-09-02 18:20:34217 if (test != 0) {
218 // The Windows version defines this condition as success.
[email protected]9e51af92009-02-04 00:58:39219 bool ret = (errno == ENOENT || errno == ENOTDIR);
[email protected]b2e97292008-09-02 18:20:34220 return ret;
221 }
222 if (!S_ISDIR(file_info.st_mode))
[email protected]640517f2008-10-30 23:54:04223 return (unlink(path_str) == 0);
[email protected]b2e97292008-09-02 18:20:34224 if (!recursive)
[email protected]640517f2008-10-30 23:54:04225 return (rmdir(path_str) == 0);
[email protected]b2e97292008-09-02 18:20:34226
227 bool success = true;
[email protected]49930c3a2009-08-06 21:23:07228 std::stack<std::string> directories;
229 directories.push(path.value());
[email protected]58b7c5a62011-08-15 13:09:27230 FileEnumerator traversal(path, true, static_cast<FileEnumerator::FileType>(
[email protected]49930c3a2009-08-06 21:23:07231 FileEnumerator::FILES | FileEnumerator::DIRECTORIES |
232 FileEnumerator::SHOW_SYM_LINKS));
233 for (FilePath current = traversal.Next(); success && !current.empty();
234 current = traversal.Next()) {
235 FileEnumerator::FindInfo info;
236 traversal.GetFindInfo(&info);
237
238 if (S_ISDIR(info.stat.st_mode))
239 directories.push(current.value());
240 else
241 success = (unlink(current.value().c_str()) == 0);
[email protected]21dec3872008-09-18 19:15:54242 }
[email protected]49930c3a2009-08-06 21:23:07243
244 while (success && !directories.empty()) {
245 FilePath dir = FilePath(directories.top());
246 directories.pop();
247 success = (rmdir(dir.value().c_str()) == 0);
[email protected]b2e97292008-09-02 18:20:34248 }
249 return success;
250}
251
[email protected]640517f2008-10-30 23:54:04252bool Move(const FilePath& from_path, const FilePath& to_path) {
[email protected]ba74b0d22010-10-23 05:19:20253 base::ThreadRestrictions::AssertIOAllowed();
[email protected]bc6a9012009-10-15 01:11:44254 // Windows compatibility: if to_path exists, from_path and to_path
255 // must be the same type, either both files, or both directories.
256 stat_wrapper_t to_file_info;
257 if (CallStat(to_path.value().c_str(), &to_file_info) == 0) {
258 stat_wrapper_t from_file_info;
259 if (CallStat(from_path.value().c_str(), &from_file_info) == 0) {
260 if (S_ISDIR(to_file_info.st_mode) != S_ISDIR(from_file_info.st_mode))
261 return false;
262 } else {
263 return false;
264 }
265 }
266
[email protected]cc7948a2009-03-13 20:01:43267 if (rename(from_path.value().c_str(), to_path.value().c_str()) == 0)
268 return true;
269
270 if (!CopyDirectory(from_path, to_path, true))
271 return false;
272
273 Delete(from_path, true);
274 return true;
[email protected]b2e97292008-09-02 18:20:34275}
276
[email protected]c5866dca2009-05-19 17:21:07277bool ReplaceFile(const FilePath& from_path, const FilePath& to_path) {
[email protected]ba74b0d22010-10-23 05:19:20278 base::ThreadRestrictions::AssertIOAllowed();
[email protected]c5866dca2009-05-19 17:21:07279 return (rename(from_path.value().c_str(), to_path.value().c_str()) == 0);
280}
281
[email protected]640517f2008-10-30 23:54:04282bool CopyDirectory(const FilePath& from_path,
283 const FilePath& to_path,
[email protected]21dec3872008-09-18 19:15:54284 bool recursive) {
[email protected]ba74b0d22010-10-23 05:19:20285 base::ThreadRestrictions::AssertIOAllowed();
[email protected]21dec3872008-09-18 19:15:54286 // Some old callers of CopyDirectory want it to support wildcards.
287 // After some discussion, we decided to fix those callers.
288 // Break loudly here if anyone tries to do this.
289 // TODO(evanm): remove this once we're sure it's ok.
[email protected]640517f2008-10-30 23:54:04290 DCHECK(to_path.value().find('*') == std::string::npos);
291 DCHECK(from_path.value().find('*') == std::string::npos);
[email protected]21dec3872008-09-18 19:15:54292
293 char top_dir[PATH_MAX];
[email protected]640517f2008-10-30 23:54:04294 if (base::strlcpy(top_dir, from_path.value().c_str(),
[email protected]21dec3872008-09-18 19:15:54295 arraysize(top_dir)) >= arraysize(top_dir)) {
296 return false;
297 }
298
[email protected]49930c3a2009-08-06 21:23:07299 // This function does not properly handle destinations within the source
300 FilePath real_to_path = to_path;
301 if (PathExists(real_to_path)) {
302 if (!AbsolutePath(&real_to_path))
303 return false;
304 } else {
305 real_to_path = real_to_path.DirName();
306 if (!AbsolutePath(&real_to_path))
307 return false;
308 }
309 FilePath real_from_path = from_path;
310 if (!AbsolutePath(&real_from_path))
[email protected]21dec3872008-09-18 19:15:54311 return false;
[email protected]49930c3a2009-08-06 21:23:07312 if (real_to_path.value().size() >= real_from_path.value().size() &&
313 real_to_path.value().compare(0, real_from_path.value().size(),
314 real_from_path.value()) == 0)
315 return false;
316
317 bool success = true;
[email protected]58b7c5a62011-08-15 13:09:27318 FileEnumerator::FileType traverse_type =
319 static_cast<FileEnumerator::FileType>(FileEnumerator::FILES |
[email protected]49930c3a2009-08-06 21:23:07320 FileEnumerator::SHOW_SYM_LINKS);
321 if (recursive)
[email protected]58b7c5a62011-08-15 13:09:27322 traverse_type = static_cast<FileEnumerator::FileType>(
[email protected]49930c3a2009-08-06 21:23:07323 traverse_type | FileEnumerator::DIRECTORIES);
324 FileEnumerator traversal(from_path, recursive, traverse_type);
325
[email protected]abbc5732009-10-13 17:57:27326 // We have to mimic windows behavior here. |to_path| may not exist yet,
[email protected]bc6a9012009-10-15 01:11:44327 // start the loop with |to_path|.
[email protected]49930c3a2009-08-06 21:23:07328 FileEnumerator::FindInfo info;
329 FilePath current = from_path;
330 if (stat(from_path.value().c_str(), &info.stat) < 0) {
[email protected]a42d4632011-10-26 21:48:00331 DLOG(ERROR) << "CopyDirectory() couldn't stat source directory: "
332 << from_path.value() << " errno = " << errno;
[email protected]49930c3a2009-08-06 21:23:07333 success = false;
[email protected]21dec3872008-09-18 19:15:54334 }
[email protected]bc6a9012009-10-15 01:11:44335 struct stat to_path_stat;
336 FilePath from_path_base = from_path;
337 if (recursive && stat(to_path.value().c_str(), &to_path_stat) == 0 &&
338 S_ISDIR(to_path_stat.st_mode)) {
339 // If the destination already exists and is a directory, then the
340 // top level of source needs to be copied.
341 from_path_base = from_path.DirName();
342 }
343
344 // The Windows version of this function assumes that non-recursive calls
345 // will always have a directory for from_path.
346 DCHECK(recursive || S_ISDIR(info.stat.st_mode));
[email protected]21dec3872008-09-18 19:15:54347
[email protected]49930c3a2009-08-06 21:23:07348 while (success && !current.empty()) {
349 // current is the source path, including from_path, so paste
[email protected]21dec3872008-09-18 19:15:54350 // the suffix after from_path onto to_path to create the target_path.
[email protected]abbc5732009-10-13 17:57:27351 std::string suffix(&current.value().c_str()[from_path_base.value().size()]);
[email protected]ca0209612009-01-13 18:57:46352 // Strip the leading '/' (if any).
353 if (!suffix.empty()) {
[email protected]6ae340f2009-03-06 09:56:28354 DCHECK_EQ('/', suffix[0]);
[email protected]ca0209612009-01-13 18:57:46355 suffix.erase(0, 1);
356 }
357 const FilePath target_path = to_path.Append(suffix);
[email protected]21dec3872008-09-18 19:15:54358
[email protected]49930c3a2009-08-06 21:23:07359 if (S_ISDIR(info.stat.st_mode)) {
360 if (mkdir(target_path.value().c_str(), info.stat.st_mode & 01777) != 0 &&
361 errno != EEXIST) {
[email protected]a42d4632011-10-26 21:48:00362 DLOG(ERROR) << "CopyDirectory() couldn't create directory: "
363 << target_path.value() << " errno = " << errno;
[email protected]49930c3a2009-08-06 21:23:07364 success = false;
365 }
366 } else if (S_ISREG(info.stat.st_mode)) {
367 if (!CopyFile(current, target_path)) {
[email protected]a42d4632011-10-26 21:48:00368 DLOG(ERROR) << "CopyDirectory() couldn't create file: "
369 << target_path.value();
[email protected]49930c3a2009-08-06 21:23:07370 success = false;
371 }
372 } else {
[email protected]a42d4632011-10-26 21:48:00373 DLOG(WARNING) << "CopyDirectory() skipping non-regular file: "
374 << current.value();
[email protected]21dec3872008-09-18 19:15:54375 }
[email protected]21dec3872008-09-18 19:15:54376
[email protected]49930c3a2009-08-06 21:23:07377 current = traversal.Next();
378 traversal.GetFindInfo(&info);
[email protected]21dec3872008-09-18 19:15:54379 }
380
[email protected]49930c3a2009-08-06 21:23:07381 return success;
[email protected]b2e97292008-09-02 18:20:34382}
383
[email protected]640517f2008-10-30 23:54:04384bool PathExists(const FilePath& path) {
[email protected]ba74b0d22010-10-23 05:19:20385 base::ThreadRestrictions::AssertIOAllowed();
[email protected]ef944e052010-05-17 15:01:22386 return access(path.value().c_str(), F_OK) == 0;
[email protected]b2e97292008-09-02 18:20:34387}
388
[email protected]7e1fde6a2008-12-23 20:20:10389bool PathIsWritable(const FilePath& path) {
[email protected]ba74b0d22010-10-23 05:19:20390 base::ThreadRestrictions::AssertIOAllowed();
[email protected]ef944e052010-05-17 15:01:22391 return access(path.value().c_str(), W_OK) == 0;
[email protected]7e1fde6a2008-12-23 20:20:10392}
393
[email protected]640517f2008-10-30 23:54:04394bool DirectoryExists(const FilePath& path) {
[email protected]ba74b0d22010-10-23 05:19:20395 base::ThreadRestrictions::AssertIOAllowed();
[email protected]fb66f9d2009-09-07 16:39:46396 stat_wrapper_t file_info;
397 if (CallStat(path.value().c_str(), &file_info) == 0)
[email protected]806b9c62008-09-11 16:09:11398 return S_ISDIR(file_info.st_mode);
399 return false;
400}
401
[email protected]b2e97292008-09-02 18:20:34402// TODO(erikkay): implement
403#if 0
404bool GetFileCreationLocalTimeFromHandle(int fd,
405 LPSYSTEMTIME creation_time) {
406 if (!file_handle)
407 return false;
[email protected]9e51af92009-02-04 00:58:39408
[email protected]b2e97292008-09-02 18:20:34409 FILETIME utc_filetime;
410 if (!GetFileTime(file_handle, &utc_filetime, NULL, NULL))
411 return false;
[email protected]9e51af92009-02-04 00:58:39412
[email protected]b2e97292008-09-02 18:20:34413 FILETIME local_filetime;
414 if (!FileTimeToLocalFileTime(&utc_filetime, &local_filetime))
415 return false;
[email protected]9e51af92009-02-04 00:58:39416
[email protected]b2e97292008-09-02 18:20:34417 return !!FileTimeToSystemTime(&local_filetime, creation_time);
418}
419
420bool GetFileCreationLocalTime(const std::string& filename,
421 LPSYSTEMTIME creation_time) {
422 ScopedHandle file_handle(
[email protected]9e51af92009-02-04 00:58:39423 CreateFile(filename.c_str(), GENERIC_READ,
[email protected]b2e97292008-09-02 18:20:34424 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
425 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
426 return GetFileCreationLocalTimeFromHandle(file_handle.Get(), creation_time);
427}
428#endif
429
[email protected]45301492009-04-23 12:38:08430bool ReadFromFD(int fd, char* buffer, size_t bytes) {
431 size_t total_read = 0;
432 while (total_read < bytes) {
[email protected]157c61b2009-05-01 21:37:31433 ssize_t bytes_read =
434 HANDLE_EINTR(read(fd, buffer + total_read, bytes - total_read));
435 if (bytes_read <= 0)
[email protected]45301492009-04-23 12:38:08436 break;
[email protected]157c61b2009-05-01 21:37:31437 total_read += bytes_read;
[email protected]45301492009-04-23 12:38:08438 }
439 return total_read == bytes;
440}
441
[email protected]2e733d102010-11-30 00:43:37442bool CreateSymbolicLink(const FilePath& target_path,
443 const FilePath& symlink_path) {
444 DCHECK(!symlink_path.empty());
445 DCHECK(!target_path.empty());
446 return ::symlink(target_path.value().c_str(),
447 symlink_path.value().c_str()) != -1;
448}
449
450bool ReadSymbolicLink(const FilePath& symlink_path,
451 FilePath* target_path) {
452 DCHECK(!symlink_path.empty());
453 DCHECK(target_path);
454 char buf[PATH_MAX];
455 ssize_t count = ::readlink(symlink_path.value().c_str(), buf, arraysize(buf));
456
[email protected]723571a2010-12-03 17:37:54457 if (count <= 0) {
458 target_path->clear();
[email protected]2e733d102010-11-30 00:43:37459 return false;
[email protected]723571a2010-12-03 17:37:54460 }
[email protected]2e733d102010-11-30 00:43:37461
462 *target_path = FilePath(FilePath::StringType(buf, count));
[email protected]2e733d102010-11-30 00:43:37463 return true;
464}
465
[email protected]5085e442012-07-11 01:24:02466bool GetPosixFilePermissions(const FilePath& path, int* mode) {
467 base::ThreadRestrictions::AssertIOAllowed();
468 DCHECK(mode);
469
470 stat_wrapper_t file_info;
471 // Uses stat(), because on symbolic link, lstat() does not return valid
472 // permission bits in st_mode
473 if (CallStat(path.value().c_str(), &file_info) != 0)
474 return false;
475
476 *mode = file_info.st_mode & FILE_PERMISSION_MASK;
477 return true;
478}
479
480bool SetPosixFilePermissions(const FilePath& path,
481 int mode) {
482 base::ThreadRestrictions::AssertIOAllowed();
483 DCHECK((mode & ~FILE_PERMISSION_MASK) == 0);
484
485 // Calls stat() so that we can preserve the higher bits like S_ISGID.
486 stat_wrapper_t stat_buf;
487 if (CallStat(path.value().c_str(), &stat_buf) != 0)
488 return false;
489
490 // Clears the existing permission bits, and adds the new ones.
491 mode_t updated_mode_bits = stat_buf.st_mode & ~FILE_PERMISSION_MASK;
492 updated_mode_bits |= mode & FILE_PERMISSION_MASK;
493
494 if (HANDLE_EINTR(chmod(path.value().c_str(), updated_mode_bits)) != 0)
495 return false;
496
497 return true;
498}
499
[email protected]9e51af92009-02-04 00:58:39500// Creates and opens a temporary file in |directory|, returning the
[email protected]16eac0a72009-09-11 17:33:50501// file descriptor. |path| is set to the temporary file path.
502// This function does NOT unlink() the file.
[email protected]9e51af92009-02-04 00:58:39503int CreateAndOpenFdForTemporaryFile(FilePath directory, FilePath* path) {
[email protected]ba74b0d22010-10-23 05:19:20504 base::ThreadRestrictions::AssertIOAllowed(); // For call to mkstemp().
[email protected]151c4a62011-04-22 04:15:13505 *path = directory.Append(TempFileName());
[email protected]9e51af92009-02-04 00:58:39506 const std::string& tmpdir_string = path->value();
[email protected]778e8c52008-09-11 17:36:23507 // this should be OK since mkstemp just replaces characters in place
508 char* buffer = const_cast<char*>(tmpdir_string.c_str());
[email protected]392264c2008-11-11 00:01:38509
[email protected]b266ffea2011-04-12 06:07:25510 return HANDLE_EINTR(mkstemp(buffer));
[email protected]9e51af92009-02-04 00:58:39511}
512
[email protected]33edeab2009-08-18 16:07:55513bool CreateTemporaryFile(FilePath* path) {
[email protected]ba74b0d22010-10-23 05:19:20514 base::ThreadRestrictions::AssertIOAllowed(); // For call to close().
[email protected]9e51af92009-02-04 00:58:39515 FilePath directory;
516 if (!GetTempDir(&directory))
517 return false;
518 int fd = CreateAndOpenFdForTemporaryFile(directory, path);
[email protected]b2e97292008-09-02 18:20:34519 if (fd < 0)
520 return false;
[email protected]2e90bee2011-04-12 06:51:22521 ignore_result(HANDLE_EINTR(close(fd)));
[email protected]b2e97292008-09-02 18:20:34522 return true;
523}
524
[email protected]103dccfa2011-12-06 18:07:05525FILE* CreateAndOpenTemporaryShmemFile(FilePath* path, bool executable) {
[email protected]9e51af92009-02-04 00:58:39526 FilePath directory;
[email protected]103dccfa2011-12-06 18:07:05527 if (!GetShmemTempDir(&directory, executable))
[email protected]628476aa2010-06-10 22:56:23528 return NULL;
[email protected]9e51af92009-02-04 00:58:39529
[email protected]6faa0e0d2009-04-28 06:50:36530 return CreateAndOpenTemporaryFileInDir(directory, path);
531}
532
533FILE* CreateAndOpenTemporaryFileInDir(const FilePath& dir, FilePath* path) {
534 int fd = CreateAndOpenFdForTemporaryFile(dir, path);
[email protected]9e51af92009-02-04 00:58:39535 if (fd < 0)
536 return NULL;
537
[email protected]139063bd2011-04-18 19:05:53538 FILE* file = fdopen(fd, "a+");
539 if (!file)
540 ignore_result(HANDLE_EINTR(close(fd)));
541 return file;
[email protected]9e51af92009-02-04 00:58:39542}
[email protected]6445c402009-09-11 20:06:27543
544bool CreateTemporaryFileInDir(const FilePath& dir, FilePath* temp_file) {
[email protected]ba74b0d22010-10-23 05:19:20545 base::ThreadRestrictions::AssertIOAllowed(); // For call to close().
[email protected]6445c402009-09-11 20:06:27546 int fd = CreateAndOpenFdForTemporaryFile(dir, temp_file);
[email protected]b266ffea2011-04-12 06:07:25547 return ((fd >= 0) && !HANDLE_EINTR(close(fd)));
[email protected]9ccbb372008-10-10 18:50:32548}
549
[email protected]b0b3abd92010-04-30 17:00:09550static bool CreateTemporaryDirInDirImpl(const FilePath& base_dir,
551 const FilePath::StringType& name_tmpl,
552 FilePath* new_dir) {
[email protected]ba74b0d22010-10-23 05:19:20553 base::ThreadRestrictions::AssertIOAllowed(); // For call to mkdtemp().
[email protected]a42d4632011-10-26 21:48:00554 DCHECK(name_tmpl.find("XXXXXX") != FilePath::StringType::npos)
555 << "Directory name template must contain \"XXXXXX\".";
[email protected]b0b3abd92010-04-30 17:00:09556
557 FilePath sub_dir = base_dir.Append(name_tmpl);
558 std::string sub_dir_string = sub_dir.value();
559
560 // this should be OK since mkdtemp just replaces characters in place
561 char* buffer = const_cast<char*>(sub_dir_string.c_str());
562 char* dtemp = mkdtemp(buffer);
[email protected]3ad035d22010-07-28 21:00:51563 if (!dtemp) {
564 DPLOG(ERROR) << "mkdtemp";
[email protected]b0b3abd92010-04-30 17:00:09565 return false;
[email protected]3ad035d22010-07-28 21:00:51566 }
[email protected]b0b3abd92010-04-30 17:00:09567 *new_dir = FilePath(dtemp);
568 return true;
569}
570
571bool CreateTemporaryDirInDir(const FilePath& base_dir,
572 const FilePath::StringType& prefix,
[email protected]046062e82010-06-30 07:19:11573 FilePath* new_dir) {
[email protected]b0b3abd92010-04-30 17:00:09574 FilePath::StringType mkdtemp_template = prefix;
575 mkdtemp_template.append(FILE_PATH_LITERAL("XXXXXX"));
576 return CreateTemporaryDirInDirImpl(base_dir, mkdtemp_template, new_dir);
577}
578
[email protected]7e1fde6a2008-12-23 20:20:10579bool CreateNewTempDirectory(const FilePath::StringType& prefix,
580 FilePath* new_temp_path) {
[email protected]392264c2008-11-11 00:01:38581 FilePath tmpdir;
[email protected]b2e97292008-09-02 18:20:34582 if (!GetTempDir(&tmpdir))
583 return false;
[email protected]b0b3abd92010-04-30 17:00:09584
[email protected]151c4a62011-04-22 04:15:13585 return CreateTemporaryDirInDirImpl(tmpdir, TempFileName(), new_temp_path);
[email protected]b2e97292008-09-02 18:20:34586}
587
[email protected]640517f2008-10-30 23:54:04588bool CreateDirectory(const FilePath& full_path) {
[email protected]ba74b0d22010-10-23 05:19:20589 base::ThreadRestrictions::AssertIOAllowed(); // For call to mkdir().
[email protected]640517f2008-10-30 23:54:04590 std::vector<FilePath> subpaths;
591
592 // Collect a list of all parent directories.
593 FilePath last_path = full_path;
594 subpaths.push_back(full_path);
595 for (FilePath path = full_path.DirName();
596 path.value() != last_path.value(); path = path.DirName()) {
597 subpaths.push_back(path);
598 last_path = path;
599 }
600
601 // Iterate through the parents and create the missing ones.
602 for (std::vector<FilePath>::reverse_iterator i = subpaths.rbegin();
603 i != subpaths.rend(); ++i) {
[email protected]0ba86e42010-03-17 21:39:42604 if (DirectoryExists(*i))
605 continue;
606 if (mkdir(i->value().c_str(), 0700) == 0)
607 continue;
608 // Mkdir failed, but it might have failed with EEXIST, or some other error
609 // due to the the directory appearing out of thin air. This can occur if
610 // two processes are trying to create the same file system tree at the same
611 // time. Check to see if it exists and make sure it is a directory.
612 if (!DirectoryExists(*i))
613 return false;
[email protected]b2e97292008-09-02 18:20:34614 }
615 return true;
616}
617
[email protected]cd78ad52011-05-31 23:10:06618// TODO(rkc): Refactor GetFileInfo and FileEnumerator to handle symlinks
619// correctly. http://code.google.com/p/chromium-os/issues/detail?id=15948
620bool IsLink(const FilePath& file_path) {
[email protected]7122db22012-06-30 05:26:59621 stat_wrapper_t st;
[email protected]cd78ad52011-05-31 23:10:06622 // If we can't lstat the file, it's safe to assume that the file won't at
623 // least be a 'followable' link.
[email protected]7122db22012-06-30 05:26:59624 if (CallLstat(file_path.value().c_str(), &st) != 0)
[email protected]cd78ad52011-05-31 23:10:06625 return false;
626
627 if (S_ISLNK(st.st_mode))
628 return true;
629 else
630 return false;
631}
632
[email protected]2f0193c22010-09-03 02:28:37633bool GetFileInfo(const FilePath& file_path, base::PlatformFileInfo* results) {
[email protected]fb66f9d2009-09-07 16:39:46634 stat_wrapper_t file_info;
635 if (CallStat(file_path.value().c_str(), &file_info) != 0)
[email protected]b2e97292008-09-02 18:20:34636 return false;
[email protected]f5e3da4d2008-09-26 01:04:08637 results->is_directory = S_ISDIR(file_info.st_mode);
638 results->size = file_info.st_size;
[email protected]5ef323892009-07-24 16:13:53639 results->last_modified = base::Time::FromTimeT(file_info.st_mtime);
[email protected]2f0193c22010-09-03 02:28:37640 results->last_accessed = base::Time::FromTimeT(file_info.st_atime);
641 results->creation_time = base::Time::FromTimeT(file_info.st_ctime);
[email protected]b2e97292008-09-02 18:20:34642 return true;
643}
644
[email protected]825003f2009-05-14 17:49:23645bool GetInode(const FilePath& path, ino_t* inode) {
[email protected]ba74b0d22010-10-23 05:19:20646 base::ThreadRestrictions::AssertIOAllowed(); // For call to stat().
[email protected]825003f2009-05-14 17:49:23647 struct stat buffer;
648 int result = stat(path.value().c_str(), &buffer);
649 if (result < 0)
650 return false;
651
652 *inode = buffer.st_ino;
653 return true;
654}
655
[email protected]836f1342008-10-01 17:40:13656FILE* OpenFile(const std::string& filename, const char* mode) {
[email protected]a9cd2a652008-11-17 21:01:19657 return OpenFile(FilePath(filename), mode);
[email protected]836f1342008-10-01 17:40:13658}
659
[email protected]a9cd2a652008-11-17 21:01:19660FILE* OpenFile(const FilePath& filename, const char* mode) {
[email protected]ba74b0d22010-10-23 05:19:20661 base::ThreadRestrictions::AssertIOAllowed();
[email protected]b266ffea2011-04-12 06:07:25662 FILE* result = NULL;
663 do {
664 result = fopen(filename.value().c_str(), mode);
665 } while (!result && errno == EINTR);
666 return result;
[email protected]836f1342008-10-01 17:40:13667}
668
[email protected]c870c762009-01-28 05:47:15669int ReadFile(const FilePath& filename, char* data, int size) {
[email protected]ba74b0d22010-10-23 05:19:20670 base::ThreadRestrictions::AssertIOAllowed();
[email protected]b266ffea2011-04-12 06:07:25671 int fd = HANDLE_EINTR(open(filename.value().c_str(), O_RDONLY));
[email protected]b2e97292008-09-02 18:20:34672 if (fd < 0)
673 return -1;
[email protected]a9cd2a652008-11-17 21:01:19674
[email protected]cabe39c2010-02-02 02:28:16675 ssize_t bytes_read = HANDLE_EINTR(read(fd, data, size));
676 if (int ret = HANDLE_EINTR(close(fd)) < 0)
677 return ret;
678 return bytes_read;
[email protected]b2e97292008-09-02 18:20:34679}
680
[email protected]c870c762009-01-28 05:47:15681int WriteFile(const FilePath& filename, const char* data, int size) {
[email protected]ba74b0d22010-10-23 05:19:20682 base::ThreadRestrictions::AssertIOAllowed();
[email protected]b266ffea2011-04-12 06:07:25683 int fd = HANDLE_EINTR(creat(filename.value().c_str(), 0666));
[email protected]b2e97292008-09-02 18:20:34684 if (fd < 0)
685 return -1;
[email protected]778e8c52008-09-11 17:36:23686
[email protected]cabe39c2010-02-02 02:28:16687 int bytes_written = WriteFileDescriptor(fd, data, size);
688 if (int ret = HANDLE_EINTR(close(fd)) < 0)
689 return ret;
690 return bytes_written;
[email protected]fbea0232009-09-16 00:29:22691}
692
693int WriteFileDescriptor(const int fd, const char* data, int size) {
694 // Allow for partial writes.
695 ssize_t bytes_written_total = 0;
696 for (ssize_t bytes_written_partial = 0; bytes_written_total < size;
697 bytes_written_total += bytes_written_partial) {
698 bytes_written_partial =
699 HANDLE_EINTR(write(fd, data + bytes_written_total,
700 size - bytes_written_total));
701 if (bytes_written_partial < 0)
702 return -1;
703 }
704
[email protected]778e8c52008-09-11 17:36:23705 return bytes_written_total;
[email protected]b2e97292008-09-02 18:20:34706}
707
[email protected]891128f2012-04-29 12:57:10708int AppendToFile(const FilePath& filename, const char* data, int size) {
709 base::ThreadRestrictions::AssertIOAllowed();
710 int fd = HANDLE_EINTR(open(filename.value().c_str(), O_WRONLY | O_APPEND));
711 if (fd < 0)
712 return -1;
713
714 int bytes_written = WriteFileDescriptor(fd, data, size);
715 if (int ret = HANDLE_EINTR(close(fd)) < 0)
716 return ret;
717 return bytes_written;
718}
719
[email protected]b2e97292008-09-02 18:20:34720// Gets the current working directory for the process.
[email protected]640517f2008-10-30 23:54:04721bool GetCurrentDirectory(FilePath* dir) {
[email protected]ba74b0d22010-10-23 05:19:20722 // getcwd can return ENOENT, which implies it checks against the disk.
723 base::ThreadRestrictions::AssertIOAllowed();
724
[email protected]b2e97292008-09-02 18:20:34725 char system_buffer[PATH_MAX] = "";
[email protected]640517f2008-10-30 23:54:04726 if (!getcwd(system_buffer, sizeof(system_buffer))) {
727 NOTREACHED();
728 return false;
729 }
730 *dir = FilePath(system_buffer);
[email protected]b2e97292008-09-02 18:20:34731 return true;
732}
733
734// Sets the current working directory for the process.
[email protected]a9cd2a652008-11-17 21:01:19735bool SetCurrentDirectory(const FilePath& path) {
[email protected]ba74b0d22010-10-23 05:19:20736 base::ThreadRestrictions::AssertIOAllowed();
[email protected]a9cd2a652008-11-17 21:01:19737 int ret = chdir(path.value().c_str());
738 return !ret;
[email protected]b2e97292008-09-02 18:20:34739}
[email protected]a9cd2a652008-11-17 21:01:19740
[email protected]7856bb82008-12-12 23:43:03741///////////////////////////////////////////////
742// FileEnumerator
743
[email protected]0b733222008-12-11 14:55:12744FileEnumerator::FileEnumerator(const FilePath& root_path,
[email protected]b2e97292008-09-02 18:20:34745 bool recursive,
[email protected]58b7c5a62011-08-15 13:09:27746 FileType file_type)
[email protected]fbf745a2009-12-08 22:05:59747 : current_directory_entry_(0),
748 root_path_(root_path),
[email protected]49930c3a2009-08-06 21:23:07749 recursive_(recursive),
[email protected]a82026e2010-10-14 23:43:29750 file_type_(file_type) {
[email protected]8199b3a2009-06-09 05:57:38751 // INCLUDE_DOT_DOT must not be specified if recursive.
752 DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_)));
[email protected]b2e97292008-09-02 18:20:34753 pending_paths_.push(root_path);
754}
755
[email protected]0b733222008-12-11 14:55:12756FileEnumerator::FileEnumerator(const FilePath& root_path,
[email protected]b2e97292008-09-02 18:20:34757 bool recursive,
[email protected]58b7c5a62011-08-15 13:09:27758 FileType file_type,
[email protected]0b733222008-12-11 14:55:12759 const FilePath::StringType& pattern)
[email protected]fbf745a2009-12-08 22:05:59760 : current_directory_entry_(0),
761 root_path_(root_path),
[email protected]49930c3a2009-08-06 21:23:07762 recursive_(recursive),
[email protected]b2e97292008-09-02 18:20:34763 file_type_(file_type),
[email protected]a82026e2010-10-14 23:43:29764 pattern_(root_path.Append(pattern).value()) {
[email protected]8199b3a2009-06-09 05:57:38765 // INCLUDE_DOT_DOT must not be specified if recursive.
766 DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_)));
[email protected]49930c3a2009-08-06 21:23:07767 // The Windows version of this code appends the pattern to the root_path,
768 // potentially only matching against items in the top-most directory.
769 // Do the same here.
[email protected]f6b8ce32011-03-02 00:03:18770 if (pattern.empty())
[email protected]fbf745a2009-12-08 22:05:59771 pattern_ = FilePath::StringType();
[email protected]b2e97292008-09-02 18:20:34772 pending_paths_.push(root_path);
773}
[email protected]a9cd2a652008-11-17 21:01:19774
[email protected]b2e97292008-09-02 18:20:34775FileEnumerator::~FileEnumerator() {
[email protected]b2e97292008-09-02 18:20:34776}
777
[email protected]0b733222008-12-11 14:55:12778FilePath FileEnumerator::Next() {
[email protected]49930c3a2009-08-06 21:23:07779 ++current_directory_entry_;
780
781 // While we've exhausted the entries in the current directory, do the next
782 while (current_directory_entry_ >= directory_entries_.size()) {
[email protected]b2e97292008-09-02 18:20:34783 if (pending_paths_.empty())
[email protected]0b733222008-12-11 14:55:12784 return FilePath();
[email protected]13ef7c02008-11-20 22:30:13785
[email protected]b2e97292008-09-02 18:20:34786 root_path_ = pending_paths_.top();
[email protected]0b733222008-12-11 14:55:12787 root_path_ = root_path_.StripTrailingSeparators();
[email protected]b2e97292008-09-02 18:20:34788 pending_paths_.pop();
[email protected]13ef7c02008-11-20 22:30:13789
[email protected]49930c3a2009-08-06 21:23:07790 std::vector<DirectoryEntryInfo> entries;
791 if (!ReadDirectory(&entries, root_path_, file_type_ & SHOW_SYM_LINKS))
792 continue;
[email protected]13ef7c02008-11-20 22:30:13793
[email protected]49930c3a2009-08-06 21:23:07794 directory_entries_.clear();
795 current_directory_entry_ = 0;
796 for (std::vector<DirectoryEntryInfo>::const_iterator
797 i = entries.begin(); i != entries.end(); ++i) {
798 FilePath full_path = root_path_.Append(i->filename);
799 if (ShouldSkip(full_path))
800 continue;
[email protected]13ef7c02008-11-20 22:30:13801
[email protected]fbf745a2009-12-08 22:05:59802 if (pattern_.size() &&
803 fnmatch(pattern_.c_str(), full_path.value().c_str(), FNM_NOESCAPE))
[email protected]49930c3a2009-08-06 21:23:07804 continue;
805
806 if (recursive_ && S_ISDIR(i->stat.st_mode))
807 pending_paths_.push(full_path);
808
809 if ((S_ISDIR(i->stat.st_mode) && (file_type_ & DIRECTORIES)) ||
810 (!S_ISDIR(i->stat.st_mode) && (file_type_ & FILES)))
811 directory_entries_.push_back(*i);
[email protected]b2e97292008-09-02 18:20:34812 }
813 }
[email protected]13ef7c02008-11-20 22:30:13814
[email protected]49930c3a2009-08-06 21:23:07815 return root_path_.Append(directory_entries_[current_directory_entry_
816 ].filename);
817}
[email protected]8199b3a2009-06-09 05:57:38818
[email protected]eae9c062011-01-11 00:50:59819void FileEnumerator::GetFindInfo(FindInfo* info) {
820 DCHECK(info);
821
822 if (current_directory_entry_ >= directory_entries_.size())
823 return;
824
825 DirectoryEntryInfo* cur_entry = &directory_entries_[current_directory_entry_];
826 memcpy(&(info->stat), &(cur_entry->stat), sizeof(info->stat));
827 info->filename.assign(cur_entry->filename.value());
828}
829
[email protected]011352fdf2012-03-10 00:18:31830// static
[email protected]eae9c062011-01-11 00:50:59831bool FileEnumerator::IsDirectory(const FindInfo& info) {
832 return S_ISDIR(info.stat.st_mode);
833}
834
835// static
[email protected]011352fdf2012-03-10 00:18:31836bool FileEnumerator::IsLink(const FindInfo& info) {
837 return S_ISLNK(info.stat.st_mode);
838}
839
840// static
[email protected]eae9c062011-01-11 00:50:59841FilePath FileEnumerator::GetFilename(const FindInfo& find_info) {
842 return FilePath(find_info.filename);
843}
844
[email protected]f1ddaa42011-07-19 05:03:03845// static
846int64 FileEnumerator::GetFilesize(const FindInfo& find_info) {
847 return find_info.stat.st_size;
848}
849
850// static
851base::Time FileEnumerator::GetLastModifiedTime(const FindInfo& find_info) {
852 return base::Time::FromTimeT(find_info.stat.st_mtime);
853}
854
[email protected]49930c3a2009-08-06 21:23:07855bool FileEnumerator::ReadDirectory(std::vector<DirectoryEntryInfo>* entries,
856 const FilePath& source, bool show_links) {
[email protected]ba74b0d22010-10-23 05:19:20857 base::ThreadRestrictions::AssertIOAllowed();
[email protected]49930c3a2009-08-06 21:23:07858 DIR* dir = opendir(source.value().c_str());
859 if (!dir)
860 return false;
861
[email protected]e37e88a2011-11-15 00:06:16862#if !defined(OS_LINUX) && !defined(OS_MACOSX) && !defined(OS_BSD) && \
863 !defined(OS_SOLARIS) && !defined(OS_ANDROID)
[email protected]e43eddf12009-12-29 00:32:52864 #error Port warning: depending on the definition of struct dirent, \
865 additional space for pathname may be needed
[email protected]49930c3a2009-08-06 21:23:07866#endif
[email protected]e43eddf12009-12-29 00:32:52867
[email protected]49930c3a2009-08-06 21:23:07868 struct dirent dent_buf;
869 struct dirent* dent;
870 while (readdir_r(dir, &dent_buf, &dent) == 0 && dent) {
871 DirectoryEntryInfo info;
[email protected]49930c3a2009-08-06 21:23:07872 info.filename = FilePath(dent->d_name);
[email protected]2237f5d72009-09-03 22:39:34873
874 FilePath full_name = source.Append(dent->d_name);
875 int ret;
[email protected]49930c3a2009-08-06 21:23:07876 if (show_links)
[email protected]2237f5d72009-09-03 22:39:34877 ret = lstat(full_name.value().c_str(), &info.stat);
[email protected]49930c3a2009-08-06 21:23:07878 else
[email protected]2237f5d72009-09-03 22:39:34879 ret = stat(full_name.value().c_str(), &info.stat);
880 if (ret < 0) {
881 // Print the stat() error message unless it was ENOENT and we're
882 // following symlinks.
[email protected]e131cf52010-03-25 19:10:28883 if (!(errno == ENOENT && !show_links)) {
[email protected]a42d4632011-10-26 21:48:00884 DPLOG(ERROR) << "Couldn't stat "
885 << source.Append(dent->d_name).value();
[email protected]2237f5d72009-09-03 22:39:34886 }
[email protected]49930c3a2009-08-06 21:23:07887 memset(&info.stat, 0, sizeof(info.stat));
[email protected]8199b3a2009-06-09 05:57:38888 }
[email protected]49930c3a2009-08-06 21:23:07889 entries->push_back(info);
[email protected]b2e97292008-09-02 18:20:34890 }
[email protected]49930c3a2009-08-06 21:23:07891
892 closedir(dir);
893 return true;
894}
895
[email protected]7856bb82008-12-12 23:43:03896///////////////////////////////////////////////
897// MemoryMappedFile
898
899MemoryMappedFile::MemoryMappedFile()
[email protected]cb6037d2009-11-16 22:55:17900 : file_(base::kInvalidPlatformFileValue),
901 data_(NULL),
[email protected]7856bb82008-12-12 23:43:03902 length_(0) {
903}
904
[email protected]85c55dc2009-11-06 03:05:46905bool MemoryMappedFile::MapFileToMemoryInternal() {
[email protected]ba74b0d22010-10-23 05:19:20906 base::ThreadRestrictions::AssertIOAllowed();
907
[email protected]7856bb82008-12-12 23:43:03908 struct stat file_stat;
[email protected]cb6037d2009-11-16 22:55:17909 if (fstat(file_, &file_stat) == base::kInvalidPlatformFileValue) {
[email protected]a42d4632011-10-26 21:48:00910 DLOG(ERROR) << "Couldn't fstat " << file_ << ", errno " << errno;
[email protected]7856bb82008-12-12 23:43:03911 return false;
[email protected]4883a4e2009-06-06 19:59:36912 }
[email protected]7856bb82008-12-12 23:43:03913 length_ = file_stat.st_size;
914
915 data_ = static_cast<uint8*>(
[email protected]cb6037d2009-11-16 22:55:17916 mmap(NULL, length_, PROT_READ, MAP_SHARED, file_, 0));
[email protected]7856bb82008-12-12 23:43:03917 if (data_ == MAP_FAILED)
[email protected]a42d4632011-10-26 21:48:00918 DLOG(ERROR) << "Couldn't mmap " << file_ << ", errno " << errno;
[email protected]4883a4e2009-06-06 19:59:36919
920 return data_ != MAP_FAILED;
[email protected]7856bb82008-12-12 23:43:03921}
922
923void MemoryMappedFile::CloseHandles() {
[email protected]ba74b0d22010-10-23 05:19:20924 base::ThreadRestrictions::AssertIOAllowed();
925
[email protected]7856bb82008-12-12 23:43:03926 if (data_ != NULL)
927 munmap(data_, length_);
[email protected]cb6037d2009-11-16 22:55:17928 if (file_ != base::kInvalidPlatformFileValue)
[email protected]2e90bee2011-04-12 06:51:22929 ignore_result(HANDLE_EINTR(close(file_)));
[email protected]7856bb82008-12-12 23:43:03930
931 data_ = NULL;
932 length_ = 0;
[email protected]cb6037d2009-11-16 22:55:17933 file_ = base::kInvalidPlatformFileValue;
[email protected]7856bb82008-12-12 23:43:03934}
[email protected]13ef7c02008-11-20 22:30:13935
[email protected]35b9be02009-11-26 00:37:06936bool HasFileBeenModifiedSince(const FileEnumerator::FindInfo& find_info,
937 const base::Time& cutoff_time) {
[email protected]e9ad4352010-11-17 11:19:15938 return static_cast<time_t>(find_info.stat.st_mtime) >= cutoff_time.ToTimeT();
[email protected]35b9be02009-11-26 00:37:06939}
940
[email protected]6f5f4322010-06-09 22:56:48941bool NormalizeFilePath(const FilePath& path, FilePath* normalized_path) {
942 FilePath real_path_result;
943 if (!RealPath(path, &real_path_result))
[email protected]01e2a1f2010-05-12 15:13:57944 return false;
945
[email protected]6f5f4322010-06-09 22:56:48946 // To be consistant with windows, fail if |real_path_result| is a
947 // directory.
948 stat_wrapper_t file_info;
949 if (CallStat(real_path_result.value().c_str(), &file_info) != 0 ||
950 S_ISDIR(file_info.st_mode))
951 return false;
952
953 *normalized_path = real_path_result;
[email protected]01e2a1f2010-05-12 15:13:57954 return true;
955}
956
[email protected]84cb1912010-04-21 21:11:36957#if !defined(OS_MACOSX)
958bool GetTempDir(FilePath* path) {
959 const char* tmp = getenv("TMPDIR");
960 if (tmp)
961 *path = FilePath(tmp);
962 else
[email protected]f7d69972011-06-21 22:34:50963#if defined(OS_ANDROID)
[email protected]0eae7eb2012-05-17 20:09:06964 return PathService::Get(base::DIR_CACHE, path);
[email protected]f7d69972011-06-21 22:34:50965#else
[email protected]84cb1912010-04-21 21:11:36966 *path = FilePath("/tmp");
[email protected]f7d69972011-06-21 22:34:50967#endif
[email protected]84cb1912010-04-21 21:11:36968 return true;
969}
970
[email protected]f7d69972011-06-21 22:34:50971#if !defined(OS_ANDROID)
[email protected]103dccfa2011-12-06 18:07:05972
[email protected]167ec822011-10-24 22:05:27973#if defined(OS_LINUX)
[email protected]103dccfa2011-12-06 18:07:05974// Determine if /dev/shm files can be mapped and then mprotect'd PROT_EXEC.
975// This depends on the mount options used for /dev/shm, which vary among
976// different Linux distributions and possibly local configuration. It also
977// depends on details of kernel--ChromeOS uses the noexec option for /dev/shm
978// but its kernel allows mprotect with PROT_EXEC anyway.
979
980namespace {
981
982bool DetermineDevShmExecutable() {
983 bool result = false;
984 FilePath path;
985 int fd = CreateAndOpenFdForTemporaryFile(FilePath("/dev/shm"), &path);
986 if (fd >= 0) {
987 ScopedFD shm_fd_closer(&fd);
988 Delete(path, false);
[email protected]37e77e02011-12-22 22:31:44989 long sysconf_result = sysconf(_SC_PAGESIZE);
990 CHECK_GE(sysconf_result, 0);
991 size_t pagesize = static_cast<size_t>(sysconf_result);
992 CHECK_GE(sizeof(pagesize), sizeof(sysconf_result));
[email protected]103dccfa2011-12-06 18:07:05993 void *mapping = mmap(NULL, pagesize, PROT_READ, MAP_SHARED, fd, 0);
994 if (mapping != MAP_FAILED) {
995 if (mprotect(mapping, pagesize, PROT_READ | PROT_EXEC) == 0)
996 result = true;
997 munmap(mapping, pagesize);
998 }
999 }
1000 return result;
[email protected]84cb1912010-04-21 21:11:361001}
[email protected]103dccfa2011-12-06 18:07:051002
1003}; // namespace
1004#endif // defined(OS_LINUX)
1005
1006bool GetShmemTempDir(FilePath* path, bool executable) {
1007#if defined(OS_LINUX)
1008 bool use_dev_shm = true;
1009 if (executable) {
1010 static const bool s_dev_shm_executable = DetermineDevShmExecutable();
1011 use_dev_shm = s_dev_shm_executable;
1012 }
1013 if (use_dev_shm) {
1014 *path = FilePath("/dev/shm");
1015 return true;
1016 }
[email protected]f7d69972011-06-21 22:34:501017#endif
[email protected]103dccfa2011-12-06 18:07:051018 return GetTempDir(path);
1019}
1020#endif // !defined(OS_ANDROID)
[email protected]84cb1912010-04-21 21:11:361021
[email protected]1c657852010-04-22 23:28:051022FilePath GetHomeDir() {
[email protected]774727282012-08-06 09:14:441023#if defined(OS_CHROMEOS)
1024 if (base::chromeos::IsRunningOnChromeOS())
1025 return FilePath("/home/chronos/user");
1026#endif
1027
[email protected]1c657852010-04-22 23:28:051028 const char* home_dir = getenv("HOME");
1029 if (home_dir && home_dir[0])
1030 return FilePath(home_dir);
1031
[email protected]f7d69972011-06-21 22:34:501032#if defined(OS_ANDROID)
[email protected]a42d4632011-10-26 21:48:001033 DLOG(WARNING) << "OS_ANDROID: Home directory lookup not yet implemented.";
[email protected]f7d69972011-06-21 22:34:501034#else
[email protected]ba74b0d22010-10-23 05:19:201035 // g_get_home_dir calls getpwent, which can fall through to LDAP calls.
1036 base::ThreadRestrictions::AssertIOAllowed();
1037
[email protected]1c657852010-04-22 23:28:051038 home_dir = g_get_home_dir();
1039 if (home_dir && home_dir[0])
1040 return FilePath(home_dir);
[email protected]f7d69972011-06-21 22:34:501041#endif
[email protected]1c657852010-04-22 23:28:051042
1043 FilePath rv;
1044 if (file_util::GetTempDir(&rv))
1045 return rv;
1046
1047 // Last resort.
1048 return FilePath("/tmp");
1049}
1050
[email protected]84cb1912010-04-21 21:11:361051bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
[email protected]ba74b0d22010-10-23 05:19:201052 base::ThreadRestrictions::AssertIOAllowed();
[email protected]b266ffea2011-04-12 06:07:251053 int infile = HANDLE_EINTR(open(from_path.value().c_str(), O_RDONLY));
[email protected]84cb1912010-04-21 21:11:361054 if (infile < 0)
1055 return false;
1056
[email protected]b266ffea2011-04-12 06:07:251057 int outfile = HANDLE_EINTR(creat(to_path.value().c_str(), 0666));
[email protected]84cb1912010-04-21 21:11:361058 if (outfile < 0) {
[email protected]2e90bee2011-04-12 06:51:221059 ignore_result(HANDLE_EINTR(close(infile)));
[email protected]84cb1912010-04-21 21:11:361060 return false;
1061 }
1062
1063 const size_t kBufferSize = 32768;
1064 std::vector<char> buffer(kBufferSize);
1065 bool result = true;
1066
1067 while (result) {
1068 ssize_t bytes_read = HANDLE_EINTR(read(infile, &buffer[0], buffer.size()));
1069 if (bytes_read < 0) {
1070 result = false;
1071 break;
1072 }
1073 if (bytes_read == 0)
1074 break;
1075 // Allow for partial writes
1076 ssize_t bytes_written_per_read = 0;
1077 do {
1078 ssize_t bytes_written_partial = HANDLE_EINTR(write(
1079 outfile,
1080 &buffer[bytes_written_per_read],
1081 bytes_read - bytes_written_per_read));
1082 if (bytes_written_partial < 0) {
1083 result = false;
1084 break;
1085 }
1086 bytes_written_per_read += bytes_written_partial;
1087 } while (bytes_written_per_read < bytes_read);
1088 }
1089
1090 if (HANDLE_EINTR(close(infile)) < 0)
1091 result = false;
1092 if (HANDLE_EINTR(close(outfile)) < 0)
1093 result = false;
1094
1095 return result;
1096}
[email protected]92e44ae0a2012-07-23 08:22:441097#endif // !defined(OS_MACOSX)
[email protected]84cb1912010-04-21 21:11:361098
[email protected]73e4c362011-09-22 14:47:181099bool VerifyPathControlledByUser(const FilePath& base,
1100 const FilePath& path,
1101 uid_t owner_uid,
[email protected]7312f42a2011-10-17 21:30:291102 const std::set<gid_t>& group_gids) {
[email protected]73e4c362011-09-22 14:47:181103 if (base != path && !base.IsParent(path)) {
[email protected]a42d4632011-10-26 21:48:001104 DLOG(ERROR) << "|base| must be a subdirectory of |path|. base = \""
1105 << base.value() << "\", path = \"" << path.value() << "\"";
[email protected]73e4c362011-09-22 14:47:181106 return false;
1107 }
1108
1109 std::vector<FilePath::StringType> base_components;
1110 std::vector<FilePath::StringType> path_components;
1111
1112 base.GetComponents(&base_components);
1113 path.GetComponents(&path_components);
1114
1115 std::vector<FilePath::StringType>::const_iterator ib, ip;
1116 for (ib = base_components.begin(), ip = path_components.begin();
1117 ib != base_components.end(); ++ib, ++ip) {
1118 // |base| must be a subpath of |path|, so all components should match.
1119 // If these CHECKs fail, look at the test that base is a parent of
1120 // path at the top of this function.
[email protected]a42d4632011-10-26 21:48:001121 DCHECK(ip != path_components.end());
1122 DCHECK(*ip == *ib);
[email protected]73e4c362011-09-22 14:47:181123 }
1124
1125 FilePath current_path = base;
[email protected]7312f42a2011-10-17 21:30:291126 if (!VerifySpecificPathControlledByUser(current_path, owner_uid, group_gids))
[email protected]73e4c362011-09-22 14:47:181127 return false;
1128
1129 for (; ip != path_components.end(); ++ip) {
1130 current_path = current_path.Append(*ip);
[email protected]7312f42a2011-10-17 21:30:291131 if (!VerifySpecificPathControlledByUser(
1132 current_path, owner_uid, group_gids))
[email protected]73e4c362011-09-22 14:47:181133 return false;
1134 }
1135 return true;
1136}
1137
[email protected]4bd46792012-07-09 14:40:391138#if defined(OS_MACOSX) && !defined(OS_IOS)
[email protected]73e4c362011-09-22 14:47:181139bool VerifyPathControlledByAdmin(const FilePath& path) {
1140 const unsigned kRootUid = 0;
1141 const FilePath kFileSystemRoot("/");
1142
1143 // The name of the administrator group on mac os.
[email protected]7312f42a2011-10-17 21:30:291144 const char* const kAdminGroupNames[] = {
1145 "admin",
1146 "wheel"
1147 };
[email protected]73e4c362011-09-22 14:47:181148
1149 // Reading the groups database may touch the file system.
1150 base::ThreadRestrictions::AssertIOAllowed();
1151
[email protected]7312f42a2011-10-17 21:30:291152 std::set<gid_t> allowed_group_ids;
1153 for (int i = 0, ie = arraysize(kAdminGroupNames); i < ie; ++i) {
1154 struct group *group_record = getgrnam(kAdminGroupNames[i]);
1155 if (!group_record) {
[email protected]a42d4632011-10-26 21:48:001156 DPLOG(ERROR) << "Could not get the group ID of group \""
1157 << kAdminGroupNames[i] << "\".";
[email protected]7312f42a2011-10-17 21:30:291158 continue;
1159 }
1160
1161 allowed_group_ids.insert(group_record->gr_gid);
[email protected]73e4c362011-09-22 14:47:181162 }
1163
1164 return VerifyPathControlledByUser(
[email protected]7312f42a2011-10-17 21:30:291165 kFileSystemRoot, path, kRootUid, allowed_group_ids);
[email protected]73e4c362011-09-22 14:47:181166}
[email protected]eba29932012-07-24 11:23:321167#endif // defined(OS_MACOSX) && !defined(OS_IOS)
[email protected]73e4c362011-09-22 14:47:181168
[email protected]33e585a2010-11-20 03:38:151169} // namespace file_util