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"
26 // The maximum number of 'uniquified' files we will try to create.
27 // This is used when the filename we're trying to download is already in use,
28 // so we create a new unique filename by appending " (nnn)" before the
29 // extension, where 1 <= nnn <= kMaxUniqueFiles.
30 // Also used by code that cleans up said files.
31 static const int kMaxUniqueFiles = 100;
35 int64 ComputeDirectorySize(const FilePath& root_path) {
36 int64 running_size = 0;
37 FileEnumerator file_iter(root_path, true, FileEnumerator::FILES);
38 while (!file_iter.Next().empty())
39 running_size += file_iter.GetInfo().GetSize();
43 bool Move(const FilePath& from_path, const FilePath& to_path) {
44 if (from_path.ReferencesParent() || to_path.ReferencesParent())
46 return internal::MoveUnsafe(from_path, to_path);
49 bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
50 if (from_path.ReferencesParent() || to_path.ReferencesParent())
52 return internal::CopyFileUnsafe(from_path, to_path);
55 bool ContentsEqual(const FilePath& filename1, const FilePath& filename2) {
56 // We open the file in binary format even if they are text files because
57 // we are just comparing that bytes are exactly same in both files and not
58 // doing anything smart with text formatting.
59 std::ifstream file1(filename1.value().c_str(),
60 std::ios::in | std::ios::binary);
61 std::ifstream file2(filename2.value().c_str(),
62 std::ios::in | std::ios::binary);
64 // Even if both files aren't openable (and thus, in some sense, "equal"),
65 // any unusable file yields a result of "false".
66 if (!file1.is_open() || !file2.is_open())
69 const int BUFFER_SIZE = 2056;
70 char buffer1[BUFFER_SIZE], buffer2[BUFFER_SIZE];
72 file1.read(buffer1, BUFFER_SIZE);
73 file2.read(buffer2, BUFFER_SIZE);
75 if ((file1.eof() != file2.eof()) ||
76 (file1.gcount() != file2.gcount()) ||
77 (memcmp(buffer1, buffer2, file1.gcount()))) {
82 } while (!file1.eof() || !file2.eof());
89 bool TextContentsEqual(const FilePath& filename1, const FilePath& filename2) {
90 std::ifstream file1(filename1.value().c_str(), std::ios::in);
91 std::ifstream file2(filename2.value().c_str(), std::ios::in);
93 // Even if both files aren't openable (and thus, in some sense, "equal"),
94 // any unusable file yields a result of "false".
95 if (!file1.is_open() || !file2.is_open())
99 std::string line1, line2;
100 getline(file1, line1);
101 getline(file2, line2);
103 // Check for mismatched EOF states, or any error state.
104 if ((file1.eof() != file2.eof()) ||
105 file1.bad() || file2.bad()) {
109 // Trim all '\r' and '\n' characters from the end of the line.
110 std::string::size_type end1 = line1.find_last_not_of("\r\n");
111 if (end1 == std::string::npos)
113 else if (end1 + 1 < line1.length())
114 line1.erase(end1 + 1);
116 std::string::size_type end2 = line2.find_last_not_of("\r\n");
117 if (end2 == std::string::npos)
119 else if (end2 + 1 < line2.length())
120 line2.erase(end2 + 1);
124 } while (!file1.eof() || !file2.eof());
129 bool ReadFileToString(const FilePath& path, std::string* contents) {
130 if (path.ReferencesParent())
132 FILE* file = file_util::OpenFile(path, "rb");
139 while ((len = fread(buf, 1, sizeof(buf), file)) > 0) {
141 contents->append(buf, len);
143 file_util::CloseFile(file);
150 // -----------------------------------------------------------------------------
152 namespace file_util {
154 using base::FileEnumerator;
155 using base::FilePath;
156 using base::kMaxUniqueFiles;
158 bool IsDirectoryEmpty(const FilePath& dir_path) {
159 FileEnumerator files(dir_path, false,
160 FileEnumerator::FILES | FileEnumerator::DIRECTORIES);
161 if (files.Next().empty())
166 FILE* CreateAndOpenTemporaryFile(FilePath* path) {
168 if (!GetTempDir(&directory))
171 return CreateAndOpenTemporaryFileInDir(directory, path);
174 bool CreateDirectory(const base::FilePath& full_path) {
175 return CreateDirectoryAndGetError(full_path, NULL);
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 TouchFile(const FilePath& path,
187 const base::Time& last_accessed,
188 const base::Time& last_modified) {
189 int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE_ATTRIBUTES;
192 // On Windows, FILE_FLAG_BACKUP_SEMANTICS is needed to open a directory.
193 if (DirectoryExists(path))
194 flags |= base::PLATFORM_FILE_BACKUP_SEMANTICS;
197 const base::PlatformFile file =
198 base::CreatePlatformFile(path, flags, NULL, NULL);
199 if (file != base::kInvalidPlatformFileValue) {
200 bool result = base::TouchPlatformFile(file, last_accessed, last_modified);
201 base::ClosePlatformFile(file);
208 bool SetLastModifiedTime(const FilePath& path,
209 const base::Time& last_modified) {
210 return TouchFile(path, last_modified, last_modified);
213 bool CloseFile(FILE* file) {
216 return fclose(file) == 0;
219 bool TruncateFile(FILE* file) {
222 long current_offset = ftell(file);
223 if (current_offset == -1)
226 int fd = _fileno(file);
227 if (_chsize(fd, current_offset) != 0)
230 int fd = fileno(file);
231 if (ftruncate(fd, current_offset) != 0)
237 int GetUniquePathNumber(
238 const FilePath& path,
239 const FilePath::StringType& suffix) {
240 bool have_suffix = !suffix.empty();
241 if (!PathExists(path) &&
242 (!have_suffix || !PathExists(FilePath(path.value() + suffix)))) {
247 for (int count = 1; count <= kMaxUniqueFiles; ++count) {
249 path.InsertBeforeExtensionASCII(base::StringPrintf(" (%d)", count));
250 if (!PathExists(new_path) &&
251 (!have_suffix || !PathExists(FilePath(new_path.value() + suffix)))) {
259 } // namespace file_util