blob: 505dfb4c07a9fd74d3e0b10ee1837811f825d903 [file] [log] [blame]
[email protected]12adfaa72009-04-07 21:02:111// Copyright (c) 2006-2009 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"
initial.commitd7cae122008-07-26 21:49:3816#include "base/string_util.h"
initial.commitd7cae122008-07-26 21:49:3817
[email protected]b9e04f02008-11-27 04:03:5718#include "base/string_piece.h"
19#include "base/sys_string_conversions.h"
20
[email protected]ceeb87e2008-12-04 20:46:0621namespace {
22
23const FilePath::CharType kExtensionSeparator = FILE_PATH_LITERAL('.');
24
[email protected]c145cbdd2009-04-24 17:44:3925} // namespace
[email protected]ceeb87e2008-12-04 20:46:0626
initial.commitd7cae122008-07-26 21:49:3827namespace file_util {
28
[email protected]b9e04f02008-11-27 04:03:5729bool EndsWithSeparator(const FilePath& path) {
30 FilePath::StringType value = path.value();
31 if (value.empty())
32 return false;
33
34 return FilePath::IsSeparator(value[value.size() - 1]);
initial.commitd7cae122008-07-26 21:49:3835}
36
[email protected]7e263942008-11-25 22:04:3737bool EnsureEndsWithSeparator(FilePath* path) {
38 if (!DirectoryExists(*path))
39 return false;
40
41 if (EndsWithSeparator(*path))
42 return true;
43
44 FilePath::StringType& path_str =
45 const_cast<FilePath::StringType&>(path->value());
46 path_str.append(&FilePath::kSeparators[0], 1);
47
48 return true;
49}
50
[email protected]a97f2b42009-04-21 23:15:4551void TrimTrailingSeparator(std::wstring* dir) {
52 while (dir->length() > 1 && EndsWithSeparator(dir))
53 dir->resize(dir->length() - 1);
54}
55
[email protected]7ae7c2cb2009-01-06 23:31:4156FilePath::StringType GetFileExtensionFromPath(const FilePath& path) {
57 FilePath::StringType file_name = path.BaseName().value();
58 const FilePath::StringType::size_type last_dot =
59 file_name.rfind(kExtensionSeparator);
60 return FilePath::StringType(last_dot == FilePath::StringType::npos ?
61 FILE_PATH_LITERAL("") :
62 file_name, last_dot+1);
[email protected]52ab8f902008-11-03 16:14:4663}
64
[email protected]ceeb87e2008-12-04 20:46:0665void InsertBeforeExtension(FilePath* path, const FilePath::StringType& suffix) {
66 FilePath::StringType& value =
67 const_cast<FilePath::StringType&>(path->value());
68
69 const FilePath::StringType::size_type last_dot =
70 value.rfind(kExtensionSeparator);
71 const FilePath::StringType::size_type last_separator =
72 value.find_last_of(FilePath::StringType(FilePath::kSeparators));
73
74 if (last_dot == FilePath::StringType::npos ||
75 (last_separator != std::wstring::npos && last_dot < last_separator)) {
76 // The path looks something like "C:\pics.old\jojo" or "C:\pics\jojo".
77 // We should just append the suffix to the entire path.
78 value.append(suffix);
79 return;
80 }
81
82 value.insert(last_dot, suffix);
83}
84
85void ReplaceExtension(FilePath* path, const FilePath::StringType& extension) {
86 FilePath::StringType clean_extension;
87 // If the new extension is "" or ".", then we will just remove the current
88 // extension.
89 if (!extension.empty() &&
90 extension != FilePath::StringType(&kExtensionSeparator, 1)) {
91 if (extension[0] != kExtensionSeparator)
92 clean_extension.append(&kExtensionSeparator, 1);
93 clean_extension.append(extension);
94 }
95
96 FilePath::StringType& value =
97 const_cast<FilePath::StringType&>(path->value());
98 const FilePath::StringType::size_type last_dot =
99 value.rfind(kExtensionSeparator);
100 const FilePath::StringType::size_type last_separator =
101 value.find_last_of(FilePath::StringType(FilePath::kSeparators));
102
103 // Erase the current extension, if any.
104 if ((last_dot > last_separator ||
105 last_separator == FilePath::StringType::npos) &&
106 last_dot != FilePath::StringType::npos)
107 value.erase(last_dot);
108
109 value.append(clean_extension);
110}
111
[email protected]640517f2008-10-30 23:54:04112bool ContentsEqual(const FilePath& filename1, const FilePath& filename2) {
initial.commitd7cae122008-07-26 21:49:38113 // We open the file in binary format even if they are text files because
114 // we are just comparing that bytes are exactly same in both files and not
115 // doing anything smart with text formatting.
[email protected]640517f2008-10-30 23:54:04116 std::ifstream file1(filename1.value().c_str(),
[email protected]5af2edb92008-08-08 20:16:08117 std::ios::in | std::ios::binary);
[email protected]640517f2008-10-30 23:54:04118 std::ifstream file2(filename2.value().c_str(),
[email protected]5af2edb92008-08-08 20:16:08119 std::ios::in | std::ios::binary);
[email protected]b9e04f02008-11-27 04:03:57120
initial.commitd7cae122008-07-26 21:49:38121 // Even if both files aren't openable (and thus, in some sense, "equal"),
122 // any unusable file yields a result of "false".
123 if (!file1.is_open() || !file2.is_open())
124 return false;
125
126 const int BUFFER_SIZE = 2056;
127 char buffer1[BUFFER_SIZE], buffer2[BUFFER_SIZE];
128 do {
129 file1.read(buffer1, BUFFER_SIZE);
130 file2.read(buffer2, BUFFER_SIZE);
131
[email protected]b81637c32009-06-26 21:17:24132 if ((file1.eof() != file2.eof()) ||
initial.commitd7cae122008-07-26 21:49:38133 (file1.gcount() != file2.gcount()) ||
134 (memcmp(buffer1, buffer2, file1.gcount()))) {
135 file1.close();
136 file2.close();
137 return false;
138 }
[email protected]b81637c32009-06-26 21:17:24139 } while (!file1.eof() || !file2.eof());
initial.commitd7cae122008-07-26 21:49:38140
141 file1.close();
142 file2.close();
143 return true;
144}
145
[email protected]b81637c32009-06-26 21:17:24146bool TextContentsEqual(const FilePath& filename1, const FilePath& filename2) {
147 std::ifstream file1(filename1.value().c_str(), std::ios::in);
148 std::ifstream file2(filename2.value().c_str(), std::ios::in);
149
150 // Even if both files aren't openable (and thus, in some sense, "equal"),
151 // any unusable file yields a result of "false".
152 if (!file1.is_open() || !file2.is_open())
153 return false;
154
155 do {
156 std::string line1, line2;
157 getline(file1, line1);
158 getline(file2, line2);
159
160 // Check for mismatched EOF states, or any error state.
161 if ((file1.eof() != file2.eof()) ||
162 file1.bad() || file2.bad()) {
163 return false;
164 }
165
166 // Trim all '\r' and '\n' characters from the end of the line.
167 std::string::size_type end1 = line1.find_last_not_of("\r\n");
168 if (end1 == std::string::npos)
169 line1.clear();
170 else if (end1 + 1 < line1.length())
171 line1.erase(end1 + 1);
172
173 std::string::size_type end2 = line2.find_last_not_of("\r\n");
174 if (end2 == std::string::npos)
175 line2.clear();
176 else if (end2 + 1 < line2.length())
177 line2.erase(end2 + 1);
178
179 if (line1 != line2)
180 return false;
181 } while (!file1.eof() || !file2.eof());
182
183 return true;
184}
185
[email protected]3c5281022009-01-28 00:22:46186bool ReadFileToString(const FilePath& path, std::string* contents) {
[email protected]836f1342008-10-01 17:40:13187 FILE* file = OpenFile(path, "rb");
188 if (!file) {
initial.commitd7cae122008-07-26 21:49:38189 return false;
[email protected]836f1342008-10-01 17:40:13190 }
initial.commitd7cae122008-07-26 21:49:38191
192 char buf[1 << 16];
193 size_t len;
194 while ((len = fread(buf, 1, sizeof(buf), file)) > 0) {
195 contents->append(buf, len);
196 }
[email protected]836f1342008-10-01 17:40:13197 CloseFile(file);
initial.commitd7cae122008-07-26 21:49:38198
199 return true;
200}
201
[email protected]6faa0e0d2009-04-28 06:50:36202FILE* CreateAndOpenTemporaryFile(FilePath* path) {
203 FilePath directory;
204 if (!GetTempDir(&directory))
205 return false;
206
207 return CreateAndOpenTemporaryFileInDir(directory, path);
208}
209
[email protected]eac0709a2008-11-04 21:00:46210bool GetFileSize(const FilePath& file_path, int64* file_size) {
[email protected]f5e3da4d2008-09-26 01:04:08211 FileInfo info;
212 if (!GetFileInfo(file_path, &info))
213 return false;
214 *file_size = info.size;
215 return true;
216}
217
[email protected]836f1342008-10-01 17:40:13218bool CloseFile(FILE* file) {
[email protected]a1a19502008-10-21 17:14:45219 if (file == NULL)
220 return true;
[email protected]836f1342008-10-01 17:40:13221 return fclose(file) == 0;
222}
223
[email protected]c2c998c2009-01-27 19:08:39224bool TruncateFile(FILE* file) {
225 if (file == NULL)
226 return false;
227 long current_offset = ftell(file);
228 if (current_offset == -1)
229 return false;
230#if defined(OS_WIN)
231 int fd = _fileno(file);
232 if (_chsize(fd, current_offset) != 0)
233 return false;
234#else
235 int fd = fileno(file);
236 if (ftruncate(fd, current_offset) != 0)
237 return false;
238#endif
239 return true;
240}
241
[email protected]ee5c29da2009-01-09 22:14:27242bool ContainsPath(const FilePath &parent, const FilePath& child) {
243 FilePath abs_parent = FilePath(parent);
244 FilePath abs_child = FilePath(child);
245
246 if (!file_util::AbsolutePath(&abs_parent) ||
247 !file_util::AbsolutePath(&abs_child))
248 return false;
249
250#if defined(OS_WIN)
251 // file_util::AbsolutePath() does not flatten case on Windows, so we must do
252 // a case-insensitive compare.
253 if (!StartsWith(abs_child.value(), abs_parent.value(), false))
254#else
255 if (!StartsWithASCII(abs_child.value(), abs_parent.value(), true))
256#endif
257 return false;
258
259 // file_util::AbsolutePath() normalizes '/' to '\' on Windows, so we only need
260 // to check kSeparators[0].
261 if (abs_child.value().length() <= abs_parent.value().length() ||
262 abs_child.value()[abs_parent.value().length()] !=
263 FilePath::kSeparators[0])
264 return false;
265
266 return true;
267}
268
[email protected]7856bb82008-12-12 23:43:03269///////////////////////////////////////////////
270// MemoryMappedFile
271
272MemoryMappedFile::~MemoryMappedFile() {
273 CloseHandles();
274}
275
276bool MemoryMappedFile::Initialize(const FilePath& file_name) {
277 if (IsValid())
278 return false;
279
280 if (!MapFileToMemory(file_name)) {
281 CloseHandles();
282 return false;
283 }
284
285 return true;
286}
287
288bool MemoryMappedFile::IsValid() {
289 return data_ != NULL;
290}
291
[email protected]640517f2008-10-30 23:54:04292// Deprecated functions ----------------------------------------------------
293
[email protected]3c5281022009-01-28 00:22:46294bool ReadFileToString(const std::wstring& path, std::string* contents) {
295 return ReadFileToString(FilePath::FromWStringHack(path), contents);
296}
297
[email protected]640517f2008-10-30 23:54:04298bool AbsolutePath(std::wstring* path_str) {
[email protected]4a2952f2008-10-31 02:03:07299 FilePath path(FilePath::FromWStringHack(*path_str));
[email protected]640517f2008-10-30 23:54:04300 if (!AbsolutePath(&path))
301 return false;
302 *path_str = path.ToWStringHack();
303 return true;
304}
[email protected]b9e04f02008-11-27 04:03:57305void AppendToPath(std::wstring* path, const std::wstring& new_ending) {
306 if (!path) {
307 NOTREACHED();
308 return; // Don't crash in this function in release builds.
309 }
310
311 if (!EndsWithSeparator(path))
312 path->push_back(FilePath::kSeparators[0]);
313 path->append(new_ending);
[email protected]640517f2008-10-30 23:54:04314}
315bool CopyDirectory(const std::wstring& from_path, const std::wstring& to_path,
316 bool recursive) {
317 return CopyDirectory(FilePath::FromWStringHack(from_path),
318 FilePath::FromWStringHack(to_path),
319 recursive);
320}
[email protected]640517f2008-10-30 23:54:04321bool ContentsEqual(const std::wstring& filename1,
322 const std::wstring& filename2) {
323 return ContentsEqual(FilePath::FromWStringHack(filename1),
324 FilePath::FromWStringHack(filename2));
325}
[email protected]b9e04f02008-11-27 04:03:57326bool CopyFile(const std::wstring& from_path, const std::wstring& to_path) {
327 return CopyFile(FilePath::FromWStringHack(from_path),
328 FilePath::FromWStringHack(to_path));
329}
[email protected]640517f2008-10-30 23:54:04330bool CreateDirectory(const std::wstring& full_path) {
331 return CreateDirectory(FilePath::FromWStringHack(full_path));
332}
[email protected]7e1fde6a2008-12-23 20:20:10333bool CreateNewTempDirectory(const std::wstring& prefix,
334 std::wstring* new_temp_path) {
335#if defined(OS_WIN)
336 FilePath::StringType dir_prefix(prefix);
337#elif defined(OS_POSIX)
338 FilePath::StringType dir_prefix = WideToUTF8(prefix);
339#endif
340 FilePath temp_path;
341 if (!CreateNewTempDirectory(dir_prefix, &temp_path))
342 return false;
343 *new_temp_path = temp_path.ToWStringHack();
344 return true;
345}
[email protected]392264c2008-11-11 00:01:38346bool CreateTemporaryFileName(std::wstring* temp_file) {
347 FilePath temp_file_path;
348 if (!CreateTemporaryFileName(&temp_file_path))
349 return false;
350 *temp_file = temp_file_path.ToWStringHack();
351 return true;
352}
[email protected]b9e04f02008-11-27 04:03:57353bool Delete(const std::wstring& path, bool recursive) {
354 return Delete(FilePath::FromWStringHack(path), recursive);
355}
356bool DirectoryExists(const std::wstring& path) {
357 return DirectoryExists(FilePath::FromWStringHack(path));
358}
359bool EndsWithSeparator(std::wstring* path) {
360 return EndsWithSeparator(FilePath::FromWStringHack(*path));
361}
362bool EndsWithSeparator(const std::wstring& path) {
363 return EndsWithSeparator(FilePath::FromWStringHack(path));
364}
[email protected]640517f2008-10-30 23:54:04365bool GetCurrentDirectory(std::wstring* path_str) {
366 FilePath path;
367 if (!GetCurrentDirectory(&path))
368 return false;
369 *path_str = path.ToWStringHack();
370 return true;
371}
[email protected]7ae7c2cb2009-01-06 23:31:41372std::wstring GetFileExtensionFromPath(const std::wstring& path) {
373 FilePath::StringType extension =
374 GetFileExtensionFromPath(FilePath::FromWStringHack(path));
375#if defined(OS_WIN)
376 return extension;
377#elif defined(OS_POSIX)
378 return UTF8ToWide(extension);
379#endif
380}
[email protected]eac0709a2008-11-04 21:00:46381bool GetFileInfo(const std::wstring& file_path, FileInfo* results) {
382 return GetFileInfo(FilePath::FromWStringHack(file_path), results);
383}
[email protected]ceeb87e2008-12-04 20:46:06384std::wstring GetFilenameFromPath(const std::wstring& path) {
385 if (path.empty() || EndsWithSeparator(path))
386 return std::wstring();
387
[email protected]5e207882009-01-05 23:59:36388 return FilePath::FromWStringHack(path).BaseName().ToWStringHack();
[email protected]ceeb87e2008-12-04 20:46:06389}
[email protected]eac0709a2008-11-04 21:00:46390bool GetFileSize(const std::wstring& file_path, int64* file_size) {
391 return GetFileSize(FilePath::FromWStringHack(file_path), file_size);
392}
[email protected]640517f2008-10-30 23:54:04393bool GetTempDir(std::wstring* path_str) {
394 FilePath path;
395 if (!GetTempDir(&path))
396 return false;
397 *path_str = path.ToWStringHack();
398 return true;
399}
[email protected]b9e04f02008-11-27 04:03:57400bool Move(const std::wstring& from_path, const std::wstring& to_path) {
401 return Move(FilePath::FromWStringHack(from_path),
402 FilePath::FromWStringHack(to_path));
403}
[email protected]a9cd2a652008-11-17 21:01:19404FILE* OpenFile(const std::wstring& filename, const char* mode) {
405 return OpenFile(FilePath::FromWStringHack(filename), mode);
406}
[email protected]b9e04f02008-11-27 04:03:57407bool PathExists(const std::wstring& path) {
408 return PathExists(FilePath::FromWStringHack(path));
409}
[email protected]7e1fde6a2008-12-23 20:20:10410bool PathIsWritable(const std::wstring& path) {
411 return PathIsWritable(FilePath::FromWStringHack(path));
412}
[email protected]c870c762009-01-28 05:47:15413int ReadFile(const std::wstring& filename, char* data, int size) {
414 return ReadFile(FilePath::FromWStringHack(filename), data, size);
415}
[email protected]a9cd2a652008-11-17 21:01:19416bool SetCurrentDirectory(const std::wstring& directory) {
417 return SetCurrentDirectory(FilePath::FromWStringHack(directory));
418}
[email protected]b9e04f02008-11-27 04:03:57419void UpOneDirectory(std::wstring* dir) {
420 FilePath path = FilePath::FromWStringHack(*dir);
421 FilePath directory = path.DirName();
422 // If there is no separator, we will get back kCurrentDirectory.
423 // In this case don't change |dir|.
424 if (directory.value() != FilePath::kCurrentDirectory)
425 *dir = directory.ToWStringHack();
426}
427void UpOneDirectoryOrEmpty(std::wstring* dir) {
428 FilePath path = FilePath::FromWStringHack(*dir);
429 FilePath directory = path.DirName();
430 // If there is no separator, we will get back kCurrentDirectory.
431 // In this case, clear dir.
432 if (directory == path || directory.value() == FilePath::kCurrentDirectory)
433 dir->clear();
434 else
435 *dir = directory.ToWStringHack();
436}
[email protected]c870c762009-01-28 05:47:15437int WriteFile(const std::wstring& filename, const char* data, int size) {
438 return WriteFile(FilePath::FromWStringHack(filename), data, size);
439}
[email protected]8199b3a2009-06-09 05:57:38440
441///////////////////////////////////////////////
442// FileEnumerator
443//
444// Note: the main logic is in file_util_<platform>.cc
445
446bool FileEnumerator::ShouldSkip(const FilePath& path) {
447 FilePath::StringType basename = path.BaseName().value();
448 return IsDot(path) || (IsDotDot(path) && !(INCLUDE_DOT_DOT & file_type_));
449}
450
451bool FileEnumerator::IsDot(const FilePath& path) {
452 return FILE_PATH_LITERAL(".") == path.BaseName().value();
453}
454
455bool FileEnumerator::IsDotDot(const FilePath& path) {
456 return FILE_PATH_LITERAL("..") == path.BaseName().value();
457}
458
initial.commitd7cae122008-07-26 21:49:38459} // namespace