blob: 747232bc3196c7d6d98429ad029dcb4bd3a1099a [file] [log] [blame]
[email protected]b33f1d92010-05-26 01:40:121// Copyright (c) 2010 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commitd7cae122008-07-26 21:49:384
5#include "base/file_util.h"
6
[email protected]c2c998c2009-01-27 19:08:397#if defined(OS_WIN)
8#include <io.h>
9#endif
[email protected]836f1342008-10-01 17:40:1310#include <stdio.h>
11
initial.commitd7cae122008-07-26 21:49:3812#include <fstream>
initial.commitd7cae122008-07-26 21:49:3813
[email protected]640517f2008-10-30 23:54:0414#include "base/file_path.h"
initial.commitd7cae122008-07-26 21:49:3815#include "base/logging.h"
[email protected]b9e04f02008-11-27 04:03:5716#include "base/string_piece.h"
[email protected]047a03f2009-10-07 02:10:2017#include "base/string_util.h"
18#include "base/utf_string_conversions.h"
[email protected]b9e04f02008-11-27 04:03:5719
[email protected]ceeb87e2008-12-04 20:46:0620namespace {
21
22const FilePath::CharType kExtensionSeparator = FILE_PATH_LITERAL('.');
23
[email protected]c145cbdd2009-04-24 17:44:3924} // namespace
[email protected]ceeb87e2008-12-04 20:46:0625
initial.commitd7cae122008-07-26 21:49:3826namespace file_util {
27
[email protected]b9e04f02008-11-27 04:03:5728bool EndsWithSeparator(const FilePath& path) {
29 FilePath::StringType value = path.value();
30 if (value.empty())
31 return false;
32
33 return FilePath::IsSeparator(value[value.size() - 1]);
initial.commitd7cae122008-07-26 21:49:3834}
35
[email protected]7e263942008-11-25 22:04:3736bool EnsureEndsWithSeparator(FilePath* path) {
37 if (!DirectoryExists(*path))
38 return false;
39
40 if (EndsWithSeparator(*path))
41 return true;
42
43 FilePath::StringType& path_str =
44 const_cast<FilePath::StringType&>(path->value());
45 path_str.append(&FilePath::kSeparators[0], 1);
46
47 return true;
48}
49
[email protected]7ae7c2cb2009-01-06 23:31:4150FilePath::StringType GetFileExtensionFromPath(const FilePath& path) {
51 FilePath::StringType file_name = path.BaseName().value();
52 const FilePath::StringType::size_type last_dot =
53 file_name.rfind(kExtensionSeparator);
54 return FilePath::StringType(last_dot == FilePath::StringType::npos ?
55 FILE_PATH_LITERAL("") :
56 file_name, last_dot+1);
[email protected]52ab8f902008-11-03 16:14:4657}
58
[email protected]ceeb87e2008-12-04 20:46:0659void InsertBeforeExtension(FilePath* path, const FilePath::StringType& suffix) {
60 FilePath::StringType& value =
61 const_cast<FilePath::StringType&>(path->value());
62
63 const FilePath::StringType::size_type last_dot =
64 value.rfind(kExtensionSeparator);
65 const FilePath::StringType::size_type last_separator =
66 value.find_last_of(FilePath::StringType(FilePath::kSeparators));
67
68 if (last_dot == FilePath::StringType::npos ||
69 (last_separator != std::wstring::npos && last_dot < last_separator)) {
70 // The path looks something like "C:\pics.old\jojo" or "C:\pics\jojo".
71 // We should just append the suffix to the entire path.
72 value.append(suffix);
73 return;
74 }
75
76 value.insert(last_dot, suffix);
77}
78
[email protected]640517f2008-10-30 23:54:0479bool ContentsEqual(const FilePath& filename1, const FilePath& filename2) {
initial.commitd7cae122008-07-26 21:49:3880 // We open the file in binary format even if they are text files because
81 // we are just comparing that bytes are exactly same in both files and not
82 // doing anything smart with text formatting.
[email protected]640517f2008-10-30 23:54:0483 std::ifstream file1(filename1.value().c_str(),
[email protected]5af2edb92008-08-08 20:16:0884 std::ios::in | std::ios::binary);
[email protected]640517f2008-10-30 23:54:0485 std::ifstream file2(filename2.value().c_str(),
[email protected]5af2edb92008-08-08 20:16:0886 std::ios::in | std::ios::binary);
[email protected]b9e04f02008-11-27 04:03:5787
initial.commitd7cae122008-07-26 21:49:3888 // Even if both files aren't openable (and thus, in some sense, "equal"),
89 // any unusable file yields a result of "false".
90 if (!file1.is_open() || !file2.is_open())
91 return false;
92
93 const int BUFFER_SIZE = 2056;
94 char buffer1[BUFFER_SIZE], buffer2[BUFFER_SIZE];
95 do {
96 file1.read(buffer1, BUFFER_SIZE);
97 file2.read(buffer2, BUFFER_SIZE);
98
[email protected]b81637c32009-06-26 21:17:2499 if ((file1.eof() != file2.eof()) ||
initial.commitd7cae122008-07-26 21:49:38100 (file1.gcount() != file2.gcount()) ||
101 (memcmp(buffer1, buffer2, file1.gcount()))) {
102 file1.close();
103 file2.close();
104 return false;
105 }
[email protected]b81637c32009-06-26 21:17:24106 } while (!file1.eof() || !file2.eof());
initial.commitd7cae122008-07-26 21:49:38107
108 file1.close();
109 file2.close();
110 return true;
111}
112
[email protected]b81637c32009-06-26 21:17:24113bool TextContentsEqual(const FilePath& filename1, const FilePath& filename2) {
114 std::ifstream file1(filename1.value().c_str(), std::ios::in);
115 std::ifstream file2(filename2.value().c_str(), std::ios::in);
116
117 // Even if both files aren't openable (and thus, in some sense, "equal"),
118 // any unusable file yields a result of "false".
119 if (!file1.is_open() || !file2.is_open())
120 return false;
121
122 do {
123 std::string line1, line2;
124 getline(file1, line1);
125 getline(file2, line2);
126
127 // Check for mismatched EOF states, or any error state.
128 if ((file1.eof() != file2.eof()) ||
129 file1.bad() || file2.bad()) {
130 return false;
131 }
132
133 // Trim all '\r' and '\n' characters from the end of the line.
134 std::string::size_type end1 = line1.find_last_not_of("\r\n");
135 if (end1 == std::string::npos)
136 line1.clear();
137 else if (end1 + 1 < line1.length())
138 line1.erase(end1 + 1);
139
140 std::string::size_type end2 = line2.find_last_not_of("\r\n");
141 if (end2 == std::string::npos)
142 line2.clear();
143 else if (end2 + 1 < line2.length())
144 line2.erase(end2 + 1);
145
146 if (line1 != line2)
147 return false;
148 } while (!file1.eof() || !file2.eof());
149
150 return true;
151}
152
[email protected]3c5281022009-01-28 00:22:46153bool ReadFileToString(const FilePath& path, std::string* contents) {
[email protected]836f1342008-10-01 17:40:13154 FILE* file = OpenFile(path, "rb");
155 if (!file) {
initial.commitd7cae122008-07-26 21:49:38156 return false;
[email protected]836f1342008-10-01 17:40:13157 }
initial.commitd7cae122008-07-26 21:49:38158
159 char buf[1 << 16];
160 size_t len;
161 while ((len = fread(buf, 1, sizeof(buf), file)) > 0) {
[email protected]4e074bae2010-05-19 11:07:55162 if (contents)
163 contents->append(buf, len);
initial.commitd7cae122008-07-26 21:49:38164 }
[email protected]836f1342008-10-01 17:40:13165 CloseFile(file);
initial.commitd7cae122008-07-26 21:49:38166
167 return true;
168}
169
[email protected]b33f1d92010-05-26 01:40:12170bool IsDirectoryEmpty(const FilePath& dir_path) {
171 FileEnumerator files(dir_path, false,
172 static_cast<FileEnumerator::FILE_TYPE>(
173 FileEnumerator::FILES | FileEnumerator::DIRECTORIES));
174 if (files.Next().value().empty())
175 return true;
176 return false;
177}
178
[email protected]6faa0e0d2009-04-28 06:50:36179FILE* CreateAndOpenTemporaryFile(FilePath* path) {
180 FilePath directory;
181 if (!GetTempDir(&directory))
[email protected]628476aa2010-06-10 22:56:23182 return NULL;
[email protected]6faa0e0d2009-04-28 06:50:36183
184 return CreateAndOpenTemporaryFileInDir(directory, path);
185}
186
[email protected]eac0709a2008-11-04 21:00:46187bool GetFileSize(const FilePath& file_path, int64* file_size) {
[email protected]2f0193c22010-09-03 02:28:37188 base::PlatformFileInfo info;
[email protected]f5e3da4d2008-09-26 01:04:08189 if (!GetFileInfo(file_path, &info))
190 return false;
191 *file_size = info.size;
192 return true;
193}
194
[email protected]1525c682010-02-11 23:27:47195bool IsDot(const FilePath& path) {
196 return FILE_PATH_LITERAL(".") == path.BaseName().value();
197}
198
199bool IsDotDot(const FilePath& path) {
200 return FILE_PATH_LITERAL("..") == path.BaseName().value();
201}
202
[email protected]507fb9a2010-09-23 23:28:22203bool TouchFile(const FilePath& path,
204 const base::Time& last_accessed,
205 const base::Time& last_modified) {
206 base::PlatformFile file =
207 base::CreatePlatformFile(path,
208 base::PLATFORM_FILE_OPEN |
209 base::PLATFORM_FILE_WRITE_ATTRIBUTES,
210 NULL, NULL);
211 if (file != base::kInvalidPlatformFileValue) {
212 bool result = base::TouchPlatformFile(file, last_accessed, last_modified);
213 base::ClosePlatformFile(file);
214 return result;
215 }
216
217 return false;
218}
219
220bool SetLastModifiedTime(const FilePath& path,
221 const base::Time& last_modified) {
222 return TouchFile(path, last_modified, last_modified);
223}
224
[email protected]836f1342008-10-01 17:40:13225bool CloseFile(FILE* file) {
[email protected]a1a19502008-10-21 17:14:45226 if (file == NULL)
227 return true;
[email protected]836f1342008-10-01 17:40:13228 return fclose(file) == 0;
229}
230
[email protected]c2c998c2009-01-27 19:08:39231bool TruncateFile(FILE* file) {
232 if (file == NULL)
233 return false;
234 long current_offset = ftell(file);
235 if (current_offset == -1)
236 return false;
237#if defined(OS_WIN)
238 int fd = _fileno(file);
239 if (_chsize(fd, current_offset) != 0)
240 return false;
241#else
242 int fd = fileno(file);
243 if (ftruncate(fd, current_offset) != 0)
244 return false;
245#endif
246 return true;
247}
248
[email protected]ee5c29da2009-01-09 22:14:27249bool ContainsPath(const FilePath &parent, const FilePath& child) {
250 FilePath abs_parent = FilePath(parent);
251 FilePath abs_child = FilePath(child);
252
253 if (!file_util::AbsolutePath(&abs_parent) ||
254 !file_util::AbsolutePath(&abs_child))
255 return false;
256
257#if defined(OS_WIN)
258 // file_util::AbsolutePath() does not flatten case on Windows, so we must do
259 // a case-insensitive compare.
260 if (!StartsWith(abs_child.value(), abs_parent.value(), false))
261#else
262 if (!StartsWithASCII(abs_child.value(), abs_parent.value(), true))
263#endif
264 return false;
265
266 // file_util::AbsolutePath() normalizes '/' to '\' on Windows, so we only need
267 // to check kSeparators[0].
268 if (abs_child.value().length() <= abs_parent.value().length() ||
269 abs_child.value()[abs_parent.value().length()] !=
270 FilePath::kSeparators[0])
271 return false;
272
273 return true;
274}
275
[email protected]c2c132c62010-03-24 21:56:26276int64 ComputeDirectorySize(const FilePath& root_path) {
277 int64 running_size = 0;
278 FileEnumerator file_iter(root_path, true, FileEnumerator::FILES);
279 for (FilePath current = file_iter.Next(); !current.empty();
280 current = file_iter.Next()) {
281 FileEnumerator::FindInfo info;
282 file_iter.GetFindInfo(&info);
283#if defined(OS_WIN)
284 LARGE_INTEGER li = { info.nFileSizeLow, info.nFileSizeHigh };
285 running_size += li.QuadPart;
286#else
287 running_size += info.stat.st_size;
288#endif
289 }
290 return running_size;
291}
292
[email protected]a04876b92010-06-11 22:53:43293int64 ComputeFilesSize(const FilePath& directory,
294 const FilePath::StringType& pattern) {
295 int64 running_size = 0;
296 FileEnumerator file_iter(directory, false, FileEnumerator::FILES, pattern);
297 for (FilePath current = file_iter.Next(); !current.empty();
298 current = file_iter.Next()) {
299 FileEnumerator::FindInfo info;
300 file_iter.GetFindInfo(&info);
301#if defined(OS_WIN)
302 LARGE_INTEGER li = { info.nFileSizeLow, info.nFileSizeHigh };
303 running_size += li.QuadPart;
304#else
305 running_size += info.stat.st_size;
306#endif
307 }
308 return running_size;
309}
310
[email protected]7856bb82008-12-12 23:43:03311///////////////////////////////////////////////
312// MemoryMappedFile
313
314MemoryMappedFile::~MemoryMappedFile() {
315 CloseHandles();
316}
317
[email protected]cb6037d2009-11-16 22:55:17318bool MemoryMappedFile::Initialize(base::PlatformFile file) {
319 if (IsValid())
320 return false;
321
322 file_ = file;
323
324 if (!MapFileToMemoryInternal()) {
325 CloseHandles();
326 return false;
327 }
328
329 return true;
330}
331
[email protected]7856bb82008-12-12 23:43:03332bool MemoryMappedFile::Initialize(const FilePath& file_name) {
333 if (IsValid())
334 return false;
335
336 if (!MapFileToMemory(file_name)) {
337 CloseHandles();
338 return false;
339 }
340
341 return true;
342}
343
[email protected]cb6037d2009-11-16 22:55:17344bool MemoryMappedFile::MapFileToMemory(const FilePath& file_name) {
[email protected]ed65fec2010-08-31 19:30:27345 file_ = base::CreatePlatformFile(
346 file_name, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ,
347 NULL, NULL);
[email protected]cb6037d2009-11-16 22:55:17348
349 if (file_ == base::kInvalidPlatformFileValue) {
350 LOG(ERROR) << "Couldn't open " << file_name.value();
351 return false;
352 }
353
354 return MapFileToMemoryInternal();
355}
356
[email protected]7856bb82008-12-12 23:43:03357bool MemoryMappedFile::IsValid() {
358 return data_ != NULL;
359}
360
[email protected]640517f2008-10-30 23:54:04361// Deprecated functions ----------------------------------------------------
362
[email protected]777d5902009-10-09 21:03:58363bool AbsolutePath(std::wstring* path_str) {
364 FilePath path(FilePath::FromWStringHack(*path_str));
365 if (!AbsolutePath(&path))
366 return false;
367 *path_str = path.ToWStringHack();
368 return true;
369}
[email protected]1840cfc2010-02-26 15:11:55370
371#if defined(OS_WIN)
372// This function is deprecated; see file_util_deprecated.h for details.
[email protected]b9e04f02008-11-27 04:03:57373void AppendToPath(std::wstring* path, const std::wstring& new_ending) {
374 if (!path) {
375 NOTREACHED();
376 return; // Don't crash in this function in release builds.
377 }
378
[email protected]147ff1242010-06-21 03:05:19379 if (!EndsWithSeparator(FilePath(*path)))
[email protected]b9e04f02008-11-27 04:03:57380 path->push_back(FilePath::kSeparators[0]);
381 path->append(new_ending);
[email protected]640517f2008-10-30 23:54:04382}
[email protected]1840cfc2010-02-26 15:11:55383#endif
384
[email protected]640517f2008-10-30 23:54:04385bool CopyDirectory(const std::wstring& from_path, const std::wstring& to_path,
386 bool recursive) {
387 return CopyDirectory(FilePath::FromWStringHack(from_path),
388 FilePath::FromWStringHack(to_path),
389 recursive);
390}
[email protected]b9e04f02008-11-27 04:03:57391bool Delete(const std::wstring& path, bool recursive) {
392 return Delete(FilePath::FromWStringHack(path), recursive);
393}
[email protected]7ae7c2cb2009-01-06 23:31:41394std::wstring GetFileExtensionFromPath(const std::wstring& path) {
395 FilePath::StringType extension =
396 GetFileExtensionFromPath(FilePath::FromWStringHack(path));
397#if defined(OS_WIN)
398 return extension;
399#elif defined(OS_POSIX)
400 return UTF8ToWide(extension);
401#endif
402}
[email protected]ceeb87e2008-12-04 20:46:06403std::wstring GetFilenameFromPath(const std::wstring& path) {
[email protected]147ff1242010-06-21 03:05:19404 if (path.empty() || EndsWithSeparator(FilePath::FromWStringHack(path)))
[email protected]ceeb87e2008-12-04 20:46:06405 return std::wstring();
406
[email protected]5e207882009-01-05 23:59:36407 return FilePath::FromWStringHack(path).BaseName().ToWStringHack();
[email protected]ceeb87e2008-12-04 20:46:06408}
[email protected]a9cd2a652008-11-17 21:01:19409FILE* OpenFile(const std::wstring& filename, const char* mode) {
410 return OpenFile(FilePath::FromWStringHack(filename), mode);
411}
[email protected]c870c762009-01-28 05:47:15412int ReadFile(const std::wstring& filename, char* data, int size) {
413 return ReadFile(FilePath::FromWStringHack(filename), data, size);
414}
[email protected]c870c762009-01-28 05:47:15415int WriteFile(const std::wstring& filename, const char* data, int size) {
416 return WriteFile(FilePath::FromWStringHack(filename), data, size);
417}
[email protected]8199b3a2009-06-09 05:57:38418
419///////////////////////////////////////////////
420// FileEnumerator
421//
422// Note: the main logic is in file_util_<platform>.cc
423
424bool FileEnumerator::ShouldSkip(const FilePath& path) {
425 FilePath::StringType basename = path.BaseName().value();
426 return IsDot(path) || (IsDotDot(path) && !(INCLUDE_DOT_DOT & file_type_));
427}
428
initial.commitd7cae122008-07-26 21:49:38429} // namespace