Record error when CreateDir fails.
[chromium-blink-merge.git] / base / file_util.cc
blob8e0fbb64dffc758c94c7073f1145996f2a45ed8d
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"
7 #if defined(OS_WIN)
8 #include <io.h>
9 #endif
10 #include <stdio.h>
12 #include <fstream>
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;
23 using base::FilePath;
25 namespace {
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;
36 } // namespace
38 namespace file_util {
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.
55 value.append(suffix);
56 return;
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())
64 return false;
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())
75 return false;
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())
91 return false;
93 const int BUFFER_SIZE = 2056;
94 char buffer1[BUFFER_SIZE], buffer2[BUFFER_SIZE];
95 do {
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()))) {
102 file1.close();
103 file2.close();
104 return false;
106 } while (!file1.eof() || !file2.eof());
108 file1.close();
109 file2.close();
110 return true;
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())
120 return false;
122 do {
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()) {
130 return false;
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)
136 line1.clear();
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)
142 line2.clear();
143 else if (end2 + 1 < line2.length())
144 line2.erase(end2 + 1);
146 if (line1 != line2)
147 return false;
148 } while (!file1.eof() || !file2.eof());
150 return true;
153 bool ReadFileToString(const FilePath& path, std::string* contents) {
154 if (path.ReferencesParent())
155 return false;
156 FILE* file = OpenFile(path, "rb");
157 if (!file) {
158 return false;
161 char buf[1 << 16];
162 size_t len;
163 while ((len = fread(buf, 1, sizeof(buf), file)) > 0) {
164 if (contents)
165 contents->append(buf, len);
167 CloseFile(file);
169 return true;
172 bool IsDirectoryEmpty(const FilePath& dir_path) {
173 FileEnumerator files(dir_path, false,
174 FileEnumerator::FILES | FileEnumerator::DIRECTORIES);
175 if (files.Next().empty())
176 return true;
177 return false;
180 FILE* CreateAndOpenTemporaryFile(FilePath* path) {
181 FilePath directory;
182 if (!GetTempDir(&directory))
183 return NULL;
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))
195 return false;
196 *file_size = info.size;
197 return true;
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;
205 #if defined(OS_WIN)
206 // On Windows, FILE_FLAG_BACKUP_SEMANTICS is needed to open a directory.
207 if (DirectoryExists(path))
208 flags |= base::PLATFORM_FILE_BACKUP_SEMANTICS;
209 #endif // OS_WIN
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);
216 return result;
219 return false;
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) {
228 if (file == NULL)
229 return true;
230 return fclose(file) == 0;
233 bool TruncateFile(FILE* file) {
234 if (file == NULL)
235 return false;
236 long current_offset = ftell(file);
237 if (current_offset == -1)
238 return false;
239 #if defined(OS_WIN)
240 int fd = _fileno(file);
241 if (_chsize(fd, current_offset) != 0)
242 return false;
243 #else
244 int fd = fileno(file);
245 if (ftruncate(fd, current_offset) != 0)
246 return false;
247 #endif
248 return true;
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)))) {
257 return 0;
260 FilePath new_path;
261 for (int count = 1; count <= kMaxUniqueFiles; ++count) {
262 new_path =
263 path.InsertBeforeExtensionASCII(base::StringPrintf(" (%d)", count));
264 if (!PathExists(new_path) &&
265 (!have_suffix || !PathExists(FilePath(new_path.value() + suffix)))) {
266 return count;
270 return -1;
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();
278 return running_size;
281 } // namespace