blob: 8eec3ac2bf1863f28a271e06fd09447c1ac9443a [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:5729void PathComponents(const FilePath& path,
30 std::vector<FilePath::StringType>* components) {
31 DCHECK(components);
32 if (!components)
[email protected]37088fef2008-08-15 17:32:1033 return;
[email protected]37088fef2008-08-15 17:32:1034
[email protected]b9e04f02008-11-27 04:03:5735 FilePath::StringType path_str = path.value();
36 FilePath::StringType::size_type start = 0;
37 FilePath::StringType::size_type end =
38 path_str.find_first_of(FilePath::kSeparators);
39
40 // If the path starts with a separator, add it to components.
[email protected]37088fef2008-08-15 17:32:1041 if (end == start) {
[email protected]b9e04f02008-11-27 04:03:5742 components->push_back(FilePath::StringType(path_str, 0, 1));
[email protected]37088fef2008-08-15 17:32:1043 start = end + 1;
[email protected]b9e04f02008-11-27 04:03:5744 end = path_str.find_first_of(FilePath::kSeparators, start);
[email protected]37088fef2008-08-15 17:32:1045 }
[email protected]b9e04f02008-11-27 04:03:5746 while (end != FilePath::StringType::npos) {
47 FilePath::StringType component =
48 FilePath::StringType(path_str, start, end - start);
[email protected]37088fef2008-08-15 17:32:1049 components->push_back(component);
50 start = end + 1;
[email protected]b9e04f02008-11-27 04:03:5751 end = path_str.find_first_of(FilePath::kSeparators, start);
[email protected]37088fef2008-08-15 17:32:1052 }
[email protected]b9e04f02008-11-27 04:03:5753
54 components->push_back(FilePath::StringType(path_str, start));
[email protected]37088fef2008-08-15 17:32:1055}
[email protected]7e263942008-11-25 22:04:3756
[email protected]b9e04f02008-11-27 04:03:5757bool EndsWithSeparator(const FilePath& path) {
58 FilePath::StringType value = path.value();
59 if (value.empty())
60 return false;
61
62 return FilePath::IsSeparator(value[value.size() - 1]);
initial.commitd7cae122008-07-26 21:49:3863}
64
[email protected]7e263942008-11-25 22:04:3765bool EnsureEndsWithSeparator(FilePath* path) {
66 if (!DirectoryExists(*path))
67 return false;
68
69 if (EndsWithSeparator(*path))
70 return true;
71
72 FilePath::StringType& path_str =
73 const_cast<FilePath::StringType&>(path->value());
74 path_str.append(&FilePath::kSeparators[0], 1);
75
76 return true;
77}
78
[email protected]a97f2b42009-04-21 23:15:4579void TrimTrailingSeparator(std::wstring* dir) {
80 while (dir->length() > 1 && EndsWithSeparator(dir))
81 dir->resize(dir->length() - 1);
82}
83
[email protected]7ae7c2cb2009-01-06 23:31:4184FilePath::StringType GetFileExtensionFromPath(const FilePath& path) {
85 FilePath::StringType file_name = path.BaseName().value();
86 const FilePath::StringType::size_type last_dot =
87 file_name.rfind(kExtensionSeparator);
88 return FilePath::StringType(last_dot == FilePath::StringType::npos ?
89 FILE_PATH_LITERAL("") :
90 file_name, last_dot+1);
[email protected]52ab8f902008-11-03 16:14:4691}
92
[email protected]ceeb87e2008-12-04 20:46:0693void InsertBeforeExtension(FilePath* path, const FilePath::StringType& suffix) {
94 FilePath::StringType& value =
95 const_cast<FilePath::StringType&>(path->value());
96
97 const FilePath::StringType::size_type last_dot =
98 value.rfind(kExtensionSeparator);
99 const FilePath::StringType::size_type last_separator =
100 value.find_last_of(FilePath::StringType(FilePath::kSeparators));
101
102 if (last_dot == FilePath::StringType::npos ||
103 (last_separator != std::wstring::npos && last_dot < last_separator)) {
104 // The path looks something like "C:\pics.old\jojo" or "C:\pics\jojo".
105 // We should just append the suffix to the entire path.
106 value.append(suffix);
107 return;
108 }
109
110 value.insert(last_dot, suffix);
111}
112
113void ReplaceExtension(FilePath* path, const FilePath::StringType& extension) {
114 FilePath::StringType clean_extension;
115 // If the new extension is "" or ".", then we will just remove the current
116 // extension.
117 if (!extension.empty() &&
118 extension != FilePath::StringType(&kExtensionSeparator, 1)) {
119 if (extension[0] != kExtensionSeparator)
120 clean_extension.append(&kExtensionSeparator, 1);
121 clean_extension.append(extension);
122 }
123
124 FilePath::StringType& value =
125 const_cast<FilePath::StringType&>(path->value());
126 const FilePath::StringType::size_type last_dot =
127 value.rfind(kExtensionSeparator);
128 const FilePath::StringType::size_type last_separator =
129 value.find_last_of(FilePath::StringType(FilePath::kSeparators));
130
131 // Erase the current extension, if any.
132 if ((last_dot > last_separator ||
133 last_separator == FilePath::StringType::npos) &&
134 last_dot != FilePath::StringType::npos)
135 value.erase(last_dot);
136
137 value.append(clean_extension);
138}
139
[email protected]640517f2008-10-30 23:54:04140bool ContentsEqual(const FilePath& filename1, const FilePath& filename2) {
initial.commitd7cae122008-07-26 21:49:38141 // We open the file in binary format even if they are text files because
142 // we are just comparing that bytes are exactly same in both files and not
143 // doing anything smart with text formatting.
[email protected]640517f2008-10-30 23:54:04144 std::ifstream file1(filename1.value().c_str(),
[email protected]5af2edb92008-08-08 20:16:08145 std::ios::in | std::ios::binary);
[email protected]640517f2008-10-30 23:54:04146 std::ifstream file2(filename2.value().c_str(),
[email protected]5af2edb92008-08-08 20:16:08147 std::ios::in | std::ios::binary);
[email protected]b9e04f02008-11-27 04:03:57148
initial.commitd7cae122008-07-26 21:49:38149 // Even if both files aren't openable (and thus, in some sense, "equal"),
150 // any unusable file yields a result of "false".
151 if (!file1.is_open() || !file2.is_open())
152 return false;
153
154 const int BUFFER_SIZE = 2056;
155 char buffer1[BUFFER_SIZE], buffer2[BUFFER_SIZE];
156 do {
157 file1.read(buffer1, BUFFER_SIZE);
158 file2.read(buffer2, BUFFER_SIZE);
159
160 if ((file1.eof() && !file2.eof()) ||
161 (!file1.eof() && file2.eof()) ||
162 (file1.gcount() != file2.gcount()) ||
163 (memcmp(buffer1, buffer2, file1.gcount()))) {
164 file1.close();
165 file2.close();
166 return false;
167 }
168 } while (!file1.eof() && !file2.eof());
169
170 file1.close();
171 file2.close();
172 return true;
173}
174
[email protected]3c5281022009-01-28 00:22:46175bool ReadFileToString(const FilePath& path, std::string* contents) {
[email protected]836f1342008-10-01 17:40:13176 FILE* file = OpenFile(path, "rb");
177 if (!file) {
initial.commitd7cae122008-07-26 21:49:38178 return false;
[email protected]836f1342008-10-01 17:40:13179 }
initial.commitd7cae122008-07-26 21:49:38180
181 char buf[1 << 16];
182 size_t len;
183 while ((len = fread(buf, 1, sizeof(buf), file)) > 0) {
184 contents->append(buf, len);
185 }
[email protected]836f1342008-10-01 17:40:13186 CloseFile(file);
initial.commitd7cae122008-07-26 21:49:38187
188 return true;
189}
190
[email protected]6faa0e0d2009-04-28 06:50:36191FILE* CreateAndOpenTemporaryFile(FilePath* path) {
192 FilePath directory;
193 if (!GetTempDir(&directory))
194 return false;
195
196 return CreateAndOpenTemporaryFileInDir(directory, path);
197}
198
[email protected]eac0709a2008-11-04 21:00:46199bool GetFileSize(const FilePath& file_path, int64* file_size) {
[email protected]f5e3da4d2008-09-26 01:04:08200 FileInfo info;
201 if (!GetFileInfo(file_path, &info))
202 return false;
203 *file_size = info.size;
204 return true;
205}
206
[email protected]836f1342008-10-01 17:40:13207bool CloseFile(FILE* file) {
[email protected]a1a19502008-10-21 17:14:45208 if (file == NULL)
209 return true;
[email protected]836f1342008-10-01 17:40:13210 return fclose(file) == 0;
211}
212
[email protected]c2c998c2009-01-27 19:08:39213bool TruncateFile(FILE* file) {
214 if (file == NULL)
215 return false;
216 long current_offset = ftell(file);
217 if (current_offset == -1)
218 return false;
219#if defined(OS_WIN)
220 int fd = _fileno(file);
221 if (_chsize(fd, current_offset) != 0)
222 return false;
223#else
224 int fd = fileno(file);
225 if (ftruncate(fd, current_offset) != 0)
226 return false;
227#endif
228 return true;
229}
230
[email protected]ee5c29da2009-01-09 22:14:27231bool ContainsPath(const FilePath &parent, const FilePath& child) {
232 FilePath abs_parent = FilePath(parent);
233 FilePath abs_child = FilePath(child);
234
235 if (!file_util::AbsolutePath(&abs_parent) ||
236 !file_util::AbsolutePath(&abs_child))
237 return false;
238
239#if defined(OS_WIN)
240 // file_util::AbsolutePath() does not flatten case on Windows, so we must do
241 // a case-insensitive compare.
242 if (!StartsWith(abs_child.value(), abs_parent.value(), false))
243#else
244 if (!StartsWithASCII(abs_child.value(), abs_parent.value(), true))
245#endif
246 return false;
247
248 // file_util::AbsolutePath() normalizes '/' to '\' on Windows, so we only need
249 // to check kSeparators[0].
250 if (abs_child.value().length() <= abs_parent.value().length() ||
251 abs_child.value()[abs_parent.value().length()] !=
252 FilePath::kSeparators[0])
253 return false;
254
255 return true;
256}
257
[email protected]7856bb82008-12-12 23:43:03258///////////////////////////////////////////////
259// MemoryMappedFile
260
261MemoryMappedFile::~MemoryMappedFile() {
262 CloseHandles();
263}
264
265bool MemoryMappedFile::Initialize(const FilePath& file_name) {
266 if (IsValid())
267 return false;
268
269 if (!MapFileToMemory(file_name)) {
270 CloseHandles();
271 return false;
272 }
273
274 return true;
275}
276
277bool MemoryMappedFile::IsValid() {
278 return data_ != NULL;
279}
280
[email protected]640517f2008-10-30 23:54:04281// Deprecated functions ----------------------------------------------------
282
[email protected]3c5281022009-01-28 00:22:46283bool ReadFileToString(const std::wstring& path, std::string* contents) {
284 return ReadFileToString(FilePath::FromWStringHack(path), contents);
285}
286
[email protected]640517f2008-10-30 23:54:04287bool AbsolutePath(std::wstring* path_str) {
[email protected]4a2952f2008-10-31 02:03:07288 FilePath path(FilePath::FromWStringHack(*path_str));
[email protected]640517f2008-10-30 23:54:04289 if (!AbsolutePath(&path))
290 return false;
291 *path_str = path.ToWStringHack();
292 return true;
293}
[email protected]b9e04f02008-11-27 04:03:57294void AppendToPath(std::wstring* path, const std::wstring& new_ending) {
295 if (!path) {
296 NOTREACHED();
297 return; // Don't crash in this function in release builds.
298 }
299
300 if (!EndsWithSeparator(path))
301 path->push_back(FilePath::kSeparators[0]);
302 path->append(new_ending);
[email protected]640517f2008-10-30 23:54:04303}
304bool CopyDirectory(const std::wstring& from_path, const std::wstring& to_path,
305 bool recursive) {
306 return CopyDirectory(FilePath::FromWStringHack(from_path),
307 FilePath::FromWStringHack(to_path),
308 recursive);
309}
[email protected]640517f2008-10-30 23:54:04310bool ContentsEqual(const std::wstring& filename1,
311 const std::wstring& filename2) {
312 return ContentsEqual(FilePath::FromWStringHack(filename1),
313 FilePath::FromWStringHack(filename2));
314}
[email protected]b9e04f02008-11-27 04:03:57315bool CopyFile(const std::wstring& from_path, const std::wstring& to_path) {
316 return CopyFile(FilePath::FromWStringHack(from_path),
317 FilePath::FromWStringHack(to_path));
318}
[email protected]640517f2008-10-30 23:54:04319bool CreateDirectory(const std::wstring& full_path) {
320 return CreateDirectory(FilePath::FromWStringHack(full_path));
321}
[email protected]7e1fde6a2008-12-23 20:20:10322bool CreateNewTempDirectory(const std::wstring& prefix,
323 std::wstring* new_temp_path) {
324#if defined(OS_WIN)
325 FilePath::StringType dir_prefix(prefix);
326#elif defined(OS_POSIX)
327 FilePath::StringType dir_prefix = WideToUTF8(prefix);
328#endif
329 FilePath temp_path;
330 if (!CreateNewTempDirectory(dir_prefix, &temp_path))
331 return false;
332 *new_temp_path = temp_path.ToWStringHack();
333 return true;
334}
[email protected]392264c2008-11-11 00:01:38335bool CreateTemporaryFileName(std::wstring* temp_file) {
336 FilePath temp_file_path;
337 if (!CreateTemporaryFileName(&temp_file_path))
338 return false;
339 *temp_file = temp_file_path.ToWStringHack();
340 return true;
341}
[email protected]b9e04f02008-11-27 04:03:57342bool Delete(const std::wstring& path, bool recursive) {
343 return Delete(FilePath::FromWStringHack(path), recursive);
344}
345bool DirectoryExists(const std::wstring& path) {
346 return DirectoryExists(FilePath::FromWStringHack(path));
347}
348bool EndsWithSeparator(std::wstring* path) {
349 return EndsWithSeparator(FilePath::FromWStringHack(*path));
350}
351bool EndsWithSeparator(const std::wstring& path) {
352 return EndsWithSeparator(FilePath::FromWStringHack(path));
353}
[email protected]640517f2008-10-30 23:54:04354bool GetCurrentDirectory(std::wstring* path_str) {
355 FilePath path;
356 if (!GetCurrentDirectory(&path))
357 return false;
358 *path_str = path.ToWStringHack();
359 return true;
360}
[email protected]7ae7c2cb2009-01-06 23:31:41361std::wstring GetFileExtensionFromPath(const std::wstring& path) {
362 FilePath::StringType extension =
363 GetFileExtensionFromPath(FilePath::FromWStringHack(path));
364#if defined(OS_WIN)
365 return extension;
366#elif defined(OS_POSIX)
367 return UTF8ToWide(extension);
368#endif
369}
[email protected]eac0709a2008-11-04 21:00:46370bool GetFileInfo(const std::wstring& file_path, FileInfo* results) {
371 return GetFileInfo(FilePath::FromWStringHack(file_path), results);
372}
[email protected]ceeb87e2008-12-04 20:46:06373std::wstring GetFilenameFromPath(const std::wstring& path) {
374 if (path.empty() || EndsWithSeparator(path))
375 return std::wstring();
376
[email protected]5e207882009-01-05 23:59:36377 return FilePath::FromWStringHack(path).BaseName().ToWStringHack();
[email protected]ceeb87e2008-12-04 20:46:06378}
[email protected]eac0709a2008-11-04 21:00:46379bool GetFileSize(const std::wstring& file_path, int64* file_size) {
380 return GetFileSize(FilePath::FromWStringHack(file_path), file_size);
381}
[email protected]640517f2008-10-30 23:54:04382bool GetTempDir(std::wstring* path_str) {
383 FilePath path;
384 if (!GetTempDir(&path))
385 return false;
386 *path_str = path.ToWStringHack();
387 return true;
388}
[email protected]b9e04f02008-11-27 04:03:57389bool Move(const std::wstring& from_path, const std::wstring& to_path) {
390 return Move(FilePath::FromWStringHack(from_path),
391 FilePath::FromWStringHack(to_path));
392}
[email protected]a9cd2a652008-11-17 21:01:19393FILE* OpenFile(const std::wstring& filename, const char* mode) {
394 return OpenFile(FilePath::FromWStringHack(filename), mode);
395}
[email protected]b9e04f02008-11-27 04:03:57396bool PathExists(const std::wstring& path) {
397 return PathExists(FilePath::FromWStringHack(path));
398}
[email protected]7e1fde6a2008-12-23 20:20:10399bool PathIsWritable(const std::wstring& path) {
400 return PathIsWritable(FilePath::FromWStringHack(path));
401}
[email protected]c870c762009-01-28 05:47:15402int ReadFile(const std::wstring& filename, char* data, int size) {
403 return ReadFile(FilePath::FromWStringHack(filename), data, size);
404}
[email protected]a9cd2a652008-11-17 21:01:19405bool SetCurrentDirectory(const std::wstring& directory) {
406 return SetCurrentDirectory(FilePath::FromWStringHack(directory));
407}
[email protected]b9e04f02008-11-27 04:03:57408void UpOneDirectory(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 don't change |dir|.
413 if (directory.value() != FilePath::kCurrentDirectory)
414 *dir = directory.ToWStringHack();
415}
416void UpOneDirectoryOrEmpty(std::wstring* dir) {
417 FilePath path = FilePath::FromWStringHack(*dir);
418 FilePath directory = path.DirName();
419 // If there is no separator, we will get back kCurrentDirectory.
420 // In this case, clear dir.
421 if (directory == path || directory.value() == FilePath::kCurrentDirectory)
422 dir->clear();
423 else
424 *dir = directory.ToWStringHack();
425}
[email protected]c870c762009-01-28 05:47:15426int WriteFile(const std::wstring& filename, const char* data, int size) {
427 return WriteFile(FilePath::FromWStringHack(filename), data, size);
428}
initial.commitd7cae122008-07-26 21:49:38429} // namespace