[go: nahoru, domu]

blob: 5ce445663618f31f5b6a8d7ac101f1cec2c5428e [file] [log] [blame]
tfarina@chromium.orgb33f1d92010-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
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"
estade@chromium.orgb9e04f02008-11-27 04:03:5716#include "base/string_piece.h"
brettw@chromium.org047a03f2009-10-07 02:10:2017#include "base/string_util.h"
18#include "base/utf_string_conversions.h"
estade@chromium.orgb9e04f02008-11-27 04:03:5719
estade@chromium.orgceeb87e2008-12-04 20:46:0620namespace {
21
22const FilePath::CharType kExtensionSeparator = FILE_PATH_LITERAL('.');
23
willchan@chromium.orgc145cbdd2009-04-24 17:44:3924} // namespace
estade@chromium.orgceeb87e2008-12-04 20:46:0625
initial.commitd7cae122008-07-26 21:49:3826namespace file_util {
27
estade@chromium.orgb9e04f02008-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]);
estade@chromium.org7e263942008-11-25 22:04:3734}
35
36bool 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;
initial.commitd7cae122008-07-26 21:49:3848}
49
estade@chromium.org7ae7c2cb2009-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);
glen@chromium.org52ab8f902008-11-03 16:14:4657}
58
estade@chromium.orgceeb87e2008-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
evanm@google.com640517f2008-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.
evanm@google.com640517f2008-10-30 23:54:0483 std::ifstream file1(filename1.value().c_str(),
erikkay@google.com5af2edb92008-08-08 20:16:0884 std::ios::in | std::ios::binary);
evanm@google.com640517f2008-10-30 23:54:0485 std::ifstream file2(filename2.value().c_str(),
erikkay@google.com5af2edb92008-08-08 20:16:0886 std::ios::in | std::ios::binary);
estade@chromium.orgb9e04f02008-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
mark@chromium.orgb81637c32009-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 }
mark@chromium.orgb81637c32009-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
mark@chromium.orgb81637c32009-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
erikkay@google.com3c5281022009-01-28 00:22:46153bool ReadFileToString(const FilePath& path, std::string* contents) {
mark@chromium.org836f1342008-10-01 17:40:13154 FILE* file = OpenFile(path, "rb");
155 if (!file) {
initial.commitd7cae122008-07-26 21:49:38156 return false;
mark@chromium.org836f1342008-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) {
evan@chromium.org4e074bae2010-05-19 11:07:55162 if (contents)
163 contents->append(buf, len);
initial.commitd7cae122008-07-26 21:49:38164 }
mark@chromium.org836f1342008-10-01 17:40:13165 CloseFile(file);
initial.commitd7cae122008-07-26 21:49:38166
167 return true;
initial.commitd7cae122008-07-26 21:49:38168}
169
tfarina@chromium.orgb33f1d92010-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
phajdan.jr@chromium.org6faa0e0d2009-04-28 06:50:36179FILE* CreateAndOpenTemporaryFile(FilePath* path) {
180 FilePath directory;
181 if (!GetTempDir(&directory))
evan@chromium.org628476aa2010-06-10 22:56:23182 return NULL;
phajdan.jr@chromium.org6faa0e0d2009-04-28 06:50:36183
184 return CreateAndOpenTemporaryFileInDir(directory, path);
185}
186
dkegel@google.comeac0709a2008-11-04 21:00:46187bool GetFileSize(const FilePath& file_path, int64* file_size) {
darin@google.comf5e3da4d2008-09-26 01:04:08188 FileInfo info;
189 if (!GetFileInfo(file_path, &info))
190 return false;
191 *file_size = info.size;
192 return true;
193}
194
estade@chromium.org1525c682010-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
mark@chromium.org836f1342008-10-01 17:40:13203bool CloseFile(FILE* file) {
sidchat@google.coma1a19502008-10-21 17:14:45204 if (file == NULL)
205 return true;
mark@chromium.org836f1342008-10-01 17:40:13206 return fclose(file) == 0;
jeremy@chromium.org6e01dae2009-01-27 17:13:02207}
208
jeremy@chromium.orgc2c998c2009-01-27 19:08:39209bool TruncateFile(FILE* file) {
210 if (file == NULL)
211 return false;
212 long current_offset = ftell(file);
213 if (current_offset == -1)
214 return false;
215#if defined(OS_WIN)
216 int fd = _fileno(file);
217 if (_chsize(fd, current_offset) != 0)
218 return false;
219#else
220 int fd = fileno(file);
221 if (ftruncate(fd, current_offset) != 0)
222 return false;
223#endif
224 return true;
225}
226
aa@chromium.orgee5c29da2009-01-09 22:14:27227bool ContainsPath(const FilePath &parent, const FilePath& child) {
228 FilePath abs_parent = FilePath(parent);
229 FilePath abs_child = FilePath(child);
230
231 if (!file_util::AbsolutePath(&abs_parent) ||
232 !file_util::AbsolutePath(&abs_child))
233 return false;
234
235#if defined(OS_WIN)
236 // file_util::AbsolutePath() does not flatten case on Windows, so we must do
237 // a case-insensitive compare.
238 if (!StartsWith(abs_child.value(), abs_parent.value(), false))
239#else
240 if (!StartsWithASCII(abs_child.value(), abs_parent.value(), true))
241#endif
242 return false;
243
244 // file_util::AbsolutePath() normalizes '/' to '\' on Windows, so we only need
245 // to check kSeparators[0].
246 if (abs_child.value().length() <= abs_parent.value().length() ||
247 abs_child.value()[abs_parent.value().length()] !=
248 FilePath::kSeparators[0])
249 return false;
250
251 return true;
252}
253
cpu@chromium.orgc2c132c2010-03-24 21:56:26254int64 ComputeDirectorySize(const FilePath& root_path) {
255 int64 running_size = 0;
256 FileEnumerator file_iter(root_path, true, FileEnumerator::FILES);
257 for (FilePath current = file_iter.Next(); !current.empty();
258 current = file_iter.Next()) {
259 FileEnumerator::FindInfo info;
260 file_iter.GetFindInfo(&info);
261#if defined(OS_WIN)
262 LARGE_INTEGER li = { info.nFileSizeLow, info.nFileSizeHigh };
263 running_size += li.QuadPart;
264#else
265 running_size += info.stat.st_size;
266#endif
267 }
268 return running_size;
269}
270
rvargas@google.coma04876b2010-06-11 22:53:43271int64 ComputeFilesSize(const FilePath& directory,
272 const FilePath::StringType& pattern) {
273 int64 running_size = 0;
274 FileEnumerator file_iter(directory, false, FileEnumerator::FILES, pattern);
275 for (FilePath current = file_iter.Next(); !current.empty();
276 current = file_iter.Next()) {
277 FileEnumerator::FindInfo info;
278 file_iter.GetFindInfo(&info);
279#if defined(OS_WIN)
280 LARGE_INTEGER li = { info.nFileSizeLow, info.nFileSizeHigh };
281 running_size += li.QuadPart;
282#else
283 running_size += info.stat.st_size;
284#endif
285 }
286 return running_size;
287}
288
estade@chromium.org7856bb82008-12-12 23:43:03289///////////////////////////////////////////////
290// MemoryMappedFile
291
292MemoryMappedFile::~MemoryMappedFile() {
293 CloseHandles();
294}
295
estade@chromium.orgcb6037d2009-11-16 22:55:17296bool MemoryMappedFile::Initialize(base::PlatformFile file) {
297 if (IsValid())
298 return false;
299
300 file_ = file;
301
302 if (!MapFileToMemoryInternal()) {
303 CloseHandles();
304 return false;
305 }
306
307 return true;
308}
309
estade@chromium.org7856bb82008-12-12 23:43:03310bool MemoryMappedFile::Initialize(const FilePath& file_name) {
311 if (IsValid())
312 return false;
313
314 if (!MapFileToMemory(file_name)) {
315 CloseHandles();
316 return false;
317 }
318
319 return true;
estade@chromium.org4e1c76f2009-11-13 01:36:50320}
321
estade@chromium.orgcb6037d2009-11-16 22:55:17322bool MemoryMappedFile::MapFileToMemory(const FilePath& file_name) {
323 file_ = base::CreatePlatformFile(file_name,
324 base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ,
325 NULL);
326
327 if (file_ == base::kInvalidPlatformFileValue) {
328 LOG(ERROR) << "Couldn't open " << file_name.value();
329 return false;
330 }
331
332 return MapFileToMemoryInternal();
333}
334
estade@chromium.org7856bb82008-12-12 23:43:03335bool MemoryMappedFile::IsValid() {
336 return data_ != NULL;
337}
338
evanm@google.com640517f2008-10-30 23:54:04339// Deprecated functions ----------------------------------------------------
340
erikkay@google.com3c5281022009-01-28 00:22:46341bool ReadFileToString(const std::wstring& path, std::string* contents) {
342 return ReadFileToString(FilePath::FromWStringHack(path), contents);
343}
344
evan@chromium.org777d5902009-10-09 21:03:58345bool AbsolutePath(std::wstring* path_str) {
346 FilePath path(FilePath::FromWStringHack(*path_str));
347 if (!AbsolutePath(&path))
348 return false;
349 *path_str = path.ToWStringHack();
350 return true;
351}
evan@chromium.org1840cfc2010-02-26 15:11:55352
353#if defined(OS_WIN)
354// This function is deprecated; see file_util_deprecated.h for details.
estade@chromium.orgb9e04f02008-11-27 04:03:57355void AppendToPath(std::wstring* path, const std::wstring& new_ending) {
356 if (!path) {
357 NOTREACHED();
358 return; // Don't crash in this function in release builds.
359 }
360
evan@chromium.org1840cfc2010-02-26 15:11:55361 if (!EndsWithSeparator(*path))
estade@chromium.orgb9e04f02008-11-27 04:03:57362 path->push_back(FilePath::kSeparators[0]);
363 path->append(new_ending);
evanm@google.com640517f2008-10-30 23:54:04364}
evan@chromium.org1840cfc2010-02-26 15:11:55365#endif
366
evanm@google.com640517f2008-10-30 23:54:04367bool CopyDirectory(const std::wstring& from_path, const std::wstring& to_path,
368 bool recursive) {
369 return CopyDirectory(FilePath::FromWStringHack(from_path),
370 FilePath::FromWStringHack(to_path),
371 recursive);
372}
estade@chromium.orgb9e04f02008-11-27 04:03:57373bool Delete(const std::wstring& path, bool recursive) {
374 return Delete(FilePath::FromWStringHack(path), recursive);
estade@chromium.orgb9e04f02008-11-27 04:03:57375}
376bool EndsWithSeparator(const std::wstring& path) {
377 return EndsWithSeparator(FilePath::FromWStringHack(path));
estade@chromium.org392264c2008-11-11 00:01:38378}
estade@chromium.org7ae7c2cb2009-01-06 23:31:41379std::wstring GetFileExtensionFromPath(const std::wstring& path) {
380 FilePath::StringType extension =
381 GetFileExtensionFromPath(FilePath::FromWStringHack(path));
382#if defined(OS_WIN)
383 return extension;
384#elif defined(OS_POSIX)
385 return UTF8ToWide(extension);
386#endif
387}
estade@chromium.orgceeb87e2008-12-04 20:46:06388std::wstring GetFilenameFromPath(const std::wstring& path) {
389 if (path.empty() || EndsWithSeparator(path))
390 return std::wstring();
391
estade@chromium.org5e207882009-01-05 23:59:36392 return FilePath::FromWStringHack(path).BaseName().ToWStringHack();
evanm@google.com640517f2008-10-30 23:54:04393}
estade@chromium.orga9cd2a652008-11-17 21:01:19394FILE* OpenFile(const std::wstring& filename, const char* mode) {
395 return OpenFile(FilePath::FromWStringHack(filename), mode);
estade@chromium.org6ec54c12009-10-15 03:41:02396}
estade@chromium.orgc870c762009-01-28 05:47:15397int ReadFile(const std::wstring& filename, char* data, int size) {
398 return ReadFile(FilePath::FromWStringHack(filename), data, size);
399}
estade@chromium.orgb9e04f02008-11-27 04:03:57400void UpOneDirectory(std::wstring* dir) {
401 FilePath path = FilePath::FromWStringHack(*dir);
402 FilePath directory = path.DirName();
403 // If there is no separator, we will get back kCurrentDirectory.
404 // In this case don't change |dir|.
405 if (directory.value() != FilePath::kCurrentDirectory)
406 *dir = directory.ToWStringHack();
407}
408void UpOneDirectoryOrEmpty(std::wstring* dir) {
409 FilePath path = FilePath::FromWStringHack(*dir);
410 FilePath directory = path.DirName();
411 // If there is no separator, we will get back kCurrentDirectory.
412 // In this case, clear dir.
413 if (directory == path || directory.value() == FilePath::kCurrentDirectory)
414 dir->clear();
415 else
416 *dir = directory.ToWStringHack();
417}
estade@chromium.orgc870c762009-01-28 05:47:15418int WriteFile(const std::wstring& filename, const char* data, int size) {
419 return WriteFile(FilePath::FromWStringHack(filename), data, size);
420}
yuzo@chromium.org8199b3a2009-06-09 05:57:38421
422///////////////////////////////////////////////
423// FileEnumerator
424//
425// Note: the main logic is in file_util_<platform>.cc
426
427bool FileEnumerator::ShouldSkip(const FilePath& path) {
428 FilePath::StringType basename = path.BaseName().value();
429 return IsDot(path) || (IsDotDot(path) && !(INCLUDE_DOT_DOT & file_type_));
yuzo@chromium.org8199b3a2009-06-09 05:57:38430}
431
initial.commitd7cae122008-07-26 21:49:38432} // namespace