Encode method and error message inside LevelDB::Status message
[chromium-blink-merge.git] / base / file_util.cc
blob58dbd795d34f54b24b7e89251b94c81d1d8e5ba5
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_path.h"
15 #include "base/logging.h"
16 #include "base/string_util.h"
17 #include "base/stringprintf.h"
18 #include "base/strings/string_piece.h"
19 #include "base/utf_string_conversions.h"
21 using base::FilePath;
23 namespace {
25 const FilePath::CharType kExtensionSeparator = FILE_PATH_LITERAL('.');
27 // The maximum number of 'uniquified' files we will try to create.
28 // This is used when the filename we're trying to download is already in use,
29 // so we create a new unique filename by appending " (nnn)" before the
30 // extension, where 1 <= nnn <= kMaxUniqueFiles.
31 // Also used by code that cleans up said files.
32 static const int kMaxUniqueFiles = 100;
34 } // namespace
36 namespace file_util {
38 bool g_bug108724_debug = false;
40 void InsertBeforeExtension(FilePath* path, const FilePath::StringType& suffix) {
41 FilePath::StringType& value =
42 const_cast<FilePath::StringType&>(path->value());
44 const FilePath::StringType::size_type last_dot =
45 value.rfind(kExtensionSeparator);
46 const FilePath::StringType::size_type last_separator =
47 value.find_last_of(FilePath::StringType(FilePath::kSeparators));
49 if (last_dot == FilePath::StringType::npos ||
50 (last_separator != std::wstring::npos && last_dot < last_separator)) {
51 // The path looks something like "C:\pics.old\jojo" or "C:\pics\jojo".
52 // We should just append the suffix to the entire path.
53 value.append(suffix);
54 return;
57 value.insert(last_dot, suffix);
60 bool Move(const FilePath& from_path, const FilePath& to_path) {
61 if (from_path.ReferencesParent() || to_path.ReferencesParent())
62 return false;
63 return MoveUnsafe(from_path, to_path);
66 bool ReplaceFile(const base::FilePath& from_path,
67 const base::FilePath& to_path) {
68 return ReplaceFileAndGetError(from_path, to_path, NULL);
71 bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
72 if (from_path.ReferencesParent() || to_path.ReferencesParent())
73 return false;
74 return CopyFileUnsafe(from_path, to_path);
77 bool ContentsEqual(const FilePath& filename1, const FilePath& filename2) {
78 // We open the file in binary format even if they are text files because
79 // we are just comparing that bytes are exactly same in both files and not
80 // doing anything smart with text formatting.
81 std::ifstream file1(filename1.value().c_str(),
82 std::ios::in | std::ios::binary);
83 std::ifstream file2(filename2.value().c_str(),
84 std::ios::in | std::ios::binary);
86 // Even if both files aren't openable (and thus, in some sense, "equal"),
87 // any unusable file yields a result of "false".
88 if (!file1.is_open() || !file2.is_open())
89 return false;
91 const int BUFFER_SIZE = 2056;
92 char buffer1[BUFFER_SIZE], buffer2[BUFFER_SIZE];
93 do {
94 file1.read(buffer1, BUFFER_SIZE);
95 file2.read(buffer2, BUFFER_SIZE);
97 if ((file1.eof() != file2.eof()) ||
98 (file1.gcount() != file2.gcount()) ||
99 (memcmp(buffer1, buffer2, file1.gcount()))) {
100 file1.close();
101 file2.close();
102 return false;
104 } while (!file1.eof() || !file2.eof());
106 file1.close();
107 file2.close();
108 return true;
111 bool TextContentsEqual(const FilePath& filename1, const FilePath& filename2) {
112 std::ifstream file1(filename1.value().c_str(), std::ios::in);
113 std::ifstream file2(filename2.value().c_str(), std::ios::in);
115 // Even if both files aren't openable (and thus, in some sense, "equal"),
116 // any unusable file yields a result of "false".
117 if (!file1.is_open() || !file2.is_open())
118 return false;
120 do {
121 std::string line1, line2;
122 getline(file1, line1);
123 getline(file2, line2);
125 // Check for mismatched EOF states, or any error state.
126 if ((file1.eof() != file2.eof()) ||
127 file1.bad() || file2.bad()) {
128 return false;
131 // Trim all '\r' and '\n' characters from the end of the line.
132 std::string::size_type end1 = line1.find_last_not_of("\r\n");
133 if (end1 == std::string::npos)
134 line1.clear();
135 else if (end1 + 1 < line1.length())
136 line1.erase(end1 + 1);
138 std::string::size_type end2 = line2.find_last_not_of("\r\n");
139 if (end2 == std::string::npos)
140 line2.clear();
141 else if (end2 + 1 < line2.length())
142 line2.erase(end2 + 1);
144 if (line1 != line2)
145 return false;
146 } while (!file1.eof() || !file2.eof());
148 return true;
151 bool ReadFileToString(const FilePath& path, std::string* contents) {
152 if (path.ReferencesParent())
153 return false;
154 FILE* file = OpenFile(path, "rb");
155 if (!file) {
156 return false;
159 char buf[1 << 16];
160 size_t len;
161 while ((len = fread(buf, 1, sizeof(buf), file)) > 0) {
162 if (contents)
163 contents->append(buf, len);
165 CloseFile(file);
167 return true;
170 bool IsDirectoryEmpty(const FilePath& dir_path) {
171 FileEnumerator files(dir_path, false,
172 FileEnumerator::FILES | FileEnumerator::DIRECTORIES);
173 if (files.Next().value().empty())
174 return true;
175 return false;
178 FILE* CreateAndOpenTemporaryFile(FilePath* path) {
179 FilePath directory;
180 if (!GetTempDir(&directory))
181 return NULL;
183 return CreateAndOpenTemporaryFileInDir(directory, path);
186 bool GetFileSize(const FilePath& file_path, int64* file_size) {
187 base::PlatformFileInfo info;
188 if (!GetFileInfo(file_path, &info))
189 return false;
190 *file_size = info.size;
191 return true;
194 bool TouchFile(const FilePath& path,
195 const base::Time& last_accessed,
196 const base::Time& last_modified) {
197 int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE_ATTRIBUTES;
199 #if defined(OS_WIN)
200 // On Windows, FILE_FLAG_BACKUP_SEMANTICS is needed to open a directory.
201 if (DirectoryExists(path))
202 flags |= base::PLATFORM_FILE_BACKUP_SEMANTICS;
203 #endif // OS_WIN
205 const base::PlatformFile file =
206 base::CreatePlatformFile(path, flags, NULL, NULL);
207 if (file != base::kInvalidPlatformFileValue) {
208 bool result = base::TouchPlatformFile(file, last_accessed, last_modified);
209 base::ClosePlatformFile(file);
210 return result;
213 return false;
216 bool SetLastModifiedTime(const FilePath& path,
217 const base::Time& last_modified) {
218 return TouchFile(path, last_modified, last_modified);
221 bool CloseFile(FILE* file) {
222 if (file == NULL)
223 return true;
224 return fclose(file) == 0;
227 bool TruncateFile(FILE* file) {
228 if (file == NULL)
229 return false;
230 long current_offset = ftell(file);
231 if (current_offset == -1)
232 return false;
233 #if defined(OS_WIN)
234 int fd = _fileno(file);
235 if (_chsize(fd, current_offset) != 0)
236 return false;
237 #else
238 int fd = fileno(file);
239 if (ftruncate(fd, current_offset) != 0)
240 return false;
241 #endif
242 return true;
245 int GetUniquePathNumber(
246 const FilePath& path,
247 const FilePath::StringType& suffix) {
248 bool have_suffix = !suffix.empty();
249 if (!PathExists(path) &&
250 (!have_suffix || !PathExists(FilePath(path.value() + suffix)))) {
251 return 0;
254 FilePath new_path;
255 for (int count = 1; count <= kMaxUniqueFiles; ++count) {
256 new_path =
257 path.InsertBeforeExtensionASCII(base::StringPrintf(" (%d)", count));
258 if (!PathExists(new_path) &&
259 (!have_suffix || !PathExists(FilePath(new_path.value() + suffix)))) {
260 return count;
264 return -1;
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);
274 #if defined(OS_WIN)
275 LARGE_INTEGER li = { info.nFileSizeLow, info.nFileSizeHigh };
276 running_size += li.QuadPart;
277 #else
278 running_size += info.stat.st_size;
279 #endif
281 return running_size;
284 ///////////////////////////////////////////////
285 // FileEnumerator
287 // Note: the main logic is in file_util_<platform>.cc
289 bool FileEnumerator::ShouldSkip(const FilePath& path) {
290 FilePath::StringType basename = path.BaseName().value();
291 return basename == FILE_PATH_LITERAL(".") ||
292 (basename == FILE_PATH_LITERAL("..") &&
293 !(INCLUDE_DOT_DOT & file_type_));
296 } // namespace