[go: nahoru, domu]

blob: 049bb36815274333e0c460681665ec2ba1df63ee [file] [log] [blame]
thestig@chromium.orgb2f28d22012-03-03 01:54:351// Copyright (c) 2012 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commitd7cae122008-07-26 21:49:384
5#include "base/file_util.h"
6
jeremy@chromium.orgc2c998c2009-01-27 19:08:397#if defined(OS_WIN)
8#include <io.h>
9#endif
mark@chromium.org836f1342008-10-01 17:40:1310#include <stdio.h>
11
initial.commitd7cae122008-07-26 21:49:3812#include <fstream>
initial.commitd7cae122008-07-26 21:49:3813
brettw@chromium.org25a4c1c2013-06-08 04:53:3614#include "base/files/file_enumerator.h"
brettw@chromium.org57999812013-02-24 05:40:5215#include "base/files/file_path.h"
initial.commitd7cae122008-07-26 21:49:3816#include "base/logging.h"
tfarina@chromium.orgeb62f7262013-03-30 14:29:0017#include "base/strings/string_piece.h"
avi@chromium.org251cd6e52013-06-11 13:36:3718#include "base/strings/string_util.h"
19#include "base/strings/stringprintf.h"
avi@chromium.orga4ea1f12013-06-07 18:37:0720#include "base/strings/utf_string_conversions.h"
estade@chromium.orgb9e04f02008-11-27 04:03:5721
brettw@chromium.org0408c752013-06-22 22:15:4622namespace base {
brettw@chromium.org04af979a2013-02-16 04:12:2623
estade@chromium.orgceeb87e2008-12-04 20:46:0624namespace {
25
26const FilePath::CharType kExtensionSeparator = FILE_PATH_LITERAL('.');
jam@chromium.orge285afa2012-01-31 23:16:3927
28// The maximum number of 'uniquified' files we will try to create.
29// This is used when the filename we're trying to download is already in use,
30// so we create a new unique filename by appending " (nnn)" before the
31// extension, where 1 <= nnn <= kMaxUniqueFiles.
32// Also used by code that cleans up said files.
33static const int kMaxUniqueFiles = 100;
estade@chromium.orgceeb87e2008-12-04 20:46:0634
willchan@chromium.orgc145cbdd2009-04-24 17:44:3935} // namespace
estade@chromium.orgceeb87e2008-12-04 20:46:0636
brettw@chromium.org0408c752013-06-22 22:15:4637bool g_bug108724_debug = false;
38
39int64 ComputeDirectorySize(const FilePath& root_path) {
40 int64 running_size = 0;
41 FileEnumerator file_iter(root_path, true, FileEnumerator::FILES);
42 while (!file_iter.Next().empty())
43 running_size += file_iter.GetInfo().GetSize();
44 return running_size;
45}
46
47} // namespace base
48
49// -----------------------------------------------------------------------------
50
initial.commitd7cae122008-07-26 21:49:3851namespace file_util {
52
brettw@chromium.org0408c752013-06-22 22:15:4653using base::FileEnumerator;
54using base::FilePath;
55using base::kExtensionSeparator;
56using base::kMaxUniqueFiles;
aa@chromium.org354002bb2012-02-05 03:22:3857
estade@chromium.orgceeb87e2008-12-04 20:46:0658void InsertBeforeExtension(FilePath* path, const FilePath::StringType& suffix) {
59 FilePath::StringType& value =
60 const_cast<FilePath::StringType&>(path->value());
61
62 const FilePath::StringType::size_type last_dot =
63 value.rfind(kExtensionSeparator);
64 const FilePath::StringType::size_type last_separator =
65 value.find_last_of(FilePath::StringType(FilePath::kSeparators));
66
67 if (last_dot == FilePath::StringType::npos ||
68 (last_separator != std::wstring::npos && last_dot < last_separator)) {
69 // The path looks something like "C:\pics.old\jojo" or "C:\pics\jojo".
70 // We should just append the suffix to the entire path.
71 value.append(suffix);
72 return;
73 }
74
75 value.insert(last_dot, suffix);
76}
77
cevans@chromium.org3cd2c1c2013-02-06 20:38:0778bool Move(const FilePath& from_path, const FilePath& to_path) {
79 if (from_path.ReferencesParent() || to_path.ReferencesParent())
80 return false;
81 return MoveUnsafe(from_path, to_path);
82}
83
dgrogan@chromium.org6f5399412013-05-08 22:02:3684bool ReplaceFile(const base::FilePath& from_path,
85 const base::FilePath& to_path) {
86 return ReplaceFileAndGetError(from_path, to_path, NULL);
87}
88
cevans@chromium.org3cd2c1c2013-02-06 20:38:0789bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
90 if (from_path.ReferencesParent() || to_path.ReferencesParent())
91 return false;
92 return CopyFileUnsafe(from_path, to_path);
93}
94
evanm@google.com640517f2008-10-30 23:54:0495bool ContentsEqual(const FilePath& filename1, const FilePath& filename2) {
initial.commitd7cae122008-07-26 21:49:3896 // We open the file in binary format even if they are text files because
97 // we are just comparing that bytes are exactly same in both files and not
98 // doing anything smart with text formatting.
evanm@google.com640517f2008-10-30 23:54:0499 std::ifstream file1(filename1.value().c_str(),
erikkay@google.com5af2edb92008-08-08 20:16:08100 std::ios::in | std::ios::binary);
evanm@google.com640517f2008-10-30 23:54:04101 std::ifstream file2(filename2.value().c_str(),
erikkay@google.com5af2edb92008-08-08 20:16:08102 std::ios::in | std::ios::binary);
estade@chromium.orgb9e04f02008-11-27 04:03:57103
initial.commitd7cae122008-07-26 21:49:38104 // Even if both files aren't openable (and thus, in some sense, "equal"),
105 // any unusable file yields a result of "false".
106 if (!file1.is_open() || !file2.is_open())
107 return false;
108
109 const int BUFFER_SIZE = 2056;
110 char buffer1[BUFFER_SIZE], buffer2[BUFFER_SIZE];
111 do {
112 file1.read(buffer1, BUFFER_SIZE);
113 file2.read(buffer2, BUFFER_SIZE);
114
mark@chromium.orgb81637c32009-06-26 21:17:24115 if ((file1.eof() != file2.eof()) ||
initial.commitd7cae122008-07-26 21:49:38116 (file1.gcount() != file2.gcount()) ||
117 (memcmp(buffer1, buffer2, file1.gcount()))) {
118 file1.close();
119 file2.close();
120 return false;
121 }
mark@chromium.orgb81637c32009-06-26 21:17:24122 } while (!file1.eof() || !file2.eof());
initial.commitd7cae122008-07-26 21:49:38123
124 file1.close();
125 file2.close();
126 return true;
127}
128
mark@chromium.orgb81637c32009-06-26 21:17:24129bool TextContentsEqual(const FilePath& filename1, const FilePath& filename2) {
130 std::ifstream file1(filename1.value().c_str(), std::ios::in);
131 std::ifstream file2(filename2.value().c_str(), std::ios::in);
132
133 // Even if both files aren't openable (and thus, in some sense, "equal"),
134 // any unusable file yields a result of "false".
135 if (!file1.is_open() || !file2.is_open())
136 return false;
137
138 do {
139 std::string line1, line2;
140 getline(file1, line1);
141 getline(file2, line2);
142
143 // Check for mismatched EOF states, or any error state.
144 if ((file1.eof() != file2.eof()) ||
145 file1.bad() || file2.bad()) {
146 return false;
147 }
148
149 // Trim all '\r' and '\n' characters from the end of the line.
150 std::string::size_type end1 = line1.find_last_not_of("\r\n");
151 if (end1 == std::string::npos)
152 line1.clear();
153 else if (end1 + 1 < line1.length())
154 line1.erase(end1 + 1);
155
156 std::string::size_type end2 = line2.find_last_not_of("\r\n");
157 if (end2 == std::string::npos)
158 line2.clear();
159 else if (end2 + 1 < line2.length())
160 line2.erase(end2 + 1);
161
162 if (line1 != line2)
163 return false;
164 } while (!file1.eof() || !file2.eof());
165
166 return true;
167}
168
erikkay@google.com3c5281022009-01-28 00:22:46169bool ReadFileToString(const FilePath& path, std::string* contents) {
cpu@chromium.org9fea5a92013-01-09 00:38:59170 if (path.ReferencesParent())
171 return false;
mark@chromium.org836f1342008-10-01 17:40:13172 FILE* file = OpenFile(path, "rb");
173 if (!file) {
initial.commitd7cae122008-07-26 21:49:38174 return false;
mark@chromium.org836f1342008-10-01 17:40:13175 }
initial.commitd7cae122008-07-26 21:49:38176
177 char buf[1 << 16];
178 size_t len;
179 while ((len = fread(buf, 1, sizeof(buf), file)) > 0) {
evan@chromium.org4e074bae2010-05-19 11:07:55180 if (contents)
181 contents->append(buf, len);
initial.commitd7cae122008-07-26 21:49:38182 }
mark@chromium.org836f1342008-10-01 17:40:13183 CloseFile(file);
initial.commitd7cae122008-07-26 21:49:38184
185 return true;
initial.commitd7cae122008-07-26 21:49:38186}
187
tfarina@chromium.orgb33f1d92010-05-26 01:40:12188bool IsDirectoryEmpty(const FilePath& dir_path) {
189 FileEnumerator files(dir_path, false,
haruki@chromium.org84c3f162012-08-12 01:57:23190 FileEnumerator::FILES | FileEnumerator::DIRECTORIES);
brettw@chromium.org25a4c1c2013-06-08 04:53:36191 if (files.Next().empty())
tfarina@chromium.orgb33f1d92010-05-26 01:40:12192 return true;
193 return false;
194}
195
phajdan.jr@chromium.org6faa0e0d2009-04-28 06:50:36196FILE* CreateAndOpenTemporaryFile(FilePath* path) {
197 FilePath directory;
198 if (!GetTempDir(&directory))
evan@chromium.org628476aa2010-06-10 22:56:23199 return NULL;
phajdan.jr@chromium.org6faa0e0d2009-04-28 06:50:36200
201 return CreateAndOpenTemporaryFileInDir(directory, path);
202}
203
dgrogan@chromium.orgcfd23d22013-06-11 03:50:25204bool CreateDirectory(const base::FilePath& full_path) {
205 return CreateDirectoryAndGetError(full_path, NULL);
206}
207
dkegel@google.comeac0709a2008-11-04 21:00:46208bool GetFileSize(const FilePath& file_path, int64* file_size) {
dumi@chromium.org2f0193c22010-09-03 02:28:37209 base::PlatformFileInfo info;
darin@google.comf5e3da4d2008-09-26 01:04:08210 if (!GetFileInfo(file_path, &info))
211 return false;
212 *file_size = info.size;
213 return true;
214}
215
dumi@chromium.org507fb9a2010-09-23 23:28:22216bool TouchFile(const FilePath& path,
217 const base::Time& last_accessed,
218 const base::Time& last_modified) {
nhiroki@chromium.org307a825a2012-11-01 11:48:52219 int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE_ATTRIBUTES;
220
221#if defined(OS_WIN)
222 // On Windows, FILE_FLAG_BACKUP_SEMANTICS is needed to open a directory.
223 if (DirectoryExists(path))
224 flags |= base::PLATFORM_FILE_BACKUP_SEMANTICS;
225#endif // OS_WIN
226
227 const base::PlatformFile file =
228 base::CreatePlatformFile(path, flags, NULL, NULL);
dumi@chromium.org507fb9a2010-09-23 23:28:22229 if (file != base::kInvalidPlatformFileValue) {
230 bool result = base::TouchPlatformFile(file, last_accessed, last_modified);
231 base::ClosePlatformFile(file);
232 return result;
233 }
234
235 return false;
236}
237
238bool SetLastModifiedTime(const FilePath& path,
239 const base::Time& last_modified) {
240 return TouchFile(path, last_modified, last_modified);
241}
242
mark@chromium.org836f1342008-10-01 17:40:13243bool CloseFile(FILE* file) {
sidchat@google.coma1a19502008-10-21 17:14:45244 if (file == NULL)
245 return true;
mark@chromium.org836f1342008-10-01 17:40:13246 return fclose(file) == 0;
jeremy@chromium.org6e01dae2009-01-27 17:13:02247}
248
jeremy@chromium.orgc2c998c2009-01-27 19:08:39249bool TruncateFile(FILE* file) {
250 if (file == NULL)
251 return false;
252 long current_offset = ftell(file);
253 if (current_offset == -1)
254 return false;
255#if defined(OS_WIN)
256 int fd = _fileno(file);
257 if (_chsize(fd, current_offset) != 0)
258 return false;
259#else
260 int fd = fileno(file);
261 if (ftruncate(fd, current_offset) != 0)
262 return false;
263#endif
264 return true;
265}
266
jam@chromium.orge285afa2012-01-31 23:16:39267int GetUniquePathNumber(
268 const FilePath& path,
269 const FilePath::StringType& suffix) {
270 bool have_suffix = !suffix.empty();
271 if (!PathExists(path) &&
272 (!have_suffix || !PathExists(FilePath(path.value() + suffix)))) {
273 return 0;
274 }
275
276 FilePath new_path;
277 for (int count = 1; count <= kMaxUniqueFiles; ++count) {
groby@chromium.org7d3cbc92013-03-18 22:33:04278 new_path =
279 path.InsertBeforeExtensionASCII(base::StringPrintf(" (%d)", count));
jam@chromium.orge285afa2012-01-31 23:16:39280 if (!PathExists(new_path) &&
281 (!have_suffix || !PathExists(FilePath(new_path.value() + suffix)))) {
282 return count;
283 }
284 }
285
286 return -1;
aa@chromium.orgee5c29da2009-01-09 22:14:27287}
288
brettw@chromium.org0408c752013-06-22 22:15:46289} // namespace file_util