blob: 4d9cf42080edd90ddc793b43fa1f924f0674f994 [file] [log] [blame]
[email protected]ec3d1452010-02-18 10:02:261// Copyright (c) 2010 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]1c657852010-04-22 23:28:0527#else
28#include <glib.h>
[email protected]3224dcd2009-09-16 17:31:2529#endif
30
[email protected]b2e97292008-09-02 18:20:3431#include <fstream>
32
33#include "base/basictypes.h"
[email protected]157c61b2009-05-01 21:37:3134#include "base/eintr_wrapper.h"
[email protected]640517f2008-10-30 23:54:0435#include "base/file_path.h"
[email protected]807bc042009-07-15 01:32:0236#include "base/lock.h"
[email protected]b2e97292008-09-02 18:20:3437#include "base/logging.h"
[email protected]807bc042009-07-15 01:32:0238#include "base/scoped_ptr.h"
39#include "base/singleton.h"
[email protected]b2e97292008-09-02 18:20:3440#include "base/string_util.h"
[email protected]807bc042009-07-15 01:32:0241#include "base/sys_string_conversions.h"
[email protected]4b7743de2009-04-21 01:50:3942#include "base/time.h"
[email protected]047a03f2009-10-07 02:10:2043#include "base/utf_string_conversions.h"
[email protected]172c5502009-06-24 03:29:2644
[email protected]b2e97292008-09-02 18:20:3445namespace file_util {
46
[email protected]6f5f4322010-06-09 22:56:4847namespace {
48
49// Helper for NormalizeFilePath(), defined below.
50bool RealPath(const FilePath& path, FilePath* real_path) {
51 FilePath::CharType buf[PATH_MAX];
52 if (!realpath(path.value().c_str(), buf))
53 return false;
54
55 *real_path = FilePath(buf);
56 return true;
57}
58
59} // namespace
60
[email protected]66700d42010-03-10 07:46:4361#if defined(OS_OPENBSD) || defined(OS_FREEBSD) || \
[email protected]3224dcd2009-09-16 17:31:2562 (defined(OS_MACOSX) && \
63 MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5)
[email protected]fb66f9d2009-09-07 16:39:4664typedef struct stat stat_wrapper_t;
65static int CallStat(const char *path, stat_wrapper_t *sb) {
66 return stat(path, sb);
67}
68#else
69typedef struct stat64 stat_wrapper_t;
70static int CallStat(const char *path, stat_wrapper_t *sb) {
71 return stat64(path, sb);
72}
73#endif
74
75
[email protected]22a087f2009-03-17 19:17:4376#if defined(GOOGLE_CHROME_BUILD)
[email protected]390433f2010-06-10 17:11:2977static const char* kTempFileName = ".com.google.chrome.XXXXXX";
[email protected]22a087f2009-03-17 19:17:4378#else
[email protected]390433f2010-06-10 17:11:2979static const char* kTempFileName = ".org.chromium.XXXXXX";
[email protected]22a087f2009-03-17 19:17:4380#endif
[email protected]778e8c52008-09-11 17:36:2381
[email protected]640517f2008-10-30 23:54:0482bool AbsolutePath(FilePath* path) {
[email protected]b2e97292008-09-02 18:20:3483 char full_path[PATH_MAX];
[email protected]640517f2008-10-30 23:54:0484 if (realpath(path->value().c_str(), full_path) == NULL)
[email protected]b2e97292008-09-02 18:20:3485 return false;
[email protected]640517f2008-10-30 23:54:0486 *path = FilePath(full_path);
[email protected]b2e97292008-09-02 18:20:3487 return true;
88}
89
[email protected]4b7743de2009-04-21 01:50:3990int CountFilesCreatedAfter(const FilePath& path,
91 const base::Time& comparison_time) {
92 int file_count = 0;
93
94 DIR* dir = opendir(path.value().c_str());
95 if (dir) {
[email protected]8d578822010-01-25 23:54:5496#if !defined(OS_LINUX) && !defined(OS_MACOSX) && !defined(OS_FREEBSD) && \
[email protected]b5c72b822010-02-18 16:11:3797 !defined(OS_OPENBSD) && !defined(OS_SOLARIS)
[email protected]e43eddf12009-12-29 00:32:5298 #error Port warning: depending on the definition of struct dirent, \
99 additional space for pathname may be needed
[email protected]49930c3a2009-08-06 21:23:07100#endif
[email protected]2126577b2009-04-23 15:05:19101 struct dirent ent_buf;
[email protected]4b7743de2009-04-21 01:50:39102 struct dirent* ent;
[email protected]2126577b2009-04-23 15:05:19103 while (readdir_r(dir, &ent_buf, &ent) == 0 && ent) {
[email protected]4b7743de2009-04-21 01:50:39104 if ((strcmp(ent->d_name, ".") == 0) ||
105 (strcmp(ent->d_name, "..") == 0))
106 continue;
107
[email protected]fb66f9d2009-09-07 16:39:46108 stat_wrapper_t st;
109 int test = CallStat(path.Append(ent->d_name).value().c_str(), &st);
[email protected]4b7743de2009-04-21 01:50:39110 if (test != 0) {
[email protected]57b765672009-10-13 18:27:40111 PLOG(ERROR) << "stat64 failed";
[email protected]4b7743de2009-04-21 01:50:39112 continue;
113 }
[email protected]2126577b2009-04-23 15:05:19114 // Here, we use Time::TimeT(), which discards microseconds. This
115 // means that files which are newer than |comparison_time| may
116 // be considered older. If we don't discard microseconds, it
117 // introduces another issue. Suppose the following case:
118 //
119 // 1. Get |comparison_time| by Time::Now() and the value is 10.1 (secs).
120 // 2. Create a file and the current time is 10.3 (secs).
121 //
122 // As POSIX doesn't have microsecond precision for |st_ctime|,
123 // the creation time of the file created in the step 2 is 10 and
124 // the file is considered older than |comparison_time|. After
125 // all, we may have to accept either of the two issues: 1. files
126 // which are older than |comparison_time| are considered newer
127 // (current implementation) 2. files newer than
128 // |comparison_time| are considered older.
[email protected]4b7743de2009-04-21 01:50:39129 if (st.st_ctime >= comparison_time.ToTimeT())
130 ++file_count;
131 }
132 closedir(dir);
133 }
134 return file_count;
135}
136
[email protected]b2e97292008-09-02 18:20:34137// TODO(erikkay): The Windows version of this accepts paths like "foo/bar/*"
138// which works both with and without the recursive flag. I'm not sure we need
139// that functionality. If not, remove from file_util_win.cc, otherwise add it
140// here.
[email protected]640517f2008-10-30 23:54:04141bool Delete(const FilePath& path, bool recursive) {
142 const char* path_str = path.value().c_str();
[email protected]fb66f9d2009-09-07 16:39:46143 stat_wrapper_t file_info;
144 int test = CallStat(path_str, &file_info);
[email protected]b2e97292008-09-02 18:20:34145 if (test != 0) {
146 // The Windows version defines this condition as success.
[email protected]9e51af92009-02-04 00:58:39147 bool ret = (errno == ENOENT || errno == ENOTDIR);
[email protected]b2e97292008-09-02 18:20:34148 return ret;
149 }
150 if (!S_ISDIR(file_info.st_mode))
[email protected]640517f2008-10-30 23:54:04151 return (unlink(path_str) == 0);
[email protected]b2e97292008-09-02 18:20:34152 if (!recursive)
[email protected]640517f2008-10-30 23:54:04153 return (rmdir(path_str) == 0);
[email protected]b2e97292008-09-02 18:20:34154
155 bool success = true;
[email protected]49930c3a2009-08-06 21:23:07156 std::stack<std::string> directories;
157 directories.push(path.value());
158 FileEnumerator traversal(path, true, static_cast<FileEnumerator::FILE_TYPE>(
159 FileEnumerator::FILES | FileEnumerator::DIRECTORIES |
160 FileEnumerator::SHOW_SYM_LINKS));
161 for (FilePath current = traversal.Next(); success && !current.empty();
162 current = traversal.Next()) {
163 FileEnumerator::FindInfo info;
164 traversal.GetFindInfo(&info);
165
166 if (S_ISDIR(info.stat.st_mode))
167 directories.push(current.value());
168 else
169 success = (unlink(current.value().c_str()) == 0);
[email protected]21dec3872008-09-18 19:15:54170 }
[email protected]49930c3a2009-08-06 21:23:07171
172 while (success && !directories.empty()) {
173 FilePath dir = FilePath(directories.top());
174 directories.pop();
175 success = (rmdir(dir.value().c_str()) == 0);
[email protected]b2e97292008-09-02 18:20:34176 }
[email protected]a0546e82010-06-11 17:44:38177#if defined(OS_CHROMEOS)
178 sync();
179#endif
[email protected]b2e97292008-09-02 18:20:34180 return success;
181}
182
[email protected]640517f2008-10-30 23:54:04183bool Move(const FilePath& from_path, const FilePath& to_path) {
[email protected]bc6a9012009-10-15 01:11:44184 // Windows compatibility: if to_path exists, from_path and to_path
185 // must be the same type, either both files, or both directories.
186 stat_wrapper_t to_file_info;
187 if (CallStat(to_path.value().c_str(), &to_file_info) == 0) {
188 stat_wrapper_t from_file_info;
189 if (CallStat(from_path.value().c_str(), &from_file_info) == 0) {
190 if (S_ISDIR(to_file_info.st_mode) != S_ISDIR(from_file_info.st_mode))
191 return false;
192 } else {
193 return false;
194 }
195 }
196
[email protected]cc7948a2009-03-13 20:01:43197 if (rename(from_path.value().c_str(), to_path.value().c_str()) == 0)
198 return true;
199
200 if (!CopyDirectory(from_path, to_path, true))
201 return false;
202
203 Delete(from_path, true);
204 return true;
[email protected]b2e97292008-09-02 18:20:34205}
206
[email protected]c5866dca2009-05-19 17:21:07207bool ReplaceFile(const FilePath& from_path, const FilePath& to_path) {
208 return (rename(from_path.value().c_str(), to_path.value().c_str()) == 0);
209}
210
[email protected]640517f2008-10-30 23:54:04211bool CopyDirectory(const FilePath& from_path,
212 const FilePath& to_path,
[email protected]21dec3872008-09-18 19:15:54213 bool recursive) {
[email protected]21dec3872008-09-18 19:15:54214 // Some old callers of CopyDirectory want it to support wildcards.
215 // After some discussion, we decided to fix those callers.
216 // Break loudly here if anyone tries to do this.
217 // TODO(evanm): remove this once we're sure it's ok.
[email protected]640517f2008-10-30 23:54:04218 DCHECK(to_path.value().find('*') == std::string::npos);
219 DCHECK(from_path.value().find('*') == std::string::npos);
[email protected]21dec3872008-09-18 19:15:54220
221 char top_dir[PATH_MAX];
[email protected]640517f2008-10-30 23:54:04222 if (base::strlcpy(top_dir, from_path.value().c_str(),
[email protected]21dec3872008-09-18 19:15:54223 arraysize(top_dir)) >= arraysize(top_dir)) {
224 return false;
225 }
226
[email protected]49930c3a2009-08-06 21:23:07227 // This function does not properly handle destinations within the source
228 FilePath real_to_path = to_path;
229 if (PathExists(real_to_path)) {
230 if (!AbsolutePath(&real_to_path))
231 return false;
232 } else {
233 real_to_path = real_to_path.DirName();
234 if (!AbsolutePath(&real_to_path))
235 return false;
236 }
237 FilePath real_from_path = from_path;
238 if (!AbsolutePath(&real_from_path))
[email protected]21dec3872008-09-18 19:15:54239 return false;
[email protected]49930c3a2009-08-06 21:23:07240 if (real_to_path.value().size() >= real_from_path.value().size() &&
241 real_to_path.value().compare(0, real_from_path.value().size(),
242 real_from_path.value()) == 0)
243 return false;
244
245 bool success = true;
246 FileEnumerator::FILE_TYPE traverse_type =
247 static_cast<FileEnumerator::FILE_TYPE>(FileEnumerator::FILES |
248 FileEnumerator::SHOW_SYM_LINKS);
249 if (recursive)
250 traverse_type = static_cast<FileEnumerator::FILE_TYPE>(
251 traverse_type | FileEnumerator::DIRECTORIES);
252 FileEnumerator traversal(from_path, recursive, traverse_type);
253
[email protected]abbc5732009-10-13 17:57:27254 // We have to mimic windows behavior here. |to_path| may not exist yet,
[email protected]bc6a9012009-10-15 01:11:44255 // start the loop with |to_path|.
[email protected]49930c3a2009-08-06 21:23:07256 FileEnumerator::FindInfo info;
257 FilePath current = from_path;
258 if (stat(from_path.value().c_str(), &info.stat) < 0) {
259 LOG(ERROR) << "CopyDirectory() couldn't stat source directory: " <<
260 from_path.value() << " errno = " << errno;
261 success = false;
[email protected]21dec3872008-09-18 19:15:54262 }
[email protected]bc6a9012009-10-15 01:11:44263 struct stat to_path_stat;
264 FilePath from_path_base = from_path;
265 if (recursive && stat(to_path.value().c_str(), &to_path_stat) == 0 &&
266 S_ISDIR(to_path_stat.st_mode)) {
267 // If the destination already exists and is a directory, then the
268 // top level of source needs to be copied.
269 from_path_base = from_path.DirName();
270 }
271
272 // The Windows version of this function assumes that non-recursive calls
273 // will always have a directory for from_path.
274 DCHECK(recursive || S_ISDIR(info.stat.st_mode));
[email protected]21dec3872008-09-18 19:15:54275
[email protected]49930c3a2009-08-06 21:23:07276 while (success && !current.empty()) {
277 // current is the source path, including from_path, so paste
[email protected]21dec3872008-09-18 19:15:54278 // the suffix after from_path onto to_path to create the target_path.
[email protected]abbc5732009-10-13 17:57:27279 std::string suffix(&current.value().c_str()[from_path_base.value().size()]);
[email protected]ca0209612009-01-13 18:57:46280 // Strip the leading '/' (if any).
281 if (!suffix.empty()) {
[email protected]6ae340f2009-03-06 09:56:28282 DCHECK_EQ('/', suffix[0]);
[email protected]ca0209612009-01-13 18:57:46283 suffix.erase(0, 1);
284 }
285 const FilePath target_path = to_path.Append(suffix);
[email protected]21dec3872008-09-18 19:15:54286
[email protected]49930c3a2009-08-06 21:23:07287 if (S_ISDIR(info.stat.st_mode)) {
288 if (mkdir(target_path.value().c_str(), info.stat.st_mode & 01777) != 0 &&
289 errno != EEXIST) {
290 LOG(ERROR) << "CopyDirectory() couldn't create directory: " <<
291 target_path.value() << " errno = " << errno;
292 success = false;
293 }
294 } else if (S_ISREG(info.stat.st_mode)) {
295 if (!CopyFile(current, target_path)) {
296 LOG(ERROR) << "CopyDirectory() couldn't create file: " <<
297 target_path.value();
298 success = false;
299 }
300 } else {
301 LOG(WARNING) << "CopyDirectory() skipping non-regular file: " <<
302 current.value();
[email protected]21dec3872008-09-18 19:15:54303 }
[email protected]21dec3872008-09-18 19:15:54304
[email protected]49930c3a2009-08-06 21:23:07305 current = traversal.Next();
306 traversal.GetFindInfo(&info);
[email protected]21dec3872008-09-18 19:15:54307 }
308
[email protected]49930c3a2009-08-06 21:23:07309 return success;
[email protected]b2e97292008-09-02 18:20:34310}
311
[email protected]640517f2008-10-30 23:54:04312bool PathExists(const FilePath& path) {
[email protected]ef944e052010-05-17 15:01:22313 return access(path.value().c_str(), F_OK) == 0;
[email protected]b2e97292008-09-02 18:20:34314}
315
[email protected]7e1fde6a2008-12-23 20:20:10316bool PathIsWritable(const FilePath& path) {
[email protected]ef944e052010-05-17 15:01:22317 return access(path.value().c_str(), W_OK) == 0;
[email protected]7e1fde6a2008-12-23 20:20:10318}
319
[email protected]640517f2008-10-30 23:54:04320bool DirectoryExists(const FilePath& path) {
[email protected]fb66f9d2009-09-07 16:39:46321 stat_wrapper_t file_info;
322 if (CallStat(path.value().c_str(), &file_info) == 0)
[email protected]806b9c62008-09-11 16:09:11323 return S_ISDIR(file_info.st_mode);
324 return false;
325}
326
[email protected]b2e97292008-09-02 18:20:34327// TODO(erikkay): implement
328#if 0
329bool GetFileCreationLocalTimeFromHandle(int fd,
330 LPSYSTEMTIME creation_time) {
331 if (!file_handle)
332 return false;
[email protected]9e51af92009-02-04 00:58:39333
[email protected]b2e97292008-09-02 18:20:34334 FILETIME utc_filetime;
335 if (!GetFileTime(file_handle, &utc_filetime, NULL, NULL))
336 return false;
[email protected]9e51af92009-02-04 00:58:39337
[email protected]b2e97292008-09-02 18:20:34338 FILETIME local_filetime;
339 if (!FileTimeToLocalFileTime(&utc_filetime, &local_filetime))
340 return false;
[email protected]9e51af92009-02-04 00:58:39341
[email protected]b2e97292008-09-02 18:20:34342 return !!FileTimeToSystemTime(&local_filetime, creation_time);
343}
344
345bool GetFileCreationLocalTime(const std::string& filename,
346 LPSYSTEMTIME creation_time) {
347 ScopedHandle file_handle(
[email protected]9e51af92009-02-04 00:58:39348 CreateFile(filename.c_str(), GENERIC_READ,
[email protected]b2e97292008-09-02 18:20:34349 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
350 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
351 return GetFileCreationLocalTimeFromHandle(file_handle.Get(), creation_time);
352}
353#endif
354
[email protected]45301492009-04-23 12:38:08355bool ReadFromFD(int fd, char* buffer, size_t bytes) {
356 size_t total_read = 0;
357 while (total_read < bytes) {
[email protected]157c61b2009-05-01 21:37:31358 ssize_t bytes_read =
359 HANDLE_EINTR(read(fd, buffer + total_read, bytes - total_read));
360 if (bytes_read <= 0)
[email protected]45301492009-04-23 12:38:08361 break;
[email protected]157c61b2009-05-01 21:37:31362 total_read += bytes_read;
[email protected]45301492009-04-23 12:38:08363 }
364 return total_read == bytes;
365}
366
[email protected]9e51af92009-02-04 00:58:39367// Creates and opens a temporary file in |directory|, returning the
[email protected]16eac0a72009-09-11 17:33:50368// file descriptor. |path| is set to the temporary file path.
369// This function does NOT unlink() the file.
[email protected]9e51af92009-02-04 00:58:39370int CreateAndOpenFdForTemporaryFile(FilePath directory, FilePath* path) {
371 *path = directory.Append(kTempFileName);
372 const std::string& tmpdir_string = path->value();
[email protected]778e8c52008-09-11 17:36:23373 // this should be OK since mkstemp just replaces characters in place
374 char* buffer = const_cast<char*>(tmpdir_string.c_str());
[email protected]392264c2008-11-11 00:01:38375
[email protected]9e51af92009-02-04 00:58:39376 return mkstemp(buffer);
377}
378
[email protected]33edeab2009-08-18 16:07:55379bool CreateTemporaryFile(FilePath* path) {
[email protected]9e51af92009-02-04 00:58:39380 FilePath directory;
381 if (!GetTempDir(&directory))
382 return false;
383 int fd = CreateAndOpenFdForTemporaryFile(directory, path);
[email protected]b2e97292008-09-02 18:20:34384 if (fd < 0)
385 return false;
[email protected]392264c2008-11-11 00:01:38386 close(fd);
[email protected]b2e97292008-09-02 18:20:34387 return true;
388}
389
[email protected]9e51af92009-02-04 00:58:39390FILE* CreateAndOpenTemporaryShmemFile(FilePath* path) {
391 FilePath directory;
392 if (!GetShmemTempDir(&directory))
[email protected]628476aa2010-06-10 22:56:23393 return NULL;
[email protected]9e51af92009-02-04 00:58:39394
[email protected]6faa0e0d2009-04-28 06:50:36395 return CreateAndOpenTemporaryFileInDir(directory, path);
396}
397
398FILE* CreateAndOpenTemporaryFileInDir(const FilePath& dir, FilePath* path) {
399 int fd = CreateAndOpenFdForTemporaryFile(dir, path);
[email protected]9e51af92009-02-04 00:58:39400 if (fd < 0)
401 return NULL;
402
[email protected]6faa0e0d2009-04-28 06:50:36403 return fdopen(fd, "a+");
[email protected]9e51af92009-02-04 00:58:39404}
[email protected]6445c402009-09-11 20:06:27405
406bool CreateTemporaryFileInDir(const FilePath& dir, FilePath* temp_file) {
407 int fd = CreateAndOpenFdForTemporaryFile(dir, temp_file);
408 return ((fd >= 0) && !close(fd));
[email protected]9ccbb372008-10-10 18:50:32409}
410
[email protected]b0b3abd92010-04-30 17:00:09411static bool CreateTemporaryDirInDirImpl(const FilePath& base_dir,
412 const FilePath::StringType& name_tmpl,
413 FilePath* new_dir) {
414 CHECK(name_tmpl.find("XXXXXX") != FilePath::StringType::npos)
415 << "Directory name template must contain \"XXXXXX\".";
416
417 FilePath sub_dir = base_dir.Append(name_tmpl);
418 std::string sub_dir_string = sub_dir.value();
419
420 // this should be OK since mkdtemp just replaces characters in place
421 char* buffer = const_cast<char*>(sub_dir_string.c_str());
422 char* dtemp = mkdtemp(buffer);
[email protected]3ad035d22010-07-28 21:00:51423 if (!dtemp) {
424 DPLOG(ERROR) << "mkdtemp";
[email protected]b0b3abd92010-04-30 17:00:09425 return false;
[email protected]3ad035d22010-07-28 21:00:51426 }
[email protected]b0b3abd92010-04-30 17:00:09427 *new_dir = FilePath(dtemp);
428 return true;
429}
430
431bool CreateTemporaryDirInDir(const FilePath& base_dir,
432 const FilePath::StringType& prefix,
[email protected]4cd2d5202010-07-01 20:24:09433 bool loosen_permissions,
[email protected]046062e82010-06-30 07:19:11434 FilePath* new_dir) {
[email protected]4cd2d5202010-07-01 20:24:09435 // To understand crbug/35198, the ability to call this
436 // this function on windows while giving loose permissions
437 // to the resulting directory has been temporarily added.
438 // It should not be possible to call this function with
439 // loosen_permissions == true on non-windows platforms.
440 DCHECK(!loosen_permissions);
441
[email protected]b0b3abd92010-04-30 17:00:09442 FilePath::StringType mkdtemp_template = prefix;
443 mkdtemp_template.append(FILE_PATH_LITERAL("XXXXXX"));
444 return CreateTemporaryDirInDirImpl(base_dir, mkdtemp_template, new_dir);
445}
446
[email protected]7e1fde6a2008-12-23 20:20:10447bool CreateNewTempDirectory(const FilePath::StringType& prefix,
448 FilePath* new_temp_path) {
[email protected]392264c2008-11-11 00:01:38449 FilePath tmpdir;
[email protected]b2e97292008-09-02 18:20:34450 if (!GetTempDir(&tmpdir))
451 return false;
[email protected]b0b3abd92010-04-30 17:00:09452
453 return CreateTemporaryDirInDirImpl(tmpdir, kTempFileName, new_temp_path);
[email protected]b2e97292008-09-02 18:20:34454}
455
[email protected]640517f2008-10-30 23:54:04456bool CreateDirectory(const FilePath& full_path) {
457 std::vector<FilePath> subpaths;
458
459 // Collect a list of all parent directories.
460 FilePath last_path = full_path;
461 subpaths.push_back(full_path);
462 for (FilePath path = full_path.DirName();
463 path.value() != last_path.value(); path = path.DirName()) {
464 subpaths.push_back(path);
465 last_path = path;
466 }
467
468 // Iterate through the parents and create the missing ones.
469 for (std::vector<FilePath>::reverse_iterator i = subpaths.rbegin();
470 i != subpaths.rend(); ++i) {
[email protected]0ba86e42010-03-17 21:39:42471 if (DirectoryExists(*i))
472 continue;
473 if (mkdir(i->value().c_str(), 0700) == 0)
474 continue;
475 // Mkdir failed, but it might have failed with EEXIST, or some other error
476 // due to the the directory appearing out of thin air. This can occur if
477 // two processes are trying to create the same file system tree at the same
478 // time. Check to see if it exists and make sure it is a directory.
479 if (!DirectoryExists(*i))
480 return false;
[email protected]b2e97292008-09-02 18:20:34481 }
482 return true;
483}
484
[email protected]eac0709a2008-11-04 21:00:46485bool GetFileInfo(const FilePath& file_path, FileInfo* results) {
[email protected]fb66f9d2009-09-07 16:39:46486 stat_wrapper_t file_info;
487 if (CallStat(file_path.value().c_str(), &file_info) != 0)
[email protected]b2e97292008-09-02 18:20:34488 return false;
[email protected]f5e3da4d2008-09-26 01:04:08489 results->is_directory = S_ISDIR(file_info.st_mode);
490 results->size = file_info.st_size;
[email protected]5ef323892009-07-24 16:13:53491 results->last_modified = base::Time::FromTimeT(file_info.st_mtime);
[email protected]b2e97292008-09-02 18:20:34492 return true;
493}
494
[email protected]ec3d1452010-02-18 10:02:26495bool SetLastModifiedTime(const FilePath& file_path, base::Time last_modified) {
496 struct timeval times[2];
497 times[0] = last_modified.ToTimeVal();
498 times[1] = last_modified.ToTimeVal();
499 return (utimes(file_path.value().c_str(), times) == 0);
500}
501
[email protected]825003f2009-05-14 17:49:23502bool GetInode(const FilePath& path, ino_t* inode) {
503 struct stat buffer;
504 int result = stat(path.value().c_str(), &buffer);
505 if (result < 0)
506 return false;
507
508 *inode = buffer.st_ino;
509 return true;
510}
511
[email protected]836f1342008-10-01 17:40:13512FILE* OpenFile(const std::string& filename, const char* mode) {
[email protected]a9cd2a652008-11-17 21:01:19513 return OpenFile(FilePath(filename), mode);
[email protected]836f1342008-10-01 17:40:13514}
515
[email protected]a9cd2a652008-11-17 21:01:19516FILE* OpenFile(const FilePath& filename, const char* mode) {
517 return fopen(filename.value().c_str(), mode);
[email protected]836f1342008-10-01 17:40:13518}
519
[email protected]c870c762009-01-28 05:47:15520int ReadFile(const FilePath& filename, char* data, int size) {
521 int fd = open(filename.value().c_str(), O_RDONLY);
[email protected]b2e97292008-09-02 18:20:34522 if (fd < 0)
523 return -1;
[email protected]a9cd2a652008-11-17 21:01:19524
[email protected]cabe39c2010-02-02 02:28:16525 ssize_t bytes_read = HANDLE_EINTR(read(fd, data, size));
526 if (int ret = HANDLE_EINTR(close(fd)) < 0)
527 return ret;
528 return bytes_read;
[email protected]b2e97292008-09-02 18:20:34529}
530
[email protected]c870c762009-01-28 05:47:15531int WriteFile(const FilePath& filename, const char* data, int size) {
532 int fd = creat(filename.value().c_str(), 0666);
[email protected]b2e97292008-09-02 18:20:34533 if (fd < 0)
534 return -1;
[email protected]778e8c52008-09-11 17:36:23535
[email protected]cabe39c2010-02-02 02:28:16536 int bytes_written = WriteFileDescriptor(fd, data, size);
537 if (int ret = HANDLE_EINTR(close(fd)) < 0)
538 return ret;
539 return bytes_written;
[email protected]fbea0232009-09-16 00:29:22540}
541
542int WriteFileDescriptor(const int fd, const char* data, int size) {
543 // Allow for partial writes.
544 ssize_t bytes_written_total = 0;
545 for (ssize_t bytes_written_partial = 0; bytes_written_total < size;
546 bytes_written_total += bytes_written_partial) {
547 bytes_written_partial =
548 HANDLE_EINTR(write(fd, data + bytes_written_total,
549 size - bytes_written_total));
550 if (bytes_written_partial < 0)
551 return -1;
552 }
553
[email protected]778e8c52008-09-11 17:36:23554 return bytes_written_total;
[email protected]b2e97292008-09-02 18:20:34555}
556
557// Gets the current working directory for the process.
[email protected]640517f2008-10-30 23:54:04558bool GetCurrentDirectory(FilePath* dir) {
[email protected]b2e97292008-09-02 18:20:34559 char system_buffer[PATH_MAX] = "";
[email protected]640517f2008-10-30 23:54:04560 if (!getcwd(system_buffer, sizeof(system_buffer))) {
561 NOTREACHED();
562 return false;
563 }
564 *dir = FilePath(system_buffer);
[email protected]b2e97292008-09-02 18:20:34565 return true;
566}
567
568// Sets the current working directory for the process.
[email protected]a9cd2a652008-11-17 21:01:19569bool SetCurrentDirectory(const FilePath& path) {
570 int ret = chdir(path.value().c_str());
571 return !ret;
[email protected]b2e97292008-09-02 18:20:34572}
[email protected]a9cd2a652008-11-17 21:01:19573
[email protected]7856bb82008-12-12 23:43:03574///////////////////////////////////////////////
575// FileEnumerator
576
[email protected]0b733222008-12-11 14:55:12577FileEnumerator::FileEnumerator(const FilePath& root_path,
[email protected]b2e97292008-09-02 18:20:34578 bool recursive,
579 FileEnumerator::FILE_TYPE file_type)
[email protected]fbf745a2009-12-08 22:05:59580 : current_directory_entry_(0),
581 root_path_(root_path),
[email protected]49930c3a2009-08-06 21:23:07582 recursive_(recursive),
[email protected]b2e97292008-09-02 18:20:34583 file_type_(file_type),
[email protected]fbf745a2009-12-08 22:05:59584 is_in_find_op_(false) {
[email protected]8199b3a2009-06-09 05:57:38585 // INCLUDE_DOT_DOT must not be specified if recursive.
586 DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_)));
[email protected]b2e97292008-09-02 18:20:34587 pending_paths_.push(root_path);
588}
589
[email protected]0b733222008-12-11 14:55:12590FileEnumerator::FileEnumerator(const FilePath& root_path,
[email protected]b2e97292008-09-02 18:20:34591 bool recursive,
592 FileEnumerator::FILE_TYPE file_type,
[email protected]0b733222008-12-11 14:55:12593 const FilePath::StringType& pattern)
[email protected]fbf745a2009-12-08 22:05:59594 : current_directory_entry_(0),
595 root_path_(root_path),
[email protected]49930c3a2009-08-06 21:23:07596 recursive_(recursive),
[email protected]b2e97292008-09-02 18:20:34597 file_type_(file_type),
[email protected]fbf745a2009-12-08 22:05:59598 pattern_(root_path.Append(pattern).value()),
599 is_in_find_op_(false) {
[email protected]8199b3a2009-06-09 05:57:38600 // INCLUDE_DOT_DOT must not be specified if recursive.
601 DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_)));
[email protected]49930c3a2009-08-06 21:23:07602 // The Windows version of this code appends the pattern to the root_path,
603 // potentially only matching against items in the top-most directory.
604 // Do the same here.
605 if (pattern.size() == 0)
[email protected]fbf745a2009-12-08 22:05:59606 pattern_ = FilePath::StringType();
[email protected]b2e97292008-09-02 18:20:34607 pending_paths_.push(root_path);
608}
[email protected]a9cd2a652008-11-17 21:01:19609
[email protected]b2e97292008-09-02 18:20:34610FileEnumerator::~FileEnumerator() {
[email protected]b2e97292008-09-02 18:20:34611}
612
[email protected]13ef7c02008-11-20 22:30:13613void FileEnumerator::GetFindInfo(FindInfo* info) {
614 DCHECK(info);
615
[email protected]49930c3a2009-08-06 21:23:07616 if (current_directory_entry_ >= directory_entries_.size())
[email protected]13ef7c02008-11-20 22:30:13617 return;
618
[email protected]49930c3a2009-08-06 21:23:07619 DirectoryEntryInfo* cur_entry = &directory_entries_[current_directory_entry_];
620 memcpy(&(info->stat), &(cur_entry->stat), sizeof(info->stat));
621 info->filename.assign(cur_entry->filename.value());
[email protected]13ef7c02008-11-20 22:30:13622}
623
[email protected]9fa8c2f52009-12-11 21:12:29624bool FileEnumerator::IsDirectory(const FindInfo& info) {
625 return S_ISDIR(info.stat.st_mode);
626}
627
[email protected]1525c682010-02-11 23:27:47628// static
629FilePath FileEnumerator::GetFilename(const FindInfo& find_info) {
630 return FilePath(find_info.filename);
631}
632
[email protected]0b733222008-12-11 14:55:12633FilePath FileEnumerator::Next() {
[email protected]49930c3a2009-08-06 21:23:07634 ++current_directory_entry_;
635
636 // While we've exhausted the entries in the current directory, do the next
637 while (current_directory_entry_ >= directory_entries_.size()) {
[email protected]b2e97292008-09-02 18:20:34638 if (pending_paths_.empty())
[email protected]0b733222008-12-11 14:55:12639 return FilePath();
[email protected]13ef7c02008-11-20 22:30:13640
[email protected]b2e97292008-09-02 18:20:34641 root_path_ = pending_paths_.top();
[email protected]0b733222008-12-11 14:55:12642 root_path_ = root_path_.StripTrailingSeparators();
[email protected]b2e97292008-09-02 18:20:34643 pending_paths_.pop();
[email protected]13ef7c02008-11-20 22:30:13644
[email protected]49930c3a2009-08-06 21:23:07645 std::vector<DirectoryEntryInfo> entries;
646 if (!ReadDirectory(&entries, root_path_, file_type_ & SHOW_SYM_LINKS))
647 continue;
[email protected]13ef7c02008-11-20 22:30:13648
[email protected]49930c3a2009-08-06 21:23:07649 directory_entries_.clear();
650 current_directory_entry_ = 0;
651 for (std::vector<DirectoryEntryInfo>::const_iterator
652 i = entries.begin(); i != entries.end(); ++i) {
653 FilePath full_path = root_path_.Append(i->filename);
654 if (ShouldSkip(full_path))
655 continue;
[email protected]13ef7c02008-11-20 22:30:13656
[email protected]fbf745a2009-12-08 22:05:59657 if (pattern_.size() &&
658 fnmatch(pattern_.c_str(), full_path.value().c_str(), FNM_NOESCAPE))
[email protected]49930c3a2009-08-06 21:23:07659 continue;
660
661 if (recursive_ && S_ISDIR(i->stat.st_mode))
662 pending_paths_.push(full_path);
663
664 if ((S_ISDIR(i->stat.st_mode) && (file_type_ & DIRECTORIES)) ||
665 (!S_ISDIR(i->stat.st_mode) && (file_type_ & FILES)))
666 directory_entries_.push_back(*i);
[email protected]b2e97292008-09-02 18:20:34667 }
668 }
[email protected]13ef7c02008-11-20 22:30:13669
[email protected]49930c3a2009-08-06 21:23:07670 return root_path_.Append(directory_entries_[current_directory_entry_
671 ].filename);
672}
[email protected]8199b3a2009-06-09 05:57:38673
[email protected]49930c3a2009-08-06 21:23:07674bool FileEnumerator::ReadDirectory(std::vector<DirectoryEntryInfo>* entries,
675 const FilePath& source, bool show_links) {
676 DIR* dir = opendir(source.value().c_str());
677 if (!dir)
678 return false;
679
[email protected]8d578822010-01-25 23:54:54680#if !defined(OS_LINUX) && !defined(OS_MACOSX) && !defined(OS_FREEBSD) && \
[email protected]b5c72b822010-02-18 16:11:37681 !defined(OS_OPENBSD) && !defined(OS_SOLARIS)
[email protected]e43eddf12009-12-29 00:32:52682 #error Port warning: depending on the definition of struct dirent, \
683 additional space for pathname may be needed
[email protected]49930c3a2009-08-06 21:23:07684#endif
[email protected]e43eddf12009-12-29 00:32:52685
[email protected]49930c3a2009-08-06 21:23:07686 struct dirent dent_buf;
687 struct dirent* dent;
688 while (readdir_r(dir, &dent_buf, &dent) == 0 && dent) {
689 DirectoryEntryInfo info;
[email protected]49930c3a2009-08-06 21:23:07690 info.filename = FilePath(dent->d_name);
[email protected]2237f5d72009-09-03 22:39:34691
692 FilePath full_name = source.Append(dent->d_name);
693 int ret;
[email protected]49930c3a2009-08-06 21:23:07694 if (show_links)
[email protected]2237f5d72009-09-03 22:39:34695 ret = lstat(full_name.value().c_str(), &info.stat);
[email protected]49930c3a2009-08-06 21:23:07696 else
[email protected]2237f5d72009-09-03 22:39:34697 ret = stat(full_name.value().c_str(), &info.stat);
698 if (ret < 0) {
699 // Print the stat() error message unless it was ENOENT and we're
700 // following symlinks.
[email protected]e131cf52010-03-25 19:10:28701 if (!(errno == ENOENT && !show_links)) {
[email protected]57b765672009-10-13 18:27:40702 PLOG(ERROR) << "Couldn't stat "
703 << source.Append(dent->d_name).value();
[email protected]2237f5d72009-09-03 22:39:34704 }
[email protected]49930c3a2009-08-06 21:23:07705 memset(&info.stat, 0, sizeof(info.stat));
[email protected]8199b3a2009-06-09 05:57:38706 }
[email protected]49930c3a2009-08-06 21:23:07707 entries->push_back(info);
[email protected]b2e97292008-09-02 18:20:34708 }
[email protected]49930c3a2009-08-06 21:23:07709
710 closedir(dir);
711 return true;
712}
713
[email protected]7856bb82008-12-12 23:43:03714///////////////////////////////////////////////
715// MemoryMappedFile
716
717MemoryMappedFile::MemoryMappedFile()
[email protected]cb6037d2009-11-16 22:55:17718 : file_(base::kInvalidPlatformFileValue),
719 data_(NULL),
[email protected]7856bb82008-12-12 23:43:03720 length_(0) {
721}
722
[email protected]85c55dc2009-11-06 03:05:46723bool MemoryMappedFile::MapFileToMemoryInternal() {
[email protected]7856bb82008-12-12 23:43:03724 struct stat file_stat;
[email protected]cb6037d2009-11-16 22:55:17725 if (fstat(file_, &file_stat) == base::kInvalidPlatformFileValue) {
726 LOG(ERROR) << "Couldn't fstat " << file_ << ", errno " << errno;
[email protected]7856bb82008-12-12 23:43:03727 return false;
[email protected]4883a4e2009-06-06 19:59:36728 }
[email protected]7856bb82008-12-12 23:43:03729 length_ = file_stat.st_size;
730
731 data_ = static_cast<uint8*>(
[email protected]cb6037d2009-11-16 22:55:17732 mmap(NULL, length_, PROT_READ, MAP_SHARED, file_, 0));
[email protected]7856bb82008-12-12 23:43:03733 if (data_ == MAP_FAILED)
[email protected]cb6037d2009-11-16 22:55:17734 LOG(ERROR) << "Couldn't mmap " << file_ << ", errno " << errno;
[email protected]4883a4e2009-06-06 19:59:36735
736 return data_ != MAP_FAILED;
[email protected]7856bb82008-12-12 23:43:03737}
738
739void MemoryMappedFile::CloseHandles() {
740 if (data_ != NULL)
741 munmap(data_, length_);
[email protected]cb6037d2009-11-16 22:55:17742 if (file_ != base::kInvalidPlatformFileValue)
743 close(file_);
[email protected]7856bb82008-12-12 23:43:03744
745 data_ = NULL;
746 length_ = 0;
[email protected]cb6037d2009-11-16 22:55:17747 file_ = base::kInvalidPlatformFileValue;
[email protected]7856bb82008-12-12 23:43:03748}
[email protected]13ef7c02008-11-20 22:30:13749
[email protected]35b9be02009-11-26 00:37:06750bool HasFileBeenModifiedSince(const FileEnumerator::FindInfo& find_info,
751 const base::Time& cutoff_time) {
752 return find_info.stat.st_mtime >= cutoff_time.ToTimeT();
753}
754
[email protected]6f5f4322010-06-09 22:56:48755bool NormalizeFilePath(const FilePath& path, FilePath* normalized_path) {
756 FilePath real_path_result;
757 if (!RealPath(path, &real_path_result))
[email protected]01e2a1f2010-05-12 15:13:57758 return false;
759
[email protected]6f5f4322010-06-09 22:56:48760 // To be consistant with windows, fail if |real_path_result| is a
761 // directory.
762 stat_wrapper_t file_info;
763 if (CallStat(real_path_result.value().c_str(), &file_info) != 0 ||
764 S_ISDIR(file_info.st_mode))
765 return false;
766
767 *normalized_path = real_path_result;
[email protected]01e2a1f2010-05-12 15:13:57768 return true;
769}
770
[email protected]84cb1912010-04-21 21:11:36771#if !defined(OS_MACOSX)
772bool GetTempDir(FilePath* path) {
773 const char* tmp = getenv("TMPDIR");
774 if (tmp)
775 *path = FilePath(tmp);
776 else
777 *path = FilePath("/tmp");
778 return true;
779}
780
781bool GetShmemTempDir(FilePath* path) {
782 *path = FilePath("/dev/shm");
783 return true;
784}
785
[email protected]1c657852010-04-22 23:28:05786FilePath GetHomeDir() {
787 const char* home_dir = getenv("HOME");
788 if (home_dir && home_dir[0])
789 return FilePath(home_dir);
790
791 home_dir = g_get_home_dir();
792 if (home_dir && home_dir[0])
793 return FilePath(home_dir);
794
795 FilePath rv;
796 if (file_util::GetTempDir(&rv))
797 return rv;
798
799 // Last resort.
800 return FilePath("/tmp");
801}
802
[email protected]84cb1912010-04-21 21:11:36803bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
804 int infile = open(from_path.value().c_str(), O_RDONLY);
805 if (infile < 0)
806 return false;
807
808 int outfile = creat(to_path.value().c_str(), 0666);
809 if (outfile < 0) {
810 close(infile);
811 return false;
812 }
813
814 const size_t kBufferSize = 32768;
815 std::vector<char> buffer(kBufferSize);
816 bool result = true;
817
818 while (result) {
819 ssize_t bytes_read = HANDLE_EINTR(read(infile, &buffer[0], buffer.size()));
820 if (bytes_read < 0) {
821 result = false;
822 break;
823 }
824 if (bytes_read == 0)
825 break;
826 // Allow for partial writes
827 ssize_t bytes_written_per_read = 0;
828 do {
829 ssize_t bytes_written_partial = HANDLE_EINTR(write(
830 outfile,
831 &buffer[bytes_written_per_read],
832 bytes_read - bytes_written_per_read));
833 if (bytes_written_partial < 0) {
834 result = false;
835 break;
836 }
837 bytes_written_per_read += bytes_written_partial;
838 } while (bytes_written_per_read < bytes_read);
839 }
840
841 if (HANDLE_EINTR(close(infile)) < 0)
842 result = false;
843 if (HANDLE_EINTR(close(outfile)) < 0)
844 result = false;
845
846 return result;
847}
848#endif // defined(OS_MACOSX)
849
[email protected]b2e97292008-09-02 18:20:34850} // namespace file_util