blob: c366a76e49e416054d0f9ec2cb9409141ec7aacb [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
132 if ((file1.eof() && !file2.eof()) ||
133 (!file1.eof() && file2.eof()) ||
134 (file1.gcount() != file2.gcount()) ||
135 (memcmp(buffer1, buffer2, file1.gcount()))) {
136 file1.close();
137 file2.close();
138 return false;
139 }
140 } while (!file1.eof() && !file2.eof());
141
142 file1.close();
143 file2.close();
144 return true;
145}
146
[email protected]3c5281022009-01-28 00:22:46147bool ReadFileToString(const FilePath& path, std::string* contents) {
[email protected]836f1342008-10-01 17:40:13148 FILE* file = OpenFile(path, "rb");
149 if (!file) {
initial.commitd7cae122008-07-26 21:49:38150 return false;
[email protected]836f1342008-10-01 17:40:13151 }
initial.commitd7cae122008-07-26 21:49:38152
153 char buf[1 << 16];
154 size_t len;
155 while ((len = fread(buf, 1, sizeof(buf), file)) > 0) {
156 contents->append(buf, len);
157 }
[email protected]836f1342008-10-01 17:40:13158 CloseFile(file);
initial.commitd7cae122008-07-26 21:49:38159
160 return true;
161}
162
[email protected]6faa0e0d2009-04-28 06:50:36163FILE* CreateAndOpenTemporaryFile(FilePath* path) {
164 FilePath directory;
165 if (!GetTempDir(&directory))
166 return false;
167
168 return CreateAndOpenTemporaryFileInDir(directory, path);
169}
170
[email protected]eac0709a2008-11-04 21:00:46171bool GetFileSize(const FilePath& file_path, int64* file_size) {
[email protected]f5e3da4d2008-09-26 01:04:08172 FileInfo info;
173 if (!GetFileInfo(file_path, &info))
174 return false;
175 *file_size = info.size;
176 return true;
177}
178
[email protected]836f1342008-10-01 17:40:13179bool CloseFile(FILE* file) {
[email protected]a1a19502008-10-21 17:14:45180 if (file == NULL)
181 return true;
[email protected]836f1342008-10-01 17:40:13182 return fclose(file) == 0;
183}
184
[email protected]c2c998c2009-01-27 19:08:39185bool TruncateFile(FILE* file) {
186 if (file == NULL)
187 return false;
188 long current_offset = ftell(file);
189 if (current_offset == -1)
190 return false;
191#if defined(OS_WIN)
192 int fd = _fileno(file);
193 if (_chsize(fd, current_offset) != 0)
194 return false;
195#else
196 int fd = fileno(file);
197 if (ftruncate(fd, current_offset) != 0)
198 return false;
199#endif
200 return true;
201}
202
[email protected]ee5c29da2009-01-09 22:14:27203bool ContainsPath(const FilePath &parent, const FilePath& child) {
204 FilePath abs_parent = FilePath(parent);
205 FilePath abs_child = FilePath(child);
206
207 if (!file_util::AbsolutePath(&abs_parent) ||
208 !file_util::AbsolutePath(&abs_child))
209 return false;
210
211#if defined(OS_WIN)
212 // file_util::AbsolutePath() does not flatten case on Windows, so we must do
213 // a case-insensitive compare.
214 if (!StartsWith(abs_child.value(), abs_parent.value(), false))
215#else
216 if (!StartsWithASCII(abs_child.value(), abs_parent.value(), true))
217#endif
218 return false;
219
220 // file_util::AbsolutePath() normalizes '/' to '\' on Windows, so we only need
221 // to check kSeparators[0].
222 if (abs_child.value().length() <= abs_parent.value().length() ||
223 abs_child.value()[abs_parent.value().length()] !=
224 FilePath::kSeparators[0])
225 return false;
226
227 return true;
228}
229
[email protected]7856bb82008-12-12 23:43:03230///////////////////////////////////////////////
231// MemoryMappedFile
232
233MemoryMappedFile::~MemoryMappedFile() {
234 CloseHandles();
235}
236
237bool MemoryMappedFile::Initialize(const FilePath& file_name) {
238 if (IsValid())
239 return false;
240
241 if (!MapFileToMemory(file_name)) {
242 CloseHandles();
243 return false;
244 }
245
246 return true;
247}
248
249bool MemoryMappedFile::IsValid() {
250 return data_ != NULL;
251}
252
[email protected]640517f2008-10-30 23:54:04253// Deprecated functions ----------------------------------------------------
254
[email protected]3c5281022009-01-28 00:22:46255bool ReadFileToString(const std::wstring& path, std::string* contents) {
256 return ReadFileToString(FilePath::FromWStringHack(path), contents);
257}
258
[email protected]640517f2008-10-30 23:54:04259bool AbsolutePath(std::wstring* path_str) {
[email protected]4a2952f2008-10-31 02:03:07260 FilePath path(FilePath::FromWStringHack(*path_str));
[email protected]640517f2008-10-30 23:54:04261 if (!AbsolutePath(&path))
262 return false;
263 *path_str = path.ToWStringHack();
264 return true;
265}
[email protected]b9e04f02008-11-27 04:03:57266void AppendToPath(std::wstring* path, const std::wstring& new_ending) {
267 if (!path) {
268 NOTREACHED();
269 return; // Don't crash in this function in release builds.
270 }
271
272 if (!EndsWithSeparator(path))
273 path->push_back(FilePath::kSeparators[0]);
274 path->append(new_ending);
[email protected]640517f2008-10-30 23:54:04275}
276bool CopyDirectory(const std::wstring& from_path, const std::wstring& to_path,
277 bool recursive) {
278 return CopyDirectory(FilePath::FromWStringHack(from_path),
279 FilePath::FromWStringHack(to_path),
280 recursive);
281}
[email protected]640517f2008-10-30 23:54:04282bool ContentsEqual(const std::wstring& filename1,
283 const std::wstring& filename2) {
284 return ContentsEqual(FilePath::FromWStringHack(filename1),
285 FilePath::FromWStringHack(filename2));
286}
[email protected]b9e04f02008-11-27 04:03:57287bool CopyFile(const std::wstring& from_path, const std::wstring& to_path) {
288 return CopyFile(FilePath::FromWStringHack(from_path),
289 FilePath::FromWStringHack(to_path));
290}
[email protected]640517f2008-10-30 23:54:04291bool CreateDirectory(const std::wstring& full_path) {
292 return CreateDirectory(FilePath::FromWStringHack(full_path));
293}
[email protected]7e1fde6a2008-12-23 20:20:10294bool CreateNewTempDirectory(const std::wstring& prefix,
295 std::wstring* new_temp_path) {
296#if defined(OS_WIN)
297 FilePath::StringType dir_prefix(prefix);
298#elif defined(OS_POSIX)
299 FilePath::StringType dir_prefix = WideToUTF8(prefix);
300#endif
301 FilePath temp_path;
302 if (!CreateNewTempDirectory(dir_prefix, &temp_path))
303 return false;
304 *new_temp_path = temp_path.ToWStringHack();
305 return true;
306}
[email protected]392264c2008-11-11 00:01:38307bool CreateTemporaryFileName(std::wstring* temp_file) {
308 FilePath temp_file_path;
309 if (!CreateTemporaryFileName(&temp_file_path))
310 return false;
311 *temp_file = temp_file_path.ToWStringHack();
312 return true;
313}
[email protected]b9e04f02008-11-27 04:03:57314bool Delete(const std::wstring& path, bool recursive) {
315 return Delete(FilePath::FromWStringHack(path), recursive);
316}
317bool DirectoryExists(const std::wstring& path) {
318 return DirectoryExists(FilePath::FromWStringHack(path));
319}
320bool EndsWithSeparator(std::wstring* path) {
321 return EndsWithSeparator(FilePath::FromWStringHack(*path));
322}
323bool EndsWithSeparator(const std::wstring& path) {
324 return EndsWithSeparator(FilePath::FromWStringHack(path));
325}
[email protected]640517f2008-10-30 23:54:04326bool GetCurrentDirectory(std::wstring* path_str) {
327 FilePath path;
328 if (!GetCurrentDirectory(&path))
329 return false;
330 *path_str = path.ToWStringHack();
331 return true;
332}
[email protected]7ae7c2cb2009-01-06 23:31:41333std::wstring GetFileExtensionFromPath(const std::wstring& path) {
334 FilePath::StringType extension =
335 GetFileExtensionFromPath(FilePath::FromWStringHack(path));
336#if defined(OS_WIN)
337 return extension;
338#elif defined(OS_POSIX)
339 return UTF8ToWide(extension);
340#endif
341}
[email protected]eac0709a2008-11-04 21:00:46342bool GetFileInfo(const std::wstring& file_path, FileInfo* results) {
343 return GetFileInfo(FilePath::FromWStringHack(file_path), results);
344}
[email protected]ceeb87e2008-12-04 20:46:06345std::wstring GetFilenameFromPath(const std::wstring& path) {
346 if (path.empty() || EndsWithSeparator(path))
347 return std::wstring();
348
[email protected]5e207882009-01-05 23:59:36349 return FilePath::FromWStringHack(path).BaseName().ToWStringHack();
[email protected]ceeb87e2008-12-04 20:46:06350}
[email protected]eac0709a2008-11-04 21:00:46351bool GetFileSize(const std::wstring& file_path, int64* file_size) {
352 return GetFileSize(FilePath::FromWStringHack(file_path), file_size);
353}
[email protected]640517f2008-10-30 23:54:04354bool GetTempDir(std::wstring* path_str) {
355 FilePath path;
356 if (!GetTempDir(&path))
357 return false;
358 *path_str = path.ToWStringHack();
359 return true;
360}
[email protected]b9e04f02008-11-27 04:03:57361bool Move(const std::wstring& from_path, const std::wstring& to_path) {
362 return Move(FilePath::FromWStringHack(from_path),
363 FilePath::FromWStringHack(to_path));
364}
[email protected]a9cd2a652008-11-17 21:01:19365FILE* OpenFile(const std::wstring& filename, const char* mode) {
366 return OpenFile(FilePath::FromWStringHack(filename), mode);
367}
[email protected]b9e04f02008-11-27 04:03:57368bool PathExists(const std::wstring& path) {
369 return PathExists(FilePath::FromWStringHack(path));
370}
[email protected]7e1fde6a2008-12-23 20:20:10371bool PathIsWritable(const std::wstring& path) {
372 return PathIsWritable(FilePath::FromWStringHack(path));
373}
[email protected]c870c762009-01-28 05:47:15374int ReadFile(const std::wstring& filename, char* data, int size) {
375 return ReadFile(FilePath::FromWStringHack(filename), data, size);
376}
[email protected]a9cd2a652008-11-17 21:01:19377bool SetCurrentDirectory(const std::wstring& directory) {
378 return SetCurrentDirectory(FilePath::FromWStringHack(directory));
379}
[email protected]b9e04f02008-11-27 04:03:57380void UpOneDirectory(std::wstring* dir) {
381 FilePath path = FilePath::FromWStringHack(*dir);
382 FilePath directory = path.DirName();
383 // If there is no separator, we will get back kCurrentDirectory.
384 // In this case don't change |dir|.
385 if (directory.value() != FilePath::kCurrentDirectory)
386 *dir = directory.ToWStringHack();
387}
388void UpOneDirectoryOrEmpty(std::wstring* dir) {
389 FilePath path = FilePath::FromWStringHack(*dir);
390 FilePath directory = path.DirName();
391 // If there is no separator, we will get back kCurrentDirectory.
392 // In this case, clear dir.
393 if (directory == path || directory.value() == FilePath::kCurrentDirectory)
394 dir->clear();
395 else
396 *dir = directory.ToWStringHack();
397}
[email protected]c870c762009-01-28 05:47:15398int WriteFile(const std::wstring& filename, const char* data, int size) {
399 return WriteFile(FilePath::FromWStringHack(filename), data, size);
400}
[email protected]8199b3a2009-06-09 05:57:38401
402///////////////////////////////////////////////
403// FileEnumerator
404//
405// Note: the main logic is in file_util_<platform>.cc
406
407bool FileEnumerator::ShouldSkip(const FilePath& path) {
408 FilePath::StringType basename = path.BaseName().value();
409 return IsDot(path) || (IsDotDot(path) && !(INCLUDE_DOT_DOT & file_type_));
410}
411
412bool FileEnumerator::IsDot(const FilePath& path) {
413 return FILE_PATH_LITERAL(".") == path.BaseName().value();
414}
415
416bool FileEnumerator::IsDotDot(const FilePath& path) {
417 return FILE_PATH_LITERAL("..") == path.BaseName().value();
418}
419
initial.commitd7cae122008-07-26 21:49:38420} // namespace