[go: nahoru, domu]

blob: 8e0fbb64dffc758c94c7073f1145996f2a45ed8d [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.org25a4c1c2013-06-08 04:53:3622using base::FileEnumerator;
brettw@chromium.org04af979a2013-02-16 04:12:2623using base::FilePath;
24
estade@chromium.orgceeb87e2008-12-04 20:46:0625namespace {
26
27const FilePath::CharType kExtensionSeparator = FILE_PATH_LITERAL('.');
jam@chromium.orge285afa2012-01-31 23:16:3928
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.
34static const int kMaxUniqueFiles = 100;
estade@chromium.orgceeb87e2008-12-04 20:46:0635
willchan@chromium.orgc145cbdd2009-04-24 17:44:3936} // namespace
estade@chromium.orgceeb87e2008-12-04 20:46:0637
initial.commitd7cae122008-07-26 21:49:3838namespace file_util {
39
aa@chromium.org354002bb2012-02-05 03:22:3840bool g_bug108724_debug = false;
41
estade@chromium.orgceeb87e2008-12-04 20:46:0642void InsertBeforeExtension(FilePath* path, const FilePath::StringType& suffix) {
43 FilePath::StringType& value =
44 const_cast<FilePath::StringType&>(path->value());
45
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));
50
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;
57 }
58
59 value.insert(last_dot, suffix);
60}
61
cevans@chromium.org3cd2c1c2013-02-06 20:38:0762bool 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);
66}
67
dgrogan@chromium.org6f5399412013-05-08 22:02:3668bool ReplaceFile(const base::FilePath& from_path,
69 const base::FilePath& to_path) {
70 return ReplaceFileAndGetError(from_path, to_path, NULL);
71}
72
cevans@chromium.org3cd2c1c2013-02-06 20:38:0773bool 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);
77}
78
evanm@google.com640517f2008-10-30 23:54:0479bool ContentsEqual(const FilePath& filename1, const FilePath& filename2) {
initial.commitd7cae122008-07-26 21:49:3880 // 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.
evanm@google.com640517f2008-10-30 23:54:0483 std::ifstream file1(filename1.value().c_str(),
erikkay@google.com5af2edb92008-08-08 20:16:0884 std::ios::in | std::ios::binary);
evanm@google.com640517f2008-10-30 23:54:0485 std::ifstream file2(filename2.value().c_str(),
erikkay@google.com5af2edb92008-08-08 20:16:0886 std::ios::in | std::ios::binary);
estade@chromium.orgb9e04f02008-11-27 04:03:5787
initial.commitd7cae122008-07-26 21:49:3888 // 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;
92
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);
98
mark@chromium.orgb81637c32009-06-26 21:17:2499 if ((file1.eof() != file2.eof()) ||
initial.commitd7cae122008-07-26 21:49:38100 (file1.gcount() != file2.gcount()) ||
101 (memcmp(buffer1, buffer2, file1.gcount()))) {
102 file1.close();
103 file2.close();
104 return false;
105 }
mark@chromium.orgb81637c32009-06-26 21:17:24106 } while (!file1.eof() || !file2.eof());
initial.commitd7cae122008-07-26 21:49:38107
108 file1.close();
109 file2.close();
110 return true;
111}
112
mark@chromium.orgb81637c32009-06-26 21:17:24113bool 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);
116
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;
121
122 do {
123 std::string line1, line2;
124 getline(file1, line1);
125 getline(file2, line2);
126
127 // Check for mismatched EOF states, or any error state.
128 if ((file1.eof() != file2.eof()) ||
129 file1.bad() || file2.bad()) {
130 return false;
131 }
132
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);
139
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);
145
146 if (line1 != line2)
147 return false;
148 } while (!file1.eof() || !file2.eof());
149
150 return true;
151}
152
erikkay@google.com3c5281022009-01-28 00:22:46153bool ReadFileToString(const FilePath& path, std::string* contents) {
cpu@chromium.org9fea5a92013-01-09 00:38:59154 if (path.ReferencesParent())
155 return false;
mark@chromium.org836f1342008-10-01 17:40:13156 FILE* file = OpenFile(path, "rb");
157 if (!file) {
initial.commitd7cae122008-07-26 21:49:38158 return false;
mark@chromium.org836f1342008-10-01 17:40:13159 }
initial.commitd7cae122008-07-26 21:49:38160
161 char buf[1 << 16];
162 size_t len;
163 while ((len = fread(buf, 1, sizeof(buf), file)) > 0) {
evan@chromium.org4e074bae2010-05-19 11:07:55164 if (contents)
165 contents->append(buf, len);
initial.commitd7cae122008-07-26 21:49:38166 }
mark@chromium.org836f1342008-10-01 17:40:13167 CloseFile(file);
initial.commitd7cae122008-07-26 21:49:38168
169 return true;
initial.commitd7cae122008-07-26 21:49:38170}
171
tfarina@chromium.orgb33f1d92010-05-26 01:40:12172bool IsDirectoryEmpty(const FilePath& dir_path) {
173 FileEnumerator files(dir_path, false,
haruki@chromium.org84c3f162012-08-12 01:57:23174 FileEnumerator::FILES | FileEnumerator::DIRECTORIES);
brettw@chromium.org25a4c1c2013-06-08 04:53:36175 if (files.Next().empty())
tfarina@chromium.orgb33f1d92010-05-26 01:40:12176 return true;
177 return false;
178}
179
phajdan.jr@chromium.org6faa0e0d2009-04-28 06:50:36180FILE* CreateAndOpenTemporaryFile(FilePath* path) {
181 FilePath directory;
182 if (!GetTempDir(&directory))
evan@chromium.org628476aa2010-06-10 22:56:23183 return NULL;
phajdan.jr@chromium.org6faa0e0d2009-04-28 06:50:36184
185 return CreateAndOpenTemporaryFileInDir(directory, path);
186}
187
dgrogan@chromium.orgcfd23d22013-06-11 03:50:25188bool CreateDirectory(const base::FilePath& full_path) {
189 return CreateDirectoryAndGetError(full_path, NULL);
190}
191
dkegel@google.comeac0709a2008-11-04 21:00:46192bool GetFileSize(const FilePath& file_path, int64* file_size) {
dumi@chromium.org2f0193c22010-09-03 02:28:37193 base::PlatformFileInfo info;
darin@google.comf5e3da4d2008-09-26 01:04:08194 if (!GetFileInfo(file_path, &info))
195 return false;
196 *file_size = info.size;
197 return true;
198}
199
dumi@chromium.org507fb9a2010-09-23 23:28:22200bool TouchFile(const FilePath& path,
201 const base::Time& last_accessed,
202 const base::Time& last_modified) {
nhiroki@chromium.org307a825a2012-11-01 11:48:52203 int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE_ATTRIBUTES;
204
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
210
211 const base::PlatformFile file =
212 base::CreatePlatformFile(path, flags, NULL, NULL);
dumi@chromium.org507fb9a2010-09-23 23:28:22213 if (file != base::kInvalidPlatformFileValue) {
214 bool result = base::TouchPlatformFile(file, last_accessed, last_modified);
215 base::ClosePlatformFile(file);
216 return result;
217 }
218
219 return false;
220}
221
222bool SetLastModifiedTime(const FilePath& path,
223 const base::Time& last_modified) {
224 return TouchFile(path, last_modified, last_modified);
225}
226
mark@chromium.org836f1342008-10-01 17:40:13227bool CloseFile(FILE* file) {
sidchat@google.coma1a19502008-10-21 17:14:45228 if (file == NULL)
229 return true;
mark@chromium.org836f1342008-10-01 17:40:13230 return fclose(file) == 0;
jeremy@chromium.org6e01dae2009-01-27 17:13:02231}
232
jeremy@chromium.orgc2c998c2009-01-27 19:08:39233bool 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;
249}
250
jam@chromium.orge285afa2012-01-31 23:16:39251int 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;
258 }
259
260 FilePath new_path;
261 for (int count = 1; count <= kMaxUniqueFiles; ++count) {
groby@chromium.org7d3cbc92013-03-18 22:33:04262 new_path =
263 path.InsertBeforeExtensionASCII(base::StringPrintf(" (%d)", count));
jam@chromium.orge285afa2012-01-31 23:16:39264 if (!PathExists(new_path) &&
265 (!have_suffix || !PathExists(FilePath(new_path.value() + suffix)))) {
266 return count;
267 }
268 }
269
270 return -1;
aa@chromium.orgee5c29da2009-01-09 22:14:27271}
272
cpu@chromium.orgc2c132c2010-03-24 21:56:26273int64 ComputeDirectorySize(const FilePath& root_path) {
274 int64 running_size = 0;
275 FileEnumerator file_iter(root_path, true, FileEnumerator::FILES);
brettw@chromium.org25a4c1c2013-06-08 04:53:36276 while (!file_iter.Next().empty())
277 running_size += file_iter.GetInfo().GetSize();
cpu@chromium.orgc2c132c2010-03-24 21:56:26278 return running_size;
dbeam@chromium.org9e66a9b2013-05-08 05:46:20279}
280
initial.commitd7cae122008-07-26 21:49:38281} // namespace