[go: nahoru, domu]

blob: 4e1163acd5dc14cb87cef16559cb999be574f822 [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
brettw@chromium.org5553d5b2013-07-01 23:07:3647bool Move(const FilePath& from_path, const FilePath& to_path) {
48 if (from_path.ReferencesParent() || to_path.ReferencesParent())
49 return false;
brettw@chromium.orgf0ff2ad2013-07-09 17:42:2650 return internal::MoveUnsafe(from_path, to_path);
51}
52
53bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
54 if (from_path.ReferencesParent() || to_path.ReferencesParent())
55 return false;
56 return internal::CopyFileUnsafe(from_path, to_path);
brettw@chromium.org5553d5b2013-07-01 23:07:3657}
58
brettw@chromium.org0408c752013-06-22 22:15:4659} // namespace base
60
61// -----------------------------------------------------------------------------
62
initial.commitd7cae122008-07-26 21:49:3863namespace file_util {
64
brettw@chromium.org0408c752013-06-22 22:15:4665using base::FileEnumerator;
66using base::FilePath;
67using base::kExtensionSeparator;
68using base::kMaxUniqueFiles;
cevans@chromium.org3cd2c1c2013-02-06 20:38:0769
evanm@google.com640517f2008-10-30 23:54:0470bool ContentsEqual(const FilePath& filename1, const FilePath& filename2) {
initial.commitd7cae122008-07-26 21:49:3871 // We open the file in binary format even if they are text files because
72 // we are just comparing that bytes are exactly same in both files and not
73 // doing anything smart with text formatting.
evanm@google.com640517f2008-10-30 23:54:0474 std::ifstream file1(filename1.value().c_str(),
erikkay@google.com5af2edb92008-08-08 20:16:0875 std::ios::in | std::ios::binary);
evanm@google.com640517f2008-10-30 23:54:0476 std::ifstream file2(filename2.value().c_str(),
erikkay@google.com5af2edb92008-08-08 20:16:0877 std::ios::in | std::ios::binary);
estade@chromium.orgb9e04f02008-11-27 04:03:5778
initial.commitd7cae122008-07-26 21:49:3879 // Even if both files aren't openable (and thus, in some sense, "equal"),
80 // any unusable file yields a result of "false".
81 if (!file1.is_open() || !file2.is_open())
82 return false;
83
84 const int BUFFER_SIZE = 2056;
85 char buffer1[BUFFER_SIZE], buffer2[BUFFER_SIZE];
86 do {
87 file1.read(buffer1, BUFFER_SIZE);
88 file2.read(buffer2, BUFFER_SIZE);
89
mark@chromium.orgb81637c32009-06-26 21:17:2490 if ((file1.eof() != file2.eof()) ||
initial.commitd7cae122008-07-26 21:49:3891 (file1.gcount() != file2.gcount()) ||
92 (memcmp(buffer1, buffer2, file1.gcount()))) {
93 file1.close();
94 file2.close();
95 return false;
96 }
mark@chromium.orgb81637c32009-06-26 21:17:2497 } while (!file1.eof() || !file2.eof());
initial.commitd7cae122008-07-26 21:49:3898
99 file1.close();
100 file2.close();
101 return true;
102}
103
mark@chromium.orgb81637c32009-06-26 21:17:24104bool TextContentsEqual(const FilePath& filename1, const FilePath& filename2) {
105 std::ifstream file1(filename1.value().c_str(), std::ios::in);
106 std::ifstream file2(filename2.value().c_str(), std::ios::in);
107
108 // Even if both files aren't openable (and thus, in some sense, "equal"),
109 // any unusable file yields a result of "false".
110 if (!file1.is_open() || !file2.is_open())
111 return false;
112
113 do {
114 std::string line1, line2;
115 getline(file1, line1);
116 getline(file2, line2);
117
118 // Check for mismatched EOF states, or any error state.
119 if ((file1.eof() != file2.eof()) ||
120 file1.bad() || file2.bad()) {
121 return false;
122 }
123
124 // Trim all '\r' and '\n' characters from the end of the line.
125 std::string::size_type end1 = line1.find_last_not_of("\r\n");
126 if (end1 == std::string::npos)
127 line1.clear();
128 else if (end1 + 1 < line1.length())
129 line1.erase(end1 + 1);
130
131 std::string::size_type end2 = line2.find_last_not_of("\r\n");
132 if (end2 == std::string::npos)
133 line2.clear();
134 else if (end2 + 1 < line2.length())
135 line2.erase(end2 + 1);
136
137 if (line1 != line2)
138 return false;
139 } while (!file1.eof() || !file2.eof());
140
141 return true;
142}
143
erikkay@google.com3c5281022009-01-28 00:22:46144bool ReadFileToString(const FilePath& path, std::string* contents) {
cpu@chromium.org9fea5a92013-01-09 00:38:59145 if (path.ReferencesParent())
146 return false;
mark@chromium.org836f1342008-10-01 17:40:13147 FILE* file = OpenFile(path, "rb");
148 if (!file) {
initial.commitd7cae122008-07-26 21:49:38149 return false;
mark@chromium.org836f1342008-10-01 17:40:13150 }
initial.commitd7cae122008-07-26 21:49:38151
152 char buf[1 << 16];
153 size_t len;
154 while ((len = fread(buf, 1, sizeof(buf), file)) > 0) {
evan@chromium.org4e074bae2010-05-19 11:07:55155 if (contents)
156 contents->append(buf, len);
initial.commitd7cae122008-07-26 21:49:38157 }
mark@chromium.org836f1342008-10-01 17:40:13158 CloseFile(file);
initial.commitd7cae122008-07-26 21:49:38159
160 return true;
initial.commitd7cae122008-07-26 21:49:38161}
162
tfarina@chromium.orgb33f1d92010-05-26 01:40:12163bool IsDirectoryEmpty(const FilePath& dir_path) {
164 FileEnumerator files(dir_path, false,
haruki@chromium.org84c3f162012-08-12 01:57:23165 FileEnumerator::FILES | FileEnumerator::DIRECTORIES);
brettw@chromium.org25a4c1c2013-06-08 04:53:36166 if (files.Next().empty())
tfarina@chromium.orgb33f1d92010-05-26 01:40:12167 return true;
168 return false;
169}
170
phajdan.jr@chromium.org6faa0e0d2009-04-28 06:50:36171FILE* CreateAndOpenTemporaryFile(FilePath* path) {
172 FilePath directory;
173 if (!GetTempDir(&directory))
evan@chromium.org628476aa2010-06-10 22:56:23174 return NULL;
phajdan.jr@chromium.org6faa0e0d2009-04-28 06:50:36175
176 return CreateAndOpenTemporaryFileInDir(directory, path);
177}
178
dgrogan@chromium.orgcfd23d22013-06-11 03:50:25179bool CreateDirectory(const base::FilePath& full_path) {
180 return CreateDirectoryAndGetError(full_path, NULL);
181}
182
dkegel@google.comeac0709a2008-11-04 21:00:46183bool GetFileSize(const FilePath& file_path, int64* file_size) {
dumi@chromium.org2f0193c22010-09-03 02:28:37184 base::PlatformFileInfo info;
darin@google.comf5e3da4d2008-09-26 01:04:08185 if (!GetFileInfo(file_path, &info))
186 return false;
187 *file_size = info.size;
188 return true;
189}
190
dumi@chromium.org507fb9a2010-09-23 23:28:22191bool TouchFile(const FilePath& path,
192 const base::Time& last_accessed,
193 const base::Time& last_modified) {
nhiroki@chromium.org307a825a2012-11-01 11:48:52194 int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE_ATTRIBUTES;
195
196#if defined(OS_WIN)
197 // On Windows, FILE_FLAG_BACKUP_SEMANTICS is needed to open a directory.
198 if (DirectoryExists(path))
199 flags |= base::PLATFORM_FILE_BACKUP_SEMANTICS;
200#endif // OS_WIN
201
202 const base::PlatformFile file =
203 base::CreatePlatformFile(path, flags, NULL, NULL);
dumi@chromium.org507fb9a2010-09-23 23:28:22204 if (file != base::kInvalidPlatformFileValue) {
205 bool result = base::TouchPlatformFile(file, last_accessed, last_modified);
206 base::ClosePlatformFile(file);
207 return result;
208 }
209
210 return false;
211}
212
213bool SetLastModifiedTime(const FilePath& path,
214 const base::Time& last_modified) {
215 return TouchFile(path, last_modified, last_modified);
216}
217
mark@chromium.org836f1342008-10-01 17:40:13218bool CloseFile(FILE* file) {
sidchat@google.coma1a19502008-10-21 17:14:45219 if (file == NULL)
220 return true;
mark@chromium.org836f1342008-10-01 17:40:13221 return fclose(file) == 0;
jeremy@chromium.org6e01dae2009-01-27 17:13:02222}
223
jeremy@chromium.orgc2c998c2009-01-27 19:08:39224bool TruncateFile(FILE* file) {
225 if (file == NULL)
226 return false;
227 long current_offset = ftell(file);
228 if (current_offset == -1)
229 return false;
230#if defined(OS_WIN)
231 int fd = _fileno(file);
232 if (_chsize(fd, current_offset) != 0)
233 return false;
234#else
235 int fd = fileno(file);
236 if (ftruncate(fd, current_offset) != 0)
237 return false;
238#endif
239 return true;
240}
241
jam@chromium.orge285afa2012-01-31 23:16:39242int GetUniquePathNumber(
243 const FilePath& path,
244 const FilePath::StringType& suffix) {
245 bool have_suffix = !suffix.empty();
246 if (!PathExists(path) &&
247 (!have_suffix || !PathExists(FilePath(path.value() + suffix)))) {
248 return 0;
249 }
250
251 FilePath new_path;
252 for (int count = 1; count <= kMaxUniqueFiles; ++count) {
groby@chromium.org7d3cbc92013-03-18 22:33:04253 new_path =
254 path.InsertBeforeExtensionASCII(base::StringPrintf(" (%d)", count));
jam@chromium.orge285afa2012-01-31 23:16:39255 if (!PathExists(new_path) &&
256 (!have_suffix || !PathExists(FilePath(new_path.value() + suffix)))) {
257 return count;
258 }
259 }
260
261 return -1;
aa@chromium.orgee5c29da2009-01-09 22:14:27262}
263
brettw@chromium.org0408c752013-06-22 22:15:46264} // namespace file_util