Add support for indeterminate checkbox on Windows classic theme.
[chromium-blink-merge.git] / base / file_util.cc
blob3e7dc4456d122bff5e0037c5bfa95f45eb9b547a
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 bool EndsWithSeparator(const FilePath& path) {
41 FilePath::StringType value = path.value();
42 if (value.empty())
43 return false;
45 return FilePath::IsSeparator(value[value.size() - 1]);
48 bool EnsureEndsWithSeparator(FilePath* path) {
49 if (!DirectoryExists(*path))
50 return false;
52 if (EndsWithSeparator(*path))
53 return true;
55 FilePath::StringType& path_str =
56 const_cast<FilePath::StringType&>(path->value());
57 path_str.append(&FilePath::kSeparators[0], 1);
59 return true;
62 void InsertBeforeExtension(FilePath* path, const FilePath::StringType& suffix) {
63 FilePath::StringType& value =
64 const_cast<FilePath::StringType&>(path->value());
66 const FilePath::StringType::size_type last_dot =
67 value.rfind(kExtensionSeparator);
68 const FilePath::StringType::size_type last_separator =
69 value.find_last_of(FilePath::StringType(FilePath::kSeparators));
71 if (last_dot == FilePath::StringType::npos ||
72 (last_separator != std::wstring::npos && last_dot < last_separator)) {
73 // The path looks something like "C:\pics.old\jojo" or "C:\pics\jojo".
74 // We should just append the suffix to the entire path.
75 value.append(suffix);
76 return;
79 value.insert(last_dot, suffix);
82 bool Move(const FilePath& from_path, const FilePath& to_path) {
83 if (from_path.ReferencesParent() || to_path.ReferencesParent())
84 return false;
85 return MoveUnsafe(from_path, to_path);
88 bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
89 if (from_path.ReferencesParent() || to_path.ReferencesParent())
90 return false;
91 return CopyFileUnsafe(from_path, to_path);
94 bool ContentsEqual(const FilePath& filename1, const FilePath& filename2) {
95 // We open the file in binary format even if they are text files because
96 // we are just comparing that bytes are exactly same in both files and not
97 // doing anything smart with text formatting.
98 std::ifstream file1(filename1.value().c_str(),
99 std::ios::in | std::ios::binary);
100 std::ifstream file2(filename2.value().c_str(),
101 std::ios::in | std::ios::binary);
103 // Even if both files aren't openable (and thus, in some sense, "equal"),
104 // any unusable file yields a result of "false".
105 if (!file1.is_open() || !file2.is_open())
106 return false;
108 const int BUFFER_SIZE = 2056;
109 char buffer1[BUFFER_SIZE], buffer2[BUFFER_SIZE];
110 do {
111 file1.read(buffer1, BUFFER_SIZE);
112 file2.read(buffer2, BUFFER_SIZE);
114 if ((file1.eof() != file2.eof()) ||
115 (file1.gcount() != file2.gcount()) ||
116 (memcmp(buffer1, buffer2, file1.gcount()))) {
117 file1.close();
118 file2.close();
119 return false;
121 } while (!file1.eof() || !file2.eof());
123 file1.close();
124 file2.close();
125 return true;
128 bool TextContentsEqual(const FilePath& filename1, const FilePath& filename2) {
129 std::ifstream file1(filename1.value().c_str(), std::ios::in);
130 std::ifstream file2(filename2.value().c_str(), std::ios::in);
132 // Even if both files aren't openable (and thus, in some sense, "equal"),
133 // any unusable file yields a result of "false".
134 if (!file1.is_open() || !file2.is_open())
135 return false;
137 do {
138 std::string line1, line2;
139 getline(file1, line1);
140 getline(file2, line2);
142 // Check for mismatched EOF states, or any error state.
143 if ((file1.eof() != file2.eof()) ||
144 file1.bad() || file2.bad()) {
145 return false;
148 // Trim all '\r' and '\n' characters from the end of the line.
149 std::string::size_type end1 = line1.find_last_not_of("\r\n");
150 if (end1 == std::string::npos)
151 line1.clear();
152 else if (end1 + 1 < line1.length())
153 line1.erase(end1 + 1);
155 std::string::size_type end2 = line2.find_last_not_of("\r\n");
156 if (end2 == std::string::npos)
157 line2.clear();
158 else if (end2 + 1 < line2.length())
159 line2.erase(end2 + 1);
161 if (line1 != line2)
162 return false;
163 } while (!file1.eof() || !file2.eof());
165 return true;
168 bool ReadFileToString(const FilePath& path, std::string* contents) {
169 if (path.ReferencesParent())
170 return false;
171 FILE* file = OpenFile(path, "rb");
172 if (!file) {
173 return false;
176 char buf[1 << 16];
177 size_t len;
178 while ((len = fread(buf, 1, sizeof(buf), file)) > 0) {
179 if (contents)
180 contents->append(buf, len);
182 CloseFile(file);
184 return true;
187 bool IsDirectoryEmpty(const FilePath& dir_path) {
188 FileEnumerator files(dir_path, false,
189 FileEnumerator::FILES | FileEnumerator::DIRECTORIES);
190 if (files.Next().value().empty())
191 return true;
192 return false;
195 FILE* CreateAndOpenTemporaryFile(FilePath* path) {
196 FilePath directory;
197 if (!GetTempDir(&directory))
198 return NULL;
200 return CreateAndOpenTemporaryFileInDir(directory, path);
203 bool GetFileSize(const FilePath& file_path, int64* file_size) {
204 base::PlatformFileInfo info;
205 if (!GetFileInfo(file_path, &info))
206 return false;
207 *file_size = info.size;
208 return true;
211 bool IsDot(const FilePath& path) {
212 return FILE_PATH_LITERAL(".") == path.BaseName().value();
215 bool IsDotDot(const FilePath& path) {
216 return FILE_PATH_LITERAL("..") == path.BaseName().value();
219 bool TouchFile(const FilePath& path,
220 const base::Time& last_accessed,
221 const base::Time& last_modified) {
222 int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE_ATTRIBUTES;
224 #if defined(OS_WIN)
225 // On Windows, FILE_FLAG_BACKUP_SEMANTICS is needed to open a directory.
226 if (DirectoryExists(path))
227 flags |= base::PLATFORM_FILE_BACKUP_SEMANTICS;
228 #endif // OS_WIN
230 const base::PlatformFile file =
231 base::CreatePlatformFile(path, flags, NULL, NULL);
232 if (file != base::kInvalidPlatformFileValue) {
233 bool result = base::TouchPlatformFile(file, last_accessed, last_modified);
234 base::ClosePlatformFile(file);
235 return result;
238 return false;
241 bool SetLastModifiedTime(const FilePath& path,
242 const base::Time& last_modified) {
243 return TouchFile(path, last_modified, last_modified);
246 bool CloseFile(FILE* file) {
247 if (file == NULL)
248 return true;
249 return fclose(file) == 0;
252 bool TruncateFile(FILE* file) {
253 if (file == NULL)
254 return false;
255 long current_offset = ftell(file);
256 if (current_offset == -1)
257 return false;
258 #if defined(OS_WIN)
259 int fd = _fileno(file);
260 if (_chsize(fd, current_offset) != 0)
261 return false;
262 #else
263 int fd = fileno(file);
264 if (ftruncate(fd, current_offset) != 0)
265 return false;
266 #endif
267 return true;
270 int GetUniquePathNumber(
271 const FilePath& path,
272 const FilePath::StringType& suffix) {
273 bool have_suffix = !suffix.empty();
274 if (!PathExists(path) &&
275 (!have_suffix || !PathExists(FilePath(path.value() + suffix)))) {
276 return 0;
279 FilePath new_path;
280 for (int count = 1; count <= kMaxUniqueFiles; ++count) {
281 new_path =
282 path.InsertBeforeExtensionASCII(base::StringPrintf(" (%d)", count));
283 if (!PathExists(new_path) &&
284 (!have_suffix || !PathExists(FilePath(new_path.value() + suffix)))) {
285 return count;
289 return -1;
292 bool ContainsPath(const FilePath &parent, const FilePath& child) {
293 FilePath abs_parent = FilePath(parent);
294 FilePath abs_child = FilePath(child);
296 if (!file_util::AbsolutePath(&abs_parent) ||
297 !file_util::AbsolutePath(&abs_child))
298 return false;
300 #if defined(OS_WIN)
301 // file_util::AbsolutePath() does not flatten case on Windows, so we must do
302 // a case-insensitive compare.
303 if (!StartsWith(abs_child.value(), abs_parent.value(), false))
304 #else
305 if (!StartsWithASCII(abs_child.value(), abs_parent.value(), true))
306 #endif
307 return false;
309 // file_util::AbsolutePath() normalizes '/' to '\' on Windows, so we only need
310 // to check kSeparators[0].
311 if (abs_child.value().length() <= abs_parent.value().length() ||
312 abs_child.value()[abs_parent.value().length()] !=
313 FilePath::kSeparators[0])
314 return false;
316 return true;
319 int64 ComputeDirectorySize(const FilePath& root_path) {
320 int64 running_size = 0;
321 FileEnumerator file_iter(root_path, true, FileEnumerator::FILES);
322 for (FilePath current = file_iter.Next(); !current.empty();
323 current = file_iter.Next()) {
324 FileEnumerator::FindInfo info;
325 file_iter.GetFindInfo(&info);
326 #if defined(OS_WIN)
327 LARGE_INTEGER li = { info.nFileSizeLow, info.nFileSizeHigh };
328 running_size += li.QuadPart;
329 #else
330 running_size += info.stat.st_size;
331 #endif
333 return running_size;
336 ///////////////////////////////////////////////
337 // FileEnumerator
339 // Note: the main logic is in file_util_<platform>.cc
341 bool FileEnumerator::ShouldSkip(const FilePath& path) {
342 FilePath::StringType basename = path.BaseName().value();
343 return IsDot(path) || (IsDotDot(path) && !(INCLUDE_DOT_DOT & file_type_));
346 } // namespace