1 // Copyright (c) 2012 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/files/file_enumerator.h"
15 #include "base/files/file_path.h"
16 #include "base/logging.h"
17 #include "base/strings/string_piece.h"
18 #include "base/strings/string_util.h"
19 #include "base/strings/stringprintf.h"
20 #include "base/strings/utf_string_conversions.h"
22 using base::FileEnumerator
;
27 const FilePath::CharType kExtensionSeparator
= FILE_PATH_LITERAL('.');
29 // The maximum number of 'uniquified' files we will try to create.
30 // This is used when the filename we're trying to download is already in use,
31 // so we create a new unique filename by appending " (nnn)" before the
32 // extension, where 1 <= nnn <= kMaxUniqueFiles.
33 // Also used by code that cleans up said files.
34 static const int kMaxUniqueFiles
= 100;
40 bool g_bug108724_debug
= false;
42 void InsertBeforeExtension(FilePath
* path
, const FilePath::StringType
& suffix
) {
43 FilePath::StringType
& value
=
44 const_cast<FilePath::StringType
&>(path
->value());
46 const FilePath::StringType::size_type last_dot
=
47 value
.rfind(kExtensionSeparator
);
48 const FilePath::StringType::size_type last_separator
=
49 value
.find_last_of(FilePath::StringType(FilePath::kSeparators
));
51 if (last_dot
== FilePath::StringType::npos
||
52 (last_separator
!= std::wstring::npos
&& last_dot
< last_separator
)) {
53 // The path looks something like "C:\pics.old\jojo" or "C:\pics\jojo".
54 // We should just append the suffix to the entire path.
59 value
.insert(last_dot
, suffix
);
62 bool Move(const FilePath
& from_path
, const FilePath
& to_path
) {
63 if (from_path
.ReferencesParent() || to_path
.ReferencesParent())
65 return MoveUnsafe(from_path
, to_path
);
68 bool ReplaceFile(const base::FilePath
& from_path
,
69 const base::FilePath
& to_path
) {
70 return ReplaceFileAndGetError(from_path
, to_path
, NULL
);
73 bool CopyFile(const FilePath
& from_path
, const FilePath
& to_path
) {
74 if (from_path
.ReferencesParent() || to_path
.ReferencesParent())
76 return CopyFileUnsafe(from_path
, to_path
);
79 bool ContentsEqual(const FilePath
& filename1
, const FilePath
& filename2
) {
80 // 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.
83 std::ifstream
file1(filename1
.value().c_str(),
84 std::ios::in
| std::ios::binary
);
85 std::ifstream
file2(filename2
.value().c_str(),
86 std::ios::in
| std::ios::binary
);
88 // 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())
93 const int BUFFER_SIZE
= 2056;
94 char buffer1
[BUFFER_SIZE
], buffer2
[BUFFER_SIZE
];
96 file1
.read(buffer1
, BUFFER_SIZE
);
97 file2
.read(buffer2
, BUFFER_SIZE
);
99 if ((file1
.eof() != file2
.eof()) ||
100 (file1
.gcount() != file2
.gcount()) ||
101 (memcmp(buffer1
, buffer2
, file1
.gcount()))) {
106 } while (!file1
.eof() || !file2
.eof());
113 bool 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
);
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())
123 std::string line1
, line2
;
124 getline(file1
, line1
);
125 getline(file2
, line2
);
127 // Check for mismatched EOF states, or any error state.
128 if ((file1
.eof() != file2
.eof()) ||
129 file1
.bad() || file2
.bad()) {
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
)
137 else if (end1
+ 1 < line1
.length())
138 line1
.erase(end1
+ 1);
140 std::string::size_type end2
= line2
.find_last_not_of("\r\n");
141 if (end2
== std::string::npos
)
143 else if (end2
+ 1 < line2
.length())
144 line2
.erase(end2
+ 1);
148 } while (!file1
.eof() || !file2
.eof());
153 bool ReadFileToString(const FilePath
& path
, std::string
* contents
) {
154 if (path
.ReferencesParent())
156 FILE* file
= OpenFile(path
, "rb");
163 while ((len
= fread(buf
, 1, sizeof(buf
), file
)) > 0) {
165 contents
->append(buf
, len
);
172 bool IsDirectoryEmpty(const FilePath
& dir_path
) {
173 FileEnumerator
files(dir_path
, false,
174 FileEnumerator::FILES
| FileEnumerator::DIRECTORIES
);
175 if (files
.Next().empty())
180 FILE* CreateAndOpenTemporaryFile(FilePath
* path
) {
182 if (!GetTempDir(&directory
))
185 return CreateAndOpenTemporaryFileInDir(directory
, path
);
188 bool CreateDirectory(const base::FilePath
& full_path
) {
189 return CreateDirectoryAndGetError(full_path
, NULL
);
192 bool GetFileSize(const FilePath
& file_path
, int64
* file_size
) {
193 base::PlatformFileInfo info
;
194 if (!GetFileInfo(file_path
, &info
))
196 *file_size
= info
.size
;
200 bool TouchFile(const FilePath
& path
,
201 const base::Time
& last_accessed
,
202 const base::Time
& last_modified
) {
203 int flags
= base::PLATFORM_FILE_OPEN
| base::PLATFORM_FILE_WRITE_ATTRIBUTES
;
206 // On Windows, FILE_FLAG_BACKUP_SEMANTICS is needed to open a directory.
207 if (DirectoryExists(path
))
208 flags
|= base::PLATFORM_FILE_BACKUP_SEMANTICS
;
211 const base::PlatformFile file
=
212 base::CreatePlatformFile(path
, flags
, NULL
, NULL
);
213 if (file
!= base::kInvalidPlatformFileValue
) {
214 bool result
= base::TouchPlatformFile(file
, last_accessed
, last_modified
);
215 base::ClosePlatformFile(file
);
222 bool SetLastModifiedTime(const FilePath
& path
,
223 const base::Time
& last_modified
) {
224 return TouchFile(path
, last_modified
, last_modified
);
227 bool CloseFile(FILE* file
) {
230 return fclose(file
) == 0;
233 bool TruncateFile(FILE* file
) {
236 long current_offset
= ftell(file
);
237 if (current_offset
== -1)
240 int fd
= _fileno(file
);
241 if (_chsize(fd
, current_offset
) != 0)
244 int fd
= fileno(file
);
245 if (ftruncate(fd
, current_offset
) != 0)
251 int GetUniquePathNumber(
252 const FilePath
& path
,
253 const FilePath::StringType
& suffix
) {
254 bool have_suffix
= !suffix
.empty();
255 if (!PathExists(path
) &&
256 (!have_suffix
|| !PathExists(FilePath(path
.value() + suffix
)))) {
261 for (int count
= 1; count
<= kMaxUniqueFiles
; ++count
) {
263 path
.InsertBeforeExtensionASCII(base::StringPrintf(" (%d)", count
));
264 if (!PathExists(new_path
) &&
265 (!have_suffix
|| !PathExists(FilePath(new_path
.value() + suffix
)))) {
273 int64
ComputeDirectorySize(const FilePath
& root_path
) {
274 int64 running_size
= 0;
275 FileEnumerator
file_iter(root_path
, true, FileEnumerator::FILES
);
276 while (!file_iter
.Next().empty())
277 running_size
+= file_iter
.GetInfo().GetSize();