[go: nahoru, domu]

blob: 846dec75532ea03b436dfc01a294211396e72483 [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
brettw@chromium.orge3177dd52014-08-13 20:22:145#include "base/files/file_util.h"
initial.commitd7cae122008-07-26 21:49:386
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>
kaliamoorthi@chromium.org0710fdd2014-02-18 16:31:5113#include <limits>
Victor Costanb5a0a97002019-09-08 04:55:1514#include <memory>
initial.commitd7cae122008-07-26 21:49:3815
brettw@chromium.org25a4c1c2013-06-08 04:53:3616#include "base/files/file_enumerator.h"
brettw@chromium.org57999812013-02-24 05:40:5217#include "base/files/file_path.h"
initial.commitd7cae122008-07-26 21:49:3818#include "base/logging.h"
tfarina@chromium.orgeb62f7262013-03-30 14:29:0019#include "base/strings/string_piece.h"
avi@chromium.org251cd6e52013-06-11 13:36:3720#include "base/strings/string_util.h"
21#include "base/strings/stringprintf.h"
avi@chromium.orga4ea1f12013-06-07 18:37:0722#include "base/strings/utf_string_conversions.h"
Etienne Pierre-Doray1da58592018-09-21 14:47:2023#include "base/threading/scoped_blocking_call.h"
avi543540e2015-12-24 05:15:3224#include "build/build_config.h"
estade@chromium.orgb9e04f02008-11-27 04:03:5725
brettw@chromium.org0408c752013-06-22 22:15:4626namespace base {
brettw@chromium.org04af979a2013-02-16 04:12:2627
hidehiko8fc7c822015-06-09 02:50:5728#if !defined(OS_NACL_NONSFI)
avi543540e2015-12-24 05:15:3229int64_t ComputeDirectorySize(const FilePath& root_path) {
30 int64_t running_size = 0;
brettw@chromium.org0408c752013-06-22 22:15:4631 FileEnumerator file_iter(root_path, true, FileEnumerator::FILES);
32 while (!file_iter.Next().empty())
33 running_size += file_iter.GetInfo().GetSize();
34 return running_size;
35}
36
brettw@chromium.org5553d5b2013-07-01 23:07:3637bool Move(const FilePath& from_path, const FilePath& to_path) {
38 if (from_path.ReferencesParent() || to_path.ReferencesParent())
39 return false;
brettw@chromium.orgf0ff2ad2013-07-09 17:42:2640 return internal::MoveUnsafe(from_path, to_path);
41}
42
evanm@google.com640517f2008-10-30 23:54:0443bool ContentsEqual(const FilePath& filename1, const FilePath& filename2) {
initial.commitd7cae122008-07-26 21:49:3844 // We open the file in binary format even if they are text files because
45 // we are just comparing that bytes are exactly same in both files and not
46 // doing anything smart with text formatting.
jdoerrie983968a2019-01-29 12:54:4147#if defined(OS_WIN)
jdoerriebacc1962019-02-07 13:39:2248 std::ifstream file1(as_wcstr(filename1.value()),
erikkay@google.com5af2edb92008-08-08 20:16:0849 std::ios::in | std::ios::binary);
jdoerriebacc1962019-02-07 13:39:2250 std::ifstream file2(as_wcstr(filename2.value()),
erikkay@google.com5af2edb92008-08-08 20:16:0851 std::ios::in | std::ios::binary);
jdoerrie983968a2019-01-29 12:54:4152#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
53 std::ifstream file1(filename1.value(), std::ios::in | std::ios::binary);
54 std::ifstream file2(filename2.value(), std::ios::in | std::ios::binary);
55#endif // OS_WIN
estade@chromium.orgb9e04f02008-11-27 04:03:5756
initial.commitd7cae122008-07-26 21:49:3857 // Even if both files aren't openable (and thus, in some sense, "equal"),
58 // any unusable file yields a result of "false".
59 if (!file1.is_open() || !file2.is_open())
60 return false;
61
62 const int BUFFER_SIZE = 2056;
63 char buffer1[BUFFER_SIZE], buffer2[BUFFER_SIZE];
64 do {
65 file1.read(buffer1, BUFFER_SIZE);
66 file2.read(buffer2, BUFFER_SIZE);
67
mark@chromium.orgb81637c32009-06-26 21:17:2468 if ((file1.eof() != file2.eof()) ||
initial.commitd7cae122008-07-26 21:49:3869 (file1.gcount() != file2.gcount()) ||
pkasting9cf9b942014-10-01 22:18:4370 (memcmp(buffer1, buffer2, static_cast<size_t>(file1.gcount())))) {
initial.commitd7cae122008-07-26 21:49:3871 file1.close();
72 file2.close();
73 return false;
74 }
mark@chromium.orgb81637c32009-06-26 21:17:2475 } while (!file1.eof() || !file2.eof());
initial.commitd7cae122008-07-26 21:49:3876
77 file1.close();
78 file2.close();
79 return true;
80}
81
mark@chromium.orgb81637c32009-06-26 21:17:2482bool TextContentsEqual(const FilePath& filename1, const FilePath& filename2) {
jdoerrie983968a2019-01-29 12:54:4183#if defined(OS_WIN)
jdoerriebacc1962019-02-07 13:39:2284 std::ifstream file1(as_wcstr(filename1.value()), std::ios::in);
85 std::ifstream file2(as_wcstr(filename2.value()), std::ios::in);
jdoerrie983968a2019-01-29 12:54:4186#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
87 std::ifstream file1(filename1.value(), std::ios::in);
88 std::ifstream file2(filename2.value(), std::ios::in);
89#endif // OS_WIN
mark@chromium.orgb81637c32009-06-26 21:17:2490
91 // Even if both files aren't openable (and thus, in some sense, "equal"),
92 // any unusable file yields a result of "false".
93 if (!file1.is_open() || !file2.is_open())
94 return false;
95
96 do {
97 std::string line1, line2;
98 getline(file1, line1);
99 getline(file2, line2);
100
101 // Check for mismatched EOF states, or any error state.
102 if ((file1.eof() != file2.eof()) ||
103 file1.bad() || file2.bad()) {
104 return false;
105 }
106
107 // Trim all '\r' and '\n' characters from the end of the line.
108 std::string::size_type end1 = line1.find_last_not_of("\r\n");
109 if (end1 == std::string::npos)
110 line1.clear();
111 else if (end1 + 1 < line1.length())
112 line1.erase(end1 + 1);
113
114 std::string::size_type end2 = line2.find_last_not_of("\r\n");
115 if (end2 == std::string::npos)
116 line2.clear();
117 else if (end2 + 1 < line2.length())
118 line2.erase(end2 + 1);
119
120 if (line1 != line2)
121 return false;
122 } while (!file1.eof() || !file2.eof());
123
124 return true;
125}
hidehiko8fc7c822015-06-09 02:50:57126#endif // !defined(OS_NACL_NONSFI)
mark@chromium.orgb81637c32009-06-26 21:17:24127
hashimoto6da2fef2016-02-24 03:39:58128bool ReadFileToStringWithMaxSize(const FilePath& path,
129 std::string* contents,
130 size_t max_size) {
kaliamoorthi@chromium.org0710fdd2014-02-18 16:31:51131 if (contents)
132 contents->clear();
cpu@chromium.org9fea5a92013-01-09 00:38:59133 if (path.ReferencesParent())
134 return false;
thakis@chromium.org7600d0b2013-12-08 21:43:30135 FILE* file = OpenFile(path, "rb");
mark@chromium.org836f1342008-10-01 17:40:13136 if (!file) {
initial.commitd7cae122008-07-26 21:49:38137 return false;
mark@chromium.org836f1342008-10-01 17:40:13138 }
initial.commitd7cae122008-07-26 21:49:38139
kaliamoorthi@chromium.org0710fdd2014-02-18 16:31:51140 // Many files supplied in |path| have incorrect size (proc files etc).
Mikhail Istomin1ede1552018-05-16 17:40:24141 // Hence, the file is read sequentially as opposed to a one-shot read, using
142 // file size as a hint for chunk size if available.
143 constexpr int64_t kDefaultChunkSize = 1 << 16;
144 int64_t chunk_size;
145#if !defined(OS_NACL_NONSFI)
146 if (!GetFileSize(path, &chunk_size) || chunk_size <= 0)
147 chunk_size = kDefaultChunkSize - 1;
148 // We need to attempt to read at EOF for feof flag to be set so here we
149 // use |chunk_size| + 1.
150 chunk_size = std::min<uint64_t>(chunk_size, max_size) + 1;
151#else
152 chunk_size = kDefaultChunkSize;
153#endif // !defined(OS_NACL_NONSFI)
154 size_t bytes_read_this_pass;
155 size_t bytes_read_so_far = 0;
156 bool read_status = true;
157 std::string local_contents;
158 local_contents.resize(chunk_size);
kaliamoorthi@chromium.org0710fdd2014-02-18 16:31:51159
Etienne Bergeron436d42212019-02-26 17:15:12160 ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
Mikhail Istomin1ede1552018-05-16 17:40:24161 while ((bytes_read_this_pass = fread(&local_contents[bytes_read_so_far], 1,
162 chunk_size, file)) > 0) {
163 if ((max_size - bytes_read_so_far) < bytes_read_this_pass) {
164 // Read more than max_size bytes, bail out.
165 bytes_read_so_far = max_size;
kaliamoorthi@chromium.org0710fdd2014-02-18 16:31:51166 read_status = false;
167 break;
168 }
Mikhail Istomin1ede1552018-05-16 17:40:24169 // In case EOF was not reached, iterate again but revert to the default
170 // chunk size.
171 if (bytes_read_so_far == 0)
172 chunk_size = kDefaultChunkSize;
kaliamoorthi@chromium.org0710fdd2014-02-18 16:31:51173
Mikhail Istomin1ede1552018-05-16 17:40:24174 bytes_read_so_far += bytes_read_this_pass;
175 // Last fread syscall (after EOF) can be avoided via feof, which is just a
176 // flag check.
177 if (feof(file))
178 break;
179 local_contents.resize(bytes_read_so_far + chunk_size);
initial.commitd7cae122008-07-26 21:49:38180 }
tnagel@chromium.org731daa12014-05-01 10:40:51181 read_status = read_status && !ferror(file);
thakis@chromium.org7600d0b2013-12-08 21:43:30182 CloseFile(file);
Mikhail Istomin1ede1552018-05-16 17:40:24183 if (contents) {
184 contents->swap(local_contents);
185 contents->resize(bytes_read_so_far);
186 }
initial.commitd7cae122008-07-26 21:49:38187
kaliamoorthi@chromium.org0710fdd2014-02-18 16:31:51188 return read_status;
189}
190
191bool ReadFileToString(const FilePath& path, std::string* contents) {
hashimoto6da2fef2016-02-24 03:39:58192 return ReadFileToStringWithMaxSize(path, contents,
193 std::numeric_limits<size_t>::max());
initial.commitd7cae122008-07-26 21:49:38194}
195
hidehiko8fc7c822015-06-09 02:50:57196#if !defined(OS_NACL_NONSFI)
brettw@chromium.orgfb4bcfa32013-12-02 18:55:49197bool IsDirectoryEmpty(const FilePath& dir_path) {
198 FileEnumerator files(dir_path, false,
199 FileEnumerator::FILES | FileEnumerator::DIRECTORIES);
200 if (files.Next().empty())
201 return true;
202 return false;
203}
204
brettw@chromium.org03d9afc02013-12-03 17:55:52205FILE* CreateAndOpenTemporaryFile(FilePath* path) {
206 FilePath directory;
207 if (!GetTempDir(&directory))
Ivan Kotenkova16212a52017-11-08 12:37:33208 return nullptr;
brettw@chromium.org03d9afc02013-12-03 17:55:52209
210 return CreateAndOpenTemporaryFileInDir(directory, path);
211}
212
brettw@chromium.org426d1c92013-12-03 20:08:54213bool CreateDirectory(const FilePath& full_path) {
Ivan Kotenkova16212a52017-11-08 12:37:33214 return CreateDirectoryAndGetError(full_path, nullptr);
brettw@chromium.org426d1c92013-12-03 20:08:54215}
216
avi543540e2015-12-24 05:15:32217bool GetFileSize(const FilePath& file_path, int64_t* file_size) {
rvargas@chromium.org54124ed02014-01-07 10:06:58218 File::Info info;
brettw@chromium.org9eae4e62013-12-04 20:56:49219 if (!GetFileInfo(file_path, &info))
brettw@chromium.org56285702013-12-04 18:22:49220 return false;
221 *file_size = info.size;
222 return true;
223}
224
brettw@chromium.orgc0d508162013-12-04 22:49:00225bool TouchFile(const FilePath& path,
226 const Time& last_accessed,
227 const Time& last_modified) {
rvargas@chromium.org54124ed02014-01-07 10:06:58228 int flags = File::FLAG_OPEN | File::FLAG_WRITE_ATTRIBUTES;
brettw@chromium.orgc0d508162013-12-04 22:49:00229
230#if defined(OS_WIN)
231 // On Windows, FILE_FLAG_BACKUP_SEMANTICS is needed to open a directory.
232 if (DirectoryExists(path))
rvargas@chromium.org54124ed02014-01-07 10:06:58233 flags |= File::FLAG_BACKUP_SEMANTICS;
Wez432ea8d892019-03-31 01:17:08234#elif defined(OS_FUCHSIA)
235 // On Fuchsia, we need O_RDONLY for directories, or O_WRONLY for files.
236 // TODO(https://crbug.com/947802): Find a cleaner workaround for this.
237 flags |= (DirectoryExists(path) ? File::FLAG_READ : File::FLAG_WRITE);
238#endif
brettw@chromium.orgc0d508162013-12-04 22:49:00239
rvargas@chromium.org54124ed02014-01-07 10:06:58240 File file(path, flags);
241 if (!file.IsValid())
242 return false;
brettw@chromium.orgc0d508162013-12-04 22:49:00243
rvargas@chromium.org54124ed02014-01-07 10:06:58244 return file.SetTimes(last_accessed, last_modified);
brettw@chromium.orgc0d508162013-12-04 22:49:00245}
hidehiko8fc7c822015-06-09 02:50:57246#endif // !defined(OS_NACL_NONSFI)
brettw@chromium.orgc0d508162013-12-04 22:49:00247
mark@chromium.org836f1342008-10-01 17:40:13248bool CloseFile(FILE* file) {
Ivan Kotenkova16212a52017-11-08 12:37:33249 if (file == nullptr)
sidchat@google.coma1a19502008-10-21 17:14:45250 return true;
mark@chromium.org836f1342008-10-01 17:40:13251 return fclose(file) == 0;
252}
253
hidehiko8fc7c822015-06-09 02:50:57254#if !defined(OS_NACL_NONSFI)
jeremy@chromium.orgc2c998c2009-01-27 19:08:39255bool TruncateFile(FILE* file) {
Ivan Kotenkova16212a52017-11-08 12:37:33256 if (file == nullptr)
jeremy@chromium.orgc2c998c2009-01-27 19:08:39257 return false;
258 long current_offset = ftell(file);
259 if (current_offset == -1)
260 return false;
261#if defined(OS_WIN)
262 int fd = _fileno(file);
263 if (_chsize(fd, current_offset) != 0)
264 return false;
265#else
266 int fd = fileno(file);
267 if (ftruncate(fd, current_offset) != 0)
268 return false;
269#endif
270 return true;
271}
272
Greg Thompsonb4abcb42019-08-23 01:42:56273int GetUniquePathNumber(const FilePath& path) {
274 DCHECK(!path.empty());
275 if (!PathExists(path))
Greg Thompson42373544a2019-08-14 10:11:10276 return 0;
277
278 std::string number;
279 for (int count = 1; count <= kMaxUniqueFiles; ++count) {
280 StringAppendF(&number, " (%d)", count);
Greg Thompsonb4abcb42019-08-23 01:42:56281 if (!PathExists(path.InsertBeforeExtensionASCII(number)))
Greg Thompson42373544a2019-08-14 10:11:10282 return count;
283 number.clear();
jam@chromium.orge285afa2012-01-31 23:16:39284 }
285
286 return -1;
287}
Bruce Longd096e482019-02-28 17:50:00288
289FilePath GetUniquePath(const FilePath& path) {
Greg Thompsonb4abcb42019-08-23 01:42:56290 DCHECK(!path.empty());
291 const int uniquifier = GetUniquePathNumber(path);
292 if (uniquifier > 0)
293 return path.InsertBeforeExtensionASCII(StringPrintf(" (%d)", uniquifier));
294 return uniquifier == 0 ? path : base::FilePath();
Bruce Longd096e482019-02-28 17:50:00295}
Victor Costanb5a0a97002019-09-08 04:55:15296
297namespace internal {
298
299bool PreReadFileSlow(const FilePath& file_path, int64_t max_bytes) {
300 DCHECK_GE(max_bytes, 0);
301
302 File file(file_path, File::FLAG_OPEN | File::FLAG_READ |
303 File::FLAG_SEQUENTIAL_SCAN |
304 File::FLAG_SHARE_DELETE);
305 if (!file.IsValid())
306 return false;
307
308 constexpr int kBufferSize = 1024 * 1024;
309 // Ensures the buffer is deallocated at function exit.
310 std::unique_ptr<char[]> buffer_deleter(new char[kBufferSize]);
311 char* const buffer = buffer_deleter.get();
312
313 while (max_bytes > 0) {
314 // The static_cast<int> is safe because kBufferSize is int, and both values
315 // are non-negative. So, the minimum is guaranteed to fit in int.
316 const int read_size =
317 static_cast<int>(std::min<int64_t>(max_bytes, kBufferSize));
318 DCHECK_GE(read_size, 0);
319 DCHECK_LE(read_size, kBufferSize);
320
321 const int read_bytes = file.ReadAtCurrentPos(buffer, read_size);
322 if (read_bytes < 0)
323 return false;
324 if (read_bytes == 0)
325 break;
326
327 max_bytes -= read_bytes;
328 }
329
330 return true;
331}
332
333} // namespace internal
334
hidehiko8fc7c822015-06-09 02:50:57335#endif // !defined(OS_NACL_NONSFI)
jam@chromium.orge285afa2012-01-31 23:16:39336
brettw@chromium.orga26f4ae2014-03-13 17:26:21337} // namespace base