[go: nahoru, domu]

blob: 8f67cc3147cbbae7995e7ccc8e681aa91ccb4132 [file] [log] [blame]
tfarina@chromium.orgb70f8522011-08-04 19:45:421// Copyright (c) 2011 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
jeremy@chromium.orgc2c998c2009-01-27 19:08:397#if defined(OS_WIN)
8#include <io.h>
9#endif
mark@chromium.org836f1342008-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
evanm@google.com640517f2008-10-30 23:54:0414#include "base/file_path.h"
initial.commitd7cae122008-07-26 21:49:3815#include "base/logging.h"
jam@chromium.orge285afa2012-01-31 23:16:3916#include "base/stringprintf.h"
estade@chromium.orgb9e04f02008-11-27 04:03:5717#include "base/string_piece.h"
brettw@chromium.org047a03f2009-10-07 02:10:2018#include "base/string_util.h"
19#include "base/utf_string_conversions.h"
estade@chromium.orgb9e04f02008-11-27 04:03:5720
estade@chromium.orgceeb87e2008-12-04 20:46:0621namespace {
22
23const FilePath::CharType kExtensionSeparator = FILE_PATH_LITERAL('.');
jam@chromium.orge285afa2012-01-31 23:16:3924
25// The maximum number of 'uniquified' files we will try to create.
26// This is used when the filename we're trying to download is already in use,
27// so we create a new unique filename by appending " (nnn)" before the
28// extension, where 1 <= nnn <= kMaxUniqueFiles.
29// Also used by code that cleans up said files.
30static const int kMaxUniqueFiles = 100;
estade@chromium.orgceeb87e2008-12-04 20:46:0631
willchan@chromium.orgc145cbdd2009-04-24 17:44:3932} // namespace
estade@chromium.orgceeb87e2008-12-04 20:46:0633
initial.commitd7cae122008-07-26 21:49:3834namespace file_util {
35
estade@chromium.orgb9e04f02008-11-27 04:03:5736bool EndsWithSeparator(const FilePath& path) {
37 FilePath::StringType value = path.value();
38 if (value.empty())
39 return false;
40
41 return FilePath::IsSeparator(value[value.size() - 1]);
estade@chromium.org7e263942008-11-25 22:04:3742}
43
44bool EnsureEndsWithSeparator(FilePath* path) {
45 if (!DirectoryExists(*path))
46 return false;
47
48 if (EndsWithSeparator(*path))
49 return true;
50
51 FilePath::StringType& path_str =
52 const_cast<FilePath::StringType&>(path->value());
53 path_str.append(&FilePath::kSeparators[0], 1);
54
55 return true;
glen@chromium.org52ab8f902008-11-03 16:14:4656}
57
estade@chromium.orgceeb87e2008-12-04 20:46:0658void InsertBeforeExtension(FilePath* path, const FilePath::StringType& suffix) {
59 FilePath::StringType& value =
60 const_cast<FilePath::StringType&>(path->value());
61
62 const FilePath::StringType::size_type last_dot =
63 value.rfind(kExtensionSeparator);
64 const FilePath::StringType::size_type last_separator =
65 value.find_last_of(FilePath::StringType(FilePath::kSeparators));
66
67 if (last_dot == FilePath::StringType::npos ||
68 (last_separator != std::wstring::npos && last_dot < last_separator)) {
69 // The path looks something like "C:\pics.old\jojo" or "C:\pics\jojo".
70 // We should just append the suffix to the entire path.
71 value.append(suffix);
72 return;
73 }
74
75 value.insert(last_dot, suffix);
76}
77
evanm@google.com640517f2008-10-30 23:54:0478bool ContentsEqual(const FilePath& filename1, const FilePath& filename2) {
initial.commitd7cae122008-07-26 21:49:3879 // We open the file in binary format even if they are text files because
80 // we are just comparing that bytes are exactly same in both files and not
81 // doing anything smart with text formatting.
evanm@google.com640517f2008-10-30 23:54:0482 std::ifstream file1(filename1.value().c_str(),
erikkay@google.com5af2edb92008-08-08 20:16:0883 std::ios::in | std::ios::binary);
evanm@google.com640517f2008-10-30 23:54:0484 std::ifstream file2(filename2.value().c_str(),
erikkay@google.com5af2edb92008-08-08 20:16:0885 std::ios::in | std::ios::binary);
estade@chromium.orgb9e04f02008-11-27 04:03:5786
initial.commitd7cae122008-07-26 21:49:3887 // Even if both files aren't openable (and thus, in some sense, "equal"),
88 // any unusable file yields a result of "false".
89 if (!file1.is_open() || !file2.is_open())
90 return false;
91
92 const int BUFFER_SIZE = 2056;
93 char buffer1[BUFFER_SIZE], buffer2[BUFFER_SIZE];
94 do {
95 file1.read(buffer1, BUFFER_SIZE);
96 file2.read(buffer2, BUFFER_SIZE);
97
mark@chromium.orgb81637c32009-06-26 21:17:2498 if ((file1.eof() != file2.eof()) ||
initial.commitd7cae122008-07-26 21:49:3899 (file1.gcount() != file2.gcount()) ||
100 (memcmp(buffer1, buffer2, file1.gcount()))) {
101 file1.close();
102 file2.close();
103 return false;
104 }
mark@chromium.orgb81637c32009-06-26 21:17:24105 } while (!file1.eof() || !file2.eof());
initial.commitd7cae122008-07-26 21:49:38106
107 file1.close();
108 file2.close();
109 return true;
110}
111
mark@chromium.orgb81637c32009-06-26 21:17:24112bool TextContentsEqual(const FilePath& filename1, const FilePath& filename2) {
113 std::ifstream file1(filename1.value().c_str(), std::ios::in);
114 std::ifstream file2(filename2.value().c_str(), std::ios::in);
115
116 // Even if both files aren't openable (and thus, in some sense, "equal"),
117 // any unusable file yields a result of "false".
118 if (!file1.is_open() || !file2.is_open())
119 return false;
120
121 do {
122 std::string line1, line2;
123 getline(file1, line1);
124 getline(file2, line2);
125
126 // Check for mismatched EOF states, or any error state.
127 if ((file1.eof() != file2.eof()) ||
128 file1.bad() || file2.bad()) {
129 return false;
130 }
131
132 // Trim all '\r' and '\n' characters from the end of the line.
133 std::string::size_type end1 = line1.find_last_not_of("\r\n");
134 if (end1 == std::string::npos)
135 line1.clear();
136 else if (end1 + 1 < line1.length())
137 line1.erase(end1 + 1);
138
139 std::string::size_type end2 = line2.find_last_not_of("\r\n");
140 if (end2 == std::string::npos)
141 line2.clear();
142 else if (end2 + 1 < line2.length())
143 line2.erase(end2 + 1);
144
145 if (line1 != line2)
146 return false;
147 } while (!file1.eof() || !file2.eof());
148
149 return true;
150}
151
erikkay@google.com3c5281022009-01-28 00:22:46152bool ReadFileToString(const FilePath& path, std::string* contents) {
mark@chromium.org836f1342008-10-01 17:40:13153 FILE* file = OpenFile(path, "rb");
154 if (!file) {
initial.commitd7cae122008-07-26 21:49:38155 return false;
mark@chromium.org836f1342008-10-01 17:40:13156 }
initial.commitd7cae122008-07-26 21:49:38157
158 char buf[1 << 16];
159 size_t len;
160 while ((len = fread(buf, 1, sizeof(buf), file)) > 0) {
evan@chromium.org4e074bae2010-05-19 11:07:55161 if (contents)
162 contents->append(buf, len);
initial.commitd7cae122008-07-26 21:49:38163 }
mark@chromium.org836f1342008-10-01 17:40:13164 CloseFile(file);
initial.commitd7cae122008-07-26 21:49:38165
166 return true;
initial.commitd7cae122008-07-26 21:49:38167}
168
tfarina@chromium.orgb33f1d92010-05-26 01:40:12169bool IsDirectoryEmpty(const FilePath& dir_path) {
170 FileEnumerator files(dir_path, false,
tfarina@chromium.org58b7c5a62011-08-15 13:09:27171 static_cast<FileEnumerator::FileType>(
tfarina@chromium.orgb33f1d92010-05-26 01:40:12172 FileEnumerator::FILES | FileEnumerator::DIRECTORIES));
173 if (files.Next().value().empty())
174 return true;
175 return false;
176}
177
phajdan.jr@chromium.org6faa0e0d2009-04-28 06:50:36178FILE* CreateAndOpenTemporaryFile(FilePath* path) {
179 FilePath directory;
180 if (!GetTempDir(&directory))
evan@chromium.org628476aa2010-06-10 22:56:23181 return NULL;
phajdan.jr@chromium.org6faa0e0d2009-04-28 06:50:36182
183 return CreateAndOpenTemporaryFileInDir(directory, path);
184}
185
dkegel@google.comeac0709a2008-11-04 21:00:46186bool GetFileSize(const FilePath& file_path, int64* file_size) {
dumi@chromium.org2f0193c22010-09-03 02:28:37187 base::PlatformFileInfo info;
darin@google.comf5e3da4d2008-09-26 01:04:08188 if (!GetFileInfo(file_path, &info))
189 return false;
190 *file_size = info.size;
191 return true;
192}
193
estade@chromium.org1525c682010-02-11 23:27:47194bool IsDot(const FilePath& path) {
195 return FILE_PATH_LITERAL(".") == path.BaseName().value();
196}
197
198bool IsDotDot(const FilePath& path) {
199 return FILE_PATH_LITERAL("..") == path.BaseName().value();
200}
201
dumi@chromium.org507fb9a2010-09-23 23:28:22202bool TouchFile(const FilePath& path,
203 const base::Time& last_accessed,
204 const base::Time& last_modified) {
205 base::PlatformFile file =
206 base::CreatePlatformFile(path,
207 base::PLATFORM_FILE_OPEN |
208 base::PLATFORM_FILE_WRITE_ATTRIBUTES,
209 NULL, NULL);
210 if (file != base::kInvalidPlatformFileValue) {
211 bool result = base::TouchPlatformFile(file, last_accessed, last_modified);
212 base::ClosePlatformFile(file);
213 return result;
214 }
215
216 return false;
217}
218
219bool SetLastModifiedTime(const FilePath& path,
220 const base::Time& last_modified) {
221 return TouchFile(path, last_modified, last_modified);
222}
223
mark@chromium.org836f1342008-10-01 17:40:13224bool CloseFile(FILE* file) {
sidchat@google.coma1a19502008-10-21 17:14:45225 if (file == NULL)
226 return true;
mark@chromium.org836f1342008-10-01 17:40:13227 return fclose(file) == 0;
jeremy@chromium.org6e01dae2009-01-27 17:13:02228}
229
jeremy@chromium.orgc2c998c2009-01-27 19:08:39230bool TruncateFile(FILE* file) {
231 if (file == NULL)
232 return false;
233 long current_offset = ftell(file);
234 if (current_offset == -1)
235 return false;
236#if defined(OS_WIN)
237 int fd = _fileno(file);
238 if (_chsize(fd, current_offset) != 0)
239 return false;
240#else
241 int fd = fileno(file);
242 if (ftruncate(fd, current_offset) != 0)
243 return false;
244#endif
245 return true;
246}
247
jam@chromium.orge285afa2012-01-31 23:16:39248int GetUniquePathNumber(
249 const FilePath& path,
250 const FilePath::StringType& suffix) {
251 bool have_suffix = !suffix.empty();
252 if (!PathExists(path) &&
253 (!have_suffix || !PathExists(FilePath(path.value() + suffix)))) {
254 return 0;
255 }
256
257 FilePath new_path;
258 for (int count = 1; count <= kMaxUniqueFiles; ++count) {
259 new_path = path.InsertBeforeExtensionASCII(StringPrintf(" (%d)", count));
260 if (!PathExists(new_path) &&
261 (!have_suffix || !PathExists(FilePath(new_path.value() + suffix)))) {
262 return count;
263 }
264 }
265
266 return -1;
267}
268
aa@chromium.orgee5c29da2009-01-09 22:14:27269bool ContainsPath(const FilePath &parent, const FilePath& child) {
270 FilePath abs_parent = FilePath(parent);
271 FilePath abs_child = FilePath(child);
272
273 if (!file_util::AbsolutePath(&abs_parent) ||
274 !file_util::AbsolutePath(&abs_child))
275 return false;
276
277#if defined(OS_WIN)
278 // file_util::AbsolutePath() does not flatten case on Windows, so we must do
279 // a case-insensitive compare.
280 if (!StartsWith(abs_child.value(), abs_parent.value(), false))
281#else
282 if (!StartsWithASCII(abs_child.value(), abs_parent.value(), true))
283#endif
284 return false;
285
286 // file_util::AbsolutePath() normalizes '/' to '\' on Windows, so we only need
287 // to check kSeparators[0].
288 if (abs_child.value().length() <= abs_parent.value().length() ||
289 abs_child.value()[abs_parent.value().length()] !=
290 FilePath::kSeparators[0])
291 return false;
292
293 return true;
294}
295
cpu@chromium.orgc2c132c2010-03-24 21:56:26296int64 ComputeDirectorySize(const FilePath& root_path) {
297 int64 running_size = 0;
298 FileEnumerator file_iter(root_path, true, FileEnumerator::FILES);
299 for (FilePath current = file_iter.Next(); !current.empty();
300 current = file_iter.Next()) {
301 FileEnumerator::FindInfo info;
302 file_iter.GetFindInfo(&info);
303#if defined(OS_WIN)
304 LARGE_INTEGER li = { info.nFileSizeLow, info.nFileSizeHigh };
305 running_size += li.QuadPart;
306#else
307 running_size += info.stat.st_size;
308#endif
309 }
310 return running_size;
311}
312
rvargas@google.coma04876b2010-06-11 22:53:43313int64 ComputeFilesSize(const FilePath& directory,
314 const FilePath::StringType& pattern) {
315 int64 running_size = 0;
316 FileEnumerator file_iter(directory, false, FileEnumerator::FILES, pattern);
317 for (FilePath current = file_iter.Next(); !current.empty();
318 current = file_iter.Next()) {
319 FileEnumerator::FindInfo info;
320 file_iter.GetFindInfo(&info);
321#if defined(OS_WIN)
322 LARGE_INTEGER li = { info.nFileSizeLow, info.nFileSizeHigh };
323 running_size += li.QuadPart;
324#else
325 running_size += info.stat.st_size;
326#endif
327 }
328 return running_size;
329}
330
estade@chromium.org7856bb82008-12-12 23:43:03331///////////////////////////////////////////////
332// MemoryMappedFile
333
334MemoryMappedFile::~MemoryMappedFile() {
335 CloseHandles();
336}
337
erg@google.comeae9c062011-01-11 00:50:59338bool MemoryMappedFile::Initialize(const FilePath& file_name) {
339 if (IsValid())
340 return false;
341
342 if (!MapFileToMemory(file_name)) {
343 CloseHandles();
344 return false;
345 }
346
347 return true;
348}
349
estade@chromium.orgcb6037d2009-11-16 22:55:17350bool MemoryMappedFile::Initialize(base::PlatformFile file) {
351 if (IsValid())
352 return false;
353
354 file_ = file;
355
356 if (!MapFileToMemoryInternal()) {
357 CloseHandles();
358 return false;
359 }
360
361 return true;
362}
363
tommi@chromium.orge318fe52011-02-23 21:42:48364bool MemoryMappedFile::IsValid() const {
erg@google.comeae9c062011-01-11 00:50:59365 return data_ != NULL;
estade@chromium.org4e1c76f2009-11-13 01:36:50366}
367
estade@chromium.orgcb6037d2009-11-16 22:55:17368bool MemoryMappedFile::MapFileToMemory(const FilePath& file_name) {
dumi@chromium.orged65fec2010-08-31 19:30:27369 file_ = base::CreatePlatformFile(
370 file_name, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ,
371 NULL, NULL);
estade@chromium.orgcb6037d2009-11-16 22:55:17372
373 if (file_ == base::kInvalidPlatformFileValue) {
brettw@chromium.orga42d4632011-10-26 21:48:00374 DLOG(ERROR) << "Couldn't open " << file_name.value();
estade@chromium.orgcb6037d2009-11-16 22:55:17375 return false;
376 }
377
378 return MapFileToMemoryInternal();
estade@chromium.org7856bb82008-12-12 23:43:03379}
380
evanm@google.com640517f2008-10-30 23:54:04381// Deprecated functions ----------------------------------------------------
382
evan@chromium.org94f9c5262010-10-13 22:43:06383#if defined(OS_WIN)
estade@chromium.orgb9e04f02008-11-27 04:03:57384void AppendToPath(std::wstring* path, const std::wstring& new_ending) {
385 if (!path) {
386 NOTREACHED();
387 return; // Don't crash in this function in release builds.
388 }
389
tfarina@chromium.org147ff1242010-06-21 03:05:19390 if (!EndsWithSeparator(FilePath(*path)))
estade@chromium.orgb9e04f02008-11-27 04:03:57391 path->push_back(FilePath::kSeparators[0]);
392 path->append(new_ending);
evanm@google.com640517f2008-10-30 23:54:04393}
evan@chromium.org1840cfc2010-02-26 15:11:55394
evanm@google.com640517f2008-10-30 23:54:04395bool CopyDirectory(const std::wstring& from_path, const std::wstring& to_path,
396 bool recursive) {
397 return CopyDirectory(FilePath::FromWStringHack(from_path),
398 FilePath::FromWStringHack(to_path),
399 recursive);
400}
estade@chromium.orgb9e04f02008-11-27 04:03:57401bool Delete(const std::wstring& path, bool recursive) {
402 return Delete(FilePath::FromWStringHack(path), recursive);
estade@chromium.orgb9e04f02008-11-27 04:03:57403}
estade@chromium.org7ae7c2cb2009-01-06 23:31:41404std::wstring GetFileExtensionFromPath(const std::wstring& path) {
tfarina@chromium.orgb70f8522011-08-04 19:45:42405 std::wstring file_name = FilePath(path).BaseName().value();
406 const std::wstring::size_type last_dot = file_name.rfind(kExtensionSeparator);
407 return std::wstring(last_dot == std::wstring::npos ? L""
408 : file_name, last_dot + 1);
estade@chromium.org7ae7c2cb2009-01-06 23:31:41409}
estade@chromium.orga9cd2a652008-11-17 21:01:19410FILE* OpenFile(const std::wstring& filename, const char* mode) {
411 return OpenFile(FilePath::FromWStringHack(filename), mode);
estade@chromium.org6ec54c12009-10-15 03:41:02412}
estade@chromium.orgc870c762009-01-28 05:47:15413int ReadFile(const std::wstring& filename, char* data, int size) {
414 return ReadFile(FilePath::FromWStringHack(filename), data, size);
415}
estade@chromium.orgc870c762009-01-28 05:47:15416int WriteFile(const std::wstring& filename, const char* data, int size) {
417 return WriteFile(FilePath::FromWStringHack(filename), data, size);
418}
evan@chromium.org94f9c5262010-10-13 22:43:06419#endif // OS_WIN
yuzo@chromium.org8199b3a2009-06-09 05:57:38420
421///////////////////////////////////////////////
422// FileEnumerator
423//
424// Note: the main logic is in file_util_<platform>.cc
425
426bool FileEnumerator::ShouldSkip(const FilePath& path) {
427 FilePath::StringType basename = path.BaseName().value();
428 return IsDot(path) || (IsDotDot(path) && !(INCLUDE_DOT_DOT & file_type_));
yuzo@chromium.org8199b3a2009-06-09 05:57:38429}
430
initial.commitd7cae122008-07-26 21:49:38431} // namespace