1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/file_util.h"
14 #include "base/file_path.h"
15 #include "base/logging.h"
16 #include "base/string_piece.h"
17 #include "base/string_util.h"
18 #include "base/utf_string_conversions.h"
22 const FilePath::CharType kExtensionSeparator
= FILE_PATH_LITERAL('.');
28 bool EndsWithSeparator(const FilePath
& path
) {
29 FilePath::StringType value
= path
.value();
33 return FilePath::IsSeparator(value
[value
.size() - 1]);
36 bool EnsureEndsWithSeparator(FilePath
* path
) {
37 if (!DirectoryExists(*path
))
40 if (EndsWithSeparator(*path
))
43 FilePath::StringType
& path_str
=
44 const_cast<FilePath::StringType
&>(path
->value());
45 path_str
.append(&FilePath::kSeparators
[0], 1);
50 void InsertBeforeExtension(FilePath
* path
, const FilePath::StringType
& suffix
) {
51 FilePath::StringType
& value
=
52 const_cast<FilePath::StringType
&>(path
->value());
54 const FilePath::StringType::size_type last_dot
=
55 value
.rfind(kExtensionSeparator
);
56 const FilePath::StringType::size_type last_separator
=
57 value
.find_last_of(FilePath::StringType(FilePath::kSeparators
));
59 if (last_dot
== FilePath::StringType::npos
||
60 (last_separator
!= std::wstring::npos
&& last_dot
< last_separator
)) {
61 // The path looks something like "C:\pics.old\jojo" or "C:\pics\jojo".
62 // We should just append the suffix to the entire path.
67 value
.insert(last_dot
, suffix
);
70 bool ContentsEqual(const FilePath
& filename1
, const FilePath
& filename2
) {
71 // We open the file in binary format even if they are text files because
72 // we are just comparing that bytes are exactly same in both files and not
73 // doing anything smart with text formatting.
74 std::ifstream
file1(filename1
.value().c_str(),
75 std::ios::in
| std::ios::binary
);
76 std::ifstream
file2(filename2
.value().c_str(),
77 std::ios::in
| std::ios::binary
);
79 // Even if both files aren't openable (and thus, in some sense, "equal"),
80 // any unusable file yields a result of "false".
81 if (!file1
.is_open() || !file2
.is_open())
84 const int BUFFER_SIZE
= 2056;
85 char buffer1
[BUFFER_SIZE
], buffer2
[BUFFER_SIZE
];
87 file1
.read(buffer1
, BUFFER_SIZE
);
88 file2
.read(buffer2
, BUFFER_SIZE
);
90 if ((file1
.eof() != file2
.eof()) ||
91 (file1
.gcount() != file2
.gcount()) ||
92 (memcmp(buffer1
, buffer2
, file1
.gcount()))) {
97 } while (!file1
.eof() || !file2
.eof());
104 bool TextContentsEqual(const FilePath
& filename1
, const FilePath
& filename2
) {
105 std::ifstream
file1(filename1
.value().c_str(), std::ios::in
);
106 std::ifstream
file2(filename2
.value().c_str(), std::ios::in
);
108 // Even if both files aren't openable (and thus, in some sense, "equal"),
109 // any unusable file yields a result of "false".
110 if (!file1
.is_open() || !file2
.is_open())
114 std::string line1
, line2
;
115 getline(file1
, line1
);
116 getline(file2
, line2
);
118 // Check for mismatched EOF states, or any error state.
119 if ((file1
.eof() != file2
.eof()) ||
120 file1
.bad() || file2
.bad()) {
124 // Trim all '\r' and '\n' characters from the end of the line.
125 std::string::size_type end1
= line1
.find_last_not_of("\r\n");
126 if (end1
== std::string::npos
)
128 else if (end1
+ 1 < line1
.length())
129 line1
.erase(end1
+ 1);
131 std::string::size_type end2
= line2
.find_last_not_of("\r\n");
132 if (end2
== std::string::npos
)
134 else if (end2
+ 1 < line2
.length())
135 line2
.erase(end2
+ 1);
139 } while (!file1
.eof() || !file2
.eof());
144 bool ReadFileToString(const FilePath
& path
, std::string
* contents
) {
145 FILE* file
= OpenFile(path
, "rb");
152 while ((len
= fread(buf
, 1, sizeof(buf
), file
)) > 0) {
154 contents
->append(buf
, len
);
161 bool IsDirectoryEmpty(const FilePath
& dir_path
) {
162 FileEnumerator
files(dir_path
, false,
163 static_cast<FileEnumerator::FileType
>(
164 FileEnumerator::FILES
| FileEnumerator::DIRECTORIES
));
165 if (files
.Next().value().empty())
170 FILE* CreateAndOpenTemporaryFile(FilePath
* path
) {
172 if (!GetTempDir(&directory
))
175 return CreateAndOpenTemporaryFileInDir(directory
, path
);
178 bool GetFileSize(const FilePath
& file_path
, int64
* file_size
) {
179 base::PlatformFileInfo info
;
180 if (!GetFileInfo(file_path
, &info
))
182 *file_size
= info
.size
;
186 bool IsDot(const FilePath
& path
) {
187 return FILE_PATH_LITERAL(".") == path
.BaseName().value();
190 bool IsDotDot(const FilePath
& path
) {
191 return FILE_PATH_LITERAL("..") == path
.BaseName().value();
194 bool TouchFile(const FilePath
& path
,
195 const base::Time
& last_accessed
,
196 const base::Time
& last_modified
) {
197 base::PlatformFile file
=
198 base::CreatePlatformFile(path
,
199 base::PLATFORM_FILE_OPEN
|
200 base::PLATFORM_FILE_WRITE_ATTRIBUTES
,
202 if (file
!= base::kInvalidPlatformFileValue
) {
203 bool result
= base::TouchPlatformFile(file
, last_accessed
, last_modified
);
204 base::ClosePlatformFile(file
);
211 bool SetLastModifiedTime(const FilePath
& path
,
212 const base::Time
& last_modified
) {
213 return TouchFile(path
, last_modified
, last_modified
);
216 bool CloseFile(FILE* file
) {
219 return fclose(file
) == 0;
222 bool TruncateFile(FILE* file
) {
225 long current_offset
= ftell(file
);
226 if (current_offset
== -1)
229 int fd
= _fileno(file
);
230 if (_chsize(fd
, current_offset
) != 0)
233 int fd
= fileno(file
);
234 if (ftruncate(fd
, current_offset
) != 0)
240 bool ContainsPath(const FilePath
&parent
, const FilePath
& child
) {
241 FilePath abs_parent
= FilePath(parent
);
242 FilePath abs_child
= FilePath(child
);
244 if (!file_util::AbsolutePath(&abs_parent
) ||
245 !file_util::AbsolutePath(&abs_child
))
249 // file_util::AbsolutePath() does not flatten case on Windows, so we must do
250 // a case-insensitive compare.
251 if (!StartsWith(abs_child
.value(), abs_parent
.value(), false))
253 if (!StartsWithASCII(abs_child
.value(), abs_parent
.value(), true))
257 // file_util::AbsolutePath() normalizes '/' to '\' on Windows, so we only need
258 // to check kSeparators[0].
259 if (abs_child
.value().length() <= abs_parent
.value().length() ||
260 abs_child
.value()[abs_parent
.value().length()] !=
261 FilePath::kSeparators
[0])
267 int64
ComputeDirectorySize(const FilePath
& root_path
) {
268 int64 running_size
= 0;
269 FileEnumerator
file_iter(root_path
, true, FileEnumerator::FILES
);
270 for (FilePath current
= file_iter
.Next(); !current
.empty();
271 current
= file_iter
.Next()) {
272 FileEnumerator::FindInfo info
;
273 file_iter
.GetFindInfo(&info
);
275 LARGE_INTEGER li
= { info
.nFileSizeLow
, info
.nFileSizeHigh
};
276 running_size
+= li
.QuadPart
;
278 running_size
+= info
.stat
.st_size
;
284 int64
ComputeFilesSize(const FilePath
& directory
,
285 const FilePath::StringType
& pattern
) {
286 int64 running_size
= 0;
287 FileEnumerator
file_iter(directory
, false, FileEnumerator::FILES
, pattern
);
288 for (FilePath current
= file_iter
.Next(); !current
.empty();
289 current
= file_iter
.Next()) {
290 FileEnumerator::FindInfo info
;
291 file_iter
.GetFindInfo(&info
);
293 LARGE_INTEGER li
= { info
.nFileSizeLow
, info
.nFileSizeHigh
};
294 running_size
+= li
.QuadPart
;
296 running_size
+= info
.stat
.st_size
;
302 ///////////////////////////////////////////////
305 MemoryMappedFile::~MemoryMappedFile() {
309 bool MemoryMappedFile::Initialize(const FilePath
& file_name
) {
313 if (!MapFileToMemory(file_name
)) {
321 bool MemoryMappedFile::Initialize(base::PlatformFile file
) {
327 if (!MapFileToMemoryInternal()) {
335 bool MemoryMappedFile::IsValid() const {
336 return data_
!= NULL
;
339 bool MemoryMappedFile::MapFileToMemory(const FilePath
& file_name
) {
340 file_
= base::CreatePlatformFile(
341 file_name
, base::PLATFORM_FILE_OPEN
| base::PLATFORM_FILE_READ
,
344 if (file_
== base::kInvalidPlatformFileValue
) {
345 LOG(ERROR
) << "Couldn't open " << file_name
.value();
349 return MapFileToMemoryInternal();
352 // Deprecated functions ----------------------------------------------------
355 void AppendToPath(std::wstring
* path
, const std::wstring
& new_ending
) {
358 return; // Don't crash in this function in release builds.
361 if (!EndsWithSeparator(FilePath(*path
)))
362 path
->push_back(FilePath::kSeparators
[0]);
363 path
->append(new_ending
);
366 bool CopyDirectory(const std::wstring
& from_path
, const std::wstring
& to_path
,
368 return CopyDirectory(FilePath::FromWStringHack(from_path
),
369 FilePath::FromWStringHack(to_path
),
372 bool Delete(const std::wstring
& path
, bool recursive
) {
373 return Delete(FilePath::FromWStringHack(path
), recursive
);
375 std::wstring
GetFileExtensionFromPath(const std::wstring
& path
) {
376 std::wstring file_name
= FilePath(path
).BaseName().value();
377 const std::wstring::size_type last_dot
= file_name
.rfind(kExtensionSeparator
);
378 return std::wstring(last_dot
== std::wstring::npos
? L
""
379 : file_name
, last_dot
+ 1);
381 FILE* OpenFile(const std::wstring
& filename
, const char* mode
) {
382 return OpenFile(FilePath::FromWStringHack(filename
), mode
);
384 int ReadFile(const std::wstring
& filename
, char* data
, int size
) {
385 return ReadFile(FilePath::FromWStringHack(filename
), data
, size
);
387 int WriteFile(const std::wstring
& filename
, const char* data
, int size
) {
388 return WriteFile(FilePath::FromWStringHack(filename
), data
, size
);
392 ///////////////////////////////////////////////
395 // Note: the main logic is in file_util_<platform>.cc
397 bool FileEnumerator::ShouldSkip(const FilePath
& path
) {
398 FilePath::StringType basename
= path
.BaseName().value();
399 return IsDot(path
) || (IsDotDot(path
) && !(INCLUDE_DOT_DOT
& file_type_
));