[go: nahoru, domu]

blob: 41ee7ad8bcb60ce2d34729ec1cb623642470b320 [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
Hans Wennborgc3cffa62020-04-27 10:09:1216#include "base/check_op.h"
brettw@chromium.org25a4c1c2013-06-08 04:53:3617#include "base/files/file_enumerator.h"
brettw@chromium.org57999812013-02-24 05:40:5218#include "base/files/file_path.h"
Greg Thompson3f7e20f42020-05-02 19:01:1119#include "base/posix/eintr_wrapper.h"
tfarina@chromium.orgeb62f7262013-03-30 14:29:0020#include "base/strings/string_piece.h"
avi@chromium.org251cd6e52013-06-11 13:36:3721#include "base/strings/string_util.h"
22#include "base/strings/stringprintf.h"
avi@chromium.orga4ea1f12013-06-07 18:37:0723#include "base/strings/utf_string_conversions.h"
Etienne Pierre-Doray1da58592018-09-21 14:47:2024#include "base/threading/scoped_blocking_call.h"
avi543540e2015-12-24 05:15:3225#include "build/build_config.h"
estade@chromium.orgb9e04f02008-11-27 04:03:5726
brettw@chromium.org0408c752013-06-22 22:15:4627namespace base {
brettw@chromium.org04af979a2013-02-16 04:12:2628
hidehiko8fc7c822015-06-09 02:50:5729#if !defined(OS_NACL_NONSFI)
Lei Zhange3aa0b9a2020-06-11 08:59:2330namespace {
31
32void DeleteFileHelper(const FilePath& path) {
33 DeleteFile(path, /*recursive=*/false);
34}
35
36} // namespace
37
38OnceCallback<void(const FilePath&)> GetDeleteFileCallback() {
39 return BindOnce(&DeleteFileHelper);
40}
41
avi543540e2015-12-24 05:15:3242int64_t ComputeDirectorySize(const FilePath& root_path) {
43 int64_t running_size = 0;
brettw@chromium.org0408c752013-06-22 22:15:4644 FileEnumerator file_iter(root_path, true, FileEnumerator::FILES);
45 while (!file_iter.Next().empty())
46 running_size += file_iter.GetInfo().GetSize();
47 return running_size;
48}
49
brettw@chromium.org5553d5b2013-07-01 23:07:3650bool Move(const FilePath& from_path, const FilePath& to_path) {
51 if (from_path.ReferencesParent() || to_path.ReferencesParent())
52 return false;
brettw@chromium.orgf0ff2ad2013-07-09 17:42:2653 return internal::MoveUnsafe(from_path, to_path);
54}
55
evanm@google.com640517f2008-10-30 23:54:0456bool ContentsEqual(const FilePath& filename1, const FilePath& filename2) {
initial.commitd7cae122008-07-26 21:49:3857 // We open the file in binary format even if they are text files because
58 // we are just comparing that bytes are exactly same in both files and not
59 // doing anything smart with text formatting.
jdoerrie983968a2019-01-29 12:54:4160#if defined(OS_WIN)
Jan Wilken Dörrie9bb441d2019-11-01 17:48:4061 std::ifstream file1(filename1.value().c_str(),
erikkay@google.com5af2edb92008-08-08 20:16:0862 std::ios::in | std::ios::binary);
Jan Wilken Dörrie9bb441d2019-11-01 17:48:4063 std::ifstream file2(filename2.value().c_str(),
erikkay@google.com5af2edb92008-08-08 20:16:0864 std::ios::in | std::ios::binary);
jdoerrie983968a2019-01-29 12:54:4165#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
66 std::ifstream file1(filename1.value(), std::ios::in | std::ios::binary);
67 std::ifstream file2(filename2.value(), std::ios::in | std::ios::binary);
68#endif // OS_WIN
estade@chromium.orgb9e04f02008-11-27 04:03:5769
initial.commitd7cae122008-07-26 21:49:3870 // Even if both files aren't openable (and thus, in some sense, "equal"),
71 // any unusable file yields a result of "false".
72 if (!file1.is_open() || !file2.is_open())
73 return false;
74
75 const int BUFFER_SIZE = 2056;
76 char buffer1[BUFFER_SIZE], buffer2[BUFFER_SIZE];
77 do {
78 file1.read(buffer1, BUFFER_SIZE);
79 file2.read(buffer2, BUFFER_SIZE);
80
mark@chromium.orgb81637c32009-06-26 21:17:2481 if ((file1.eof() != file2.eof()) ||
initial.commitd7cae122008-07-26 21:49:3882 (file1.gcount() != file2.gcount()) ||
pkasting9cf9b942014-10-01 22:18:4383 (memcmp(buffer1, buffer2, static_cast<size_t>(file1.gcount())))) {
initial.commitd7cae122008-07-26 21:49:3884 file1.close();
85 file2.close();
86 return false;
87 }
mark@chromium.orgb81637c32009-06-26 21:17:2488 } while (!file1.eof() || !file2.eof());
initial.commitd7cae122008-07-26 21:49:3889
90 file1.close();
91 file2.close();
92 return true;
93}
94
mark@chromium.orgb81637c32009-06-26 21:17:2495bool TextContentsEqual(const FilePath& filename1, const FilePath& filename2) {
jdoerrie983968a2019-01-29 12:54:4196#if defined(OS_WIN)
Jan Wilken Dörrie9bb441d2019-11-01 17:48:4097 std::ifstream file1(filename1.value().c_str(), std::ios::in);
98 std::ifstream file2(filename2.value().c_str(), std::ios::in);
jdoerrie983968a2019-01-29 12:54:4199#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
100 std::ifstream file1(filename1.value(), std::ios::in);
101 std::ifstream file2(filename2.value(), std::ios::in);
102#endif // OS_WIN
mark@chromium.orgb81637c32009-06-26 21:17:24103
104 // 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 do {
110 std::string line1, line2;
111 getline(file1, line1);
112 getline(file2, line2);
113
114 // Check for mismatched EOF states, or any error state.
115 if ((file1.eof() != file2.eof()) ||
116 file1.bad() || file2.bad()) {
117 return false;
118 }
119
120 // Trim all '\r' and '\n' characters from the end of the line.
121 std::string::size_type end1 = line1.find_last_not_of("\r\n");
122 if (end1 == std::string::npos)
123 line1.clear();
124 else if (end1 + 1 < line1.length())
125 line1.erase(end1 + 1);
126
127 std::string::size_type end2 = line2.find_last_not_of("\r\n");
128 if (end2 == std::string::npos)
129 line2.clear();
130 else if (end2 + 1 < line2.length())
131 line2.erase(end2 + 1);
132
133 if (line1 != line2)
134 return false;
135 } while (!file1.eof() || !file2.eof());
136
137 return true;
138}
hidehiko8fc7c822015-06-09 02:50:57139#endif // !defined(OS_NACL_NONSFI)
mark@chromium.orgb81637c32009-06-26 21:17:24140
Greg Thompson3f7e20f42020-05-02 19:01:11141bool ReadStreamToString(FILE* stream, std::string* contents) {
142 return ReadStreamToStringWithMaxSize(
143 stream, std::numeric_limits<size_t>::max(), contents);
144}
145
146bool ReadStreamToStringWithMaxSize(FILE* stream,
147 size_t max_size,
148 std::string* contents) {
kaliamoorthi@chromium.org0710fdd2014-02-18 16:31:51149 if (contents)
150 contents->clear();
initial.commitd7cae122008-07-26 21:49:38151
Greg Thompson3f7e20f42020-05-02 19:01:11152 // Seeking to the beginning is best-effort -- it is expected to fail for
153 // certain non-file stream (e.g., pipes).
154 HANDLE_EINTR(fseek(stream, 0, SEEK_SET));
155
156 // Many files have incorrect size (proc files etc). Hence, the file is read
157 // sequentially as opposed to a one-shot read, using file size as a hint for
158 // chunk size if available.
Mikhail Istomin1ede1552018-05-16 17:40:24159 constexpr int64_t kDefaultChunkSize = 1 << 16;
Greg Thompson3f7e20f42020-05-02 19:01:11160 int64_t chunk_size = kDefaultChunkSize - 1;
Mikhail Istomin1ede1552018-05-16 17:40:24161#if !defined(OS_NACL_NONSFI)
Greg Thompson3f7e20f42020-05-02 19:01:11162 ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
163#if defined(OS_WIN)
164 BY_HANDLE_FILE_INFORMATION file_info = {};
165 if (::GetFileInformationByHandle(
166 reinterpret_cast<HANDLE>(_get_osfhandle(_fileno(stream))),
167 &file_info)) {
168 LARGE_INTEGER size;
169 size.HighPart = file_info.nFileSizeHigh;
170 size.LowPart = file_info.nFileSizeLow;
171 if (size.QuadPart > 0)
172 chunk_size = size.QuadPart;
173 }
174#else // defined(OS_WIN)
175 stat_wrapper_t file_info = {};
176 if (!File::Fstat(fileno(stream), &file_info) && file_info.st_size > 0)
177 chunk_size = file_info.st_size;
178#endif // defined(OS_WIN)
Mikhail Istomin1ede1552018-05-16 17:40:24179 // We need to attempt to read at EOF for feof flag to be set so here we
180 // use |chunk_size| + 1.
181 chunk_size = std::min<uint64_t>(chunk_size, max_size) + 1;
Greg Thompson3f7e20f42020-05-02 19:01:11182#else // !defined(OS_NACL_NONSFI)
Mikhail Istomin1ede1552018-05-16 17:40:24183 chunk_size = kDefaultChunkSize;
184#endif // !defined(OS_NACL_NONSFI)
185 size_t bytes_read_this_pass;
186 size_t bytes_read_so_far = 0;
187 bool read_status = true;
188 std::string local_contents;
189 local_contents.resize(chunk_size);
kaliamoorthi@chromium.org0710fdd2014-02-18 16:31:51190
Mikhail Istomin1ede1552018-05-16 17:40:24191 while ((bytes_read_this_pass = fread(&local_contents[bytes_read_so_far], 1,
Greg Thompson3f7e20f42020-05-02 19:01:11192 chunk_size, stream)) > 0) {
Mikhail Istomin1ede1552018-05-16 17:40:24193 if ((max_size - bytes_read_so_far) < bytes_read_this_pass) {
194 // Read more than max_size bytes, bail out.
195 bytes_read_so_far = max_size;
kaliamoorthi@chromium.org0710fdd2014-02-18 16:31:51196 read_status = false;
197 break;
198 }
Mikhail Istomin1ede1552018-05-16 17:40:24199 // In case EOF was not reached, iterate again but revert to the default
200 // chunk size.
201 if (bytes_read_so_far == 0)
202 chunk_size = kDefaultChunkSize;
kaliamoorthi@chromium.org0710fdd2014-02-18 16:31:51203
Mikhail Istomin1ede1552018-05-16 17:40:24204 bytes_read_so_far += bytes_read_this_pass;
205 // Last fread syscall (after EOF) can be avoided via feof, which is just a
206 // flag check.
Greg Thompson3f7e20f42020-05-02 19:01:11207 if (feof(stream))
Mikhail Istomin1ede1552018-05-16 17:40:24208 break;
209 local_contents.resize(bytes_read_so_far + chunk_size);
initial.commitd7cae122008-07-26 21:49:38210 }
Greg Thompson3f7e20f42020-05-02 19:01:11211 read_status = read_status && !ferror(stream);
Mikhail Istomin1ede1552018-05-16 17:40:24212 if (contents) {
213 contents->swap(local_contents);
214 contents->resize(bytes_read_so_far);
215 }
initial.commitd7cae122008-07-26 21:49:38216
kaliamoorthi@chromium.org0710fdd2014-02-18 16:31:51217 return read_status;
218}
219
220bool ReadFileToString(const FilePath& path, std::string* contents) {
hashimoto6da2fef2016-02-24 03:39:58221 return ReadFileToStringWithMaxSize(path, contents,
222 std::numeric_limits<size_t>::max());
initial.commitd7cae122008-07-26 21:49:38223}
224
Greg Thompson3f7e20f42020-05-02 19:01:11225bool ReadFileToStringWithMaxSize(const FilePath& path,
226 std::string* contents,
227 size_t max_size) {
228 if (contents)
229 contents->clear();
230 if (path.ReferencesParent())
231 return false;
232 ScopedFILE file_stream(OpenFile(path, "rb"));
233 if (!file_stream)
234 return false;
235 return ReadStreamToStringWithMaxSize(file_stream.get(), max_size, contents);
236}
237
hidehiko8fc7c822015-06-09 02:50:57238#if !defined(OS_NACL_NONSFI)
brettw@chromium.orgfb4bcfa32013-12-02 18:55:49239bool IsDirectoryEmpty(const FilePath& dir_path) {
240 FileEnumerator files(dir_path, false,
241 FileEnumerator::FILES | FileEnumerator::DIRECTORIES);
242 if (files.Next().empty())
243 return true;
244 return false;
245}
246
Greg Thompson3f7e20f42020-05-02 19:01:11247bool CreateTemporaryFile(FilePath* path) {
248 FilePath temp_dir;
249 return GetTempDir(&temp_dir) && CreateTemporaryFileInDir(temp_dir, path);
250}
251
Greg Thompsonf75f5fb2020-04-30 08:13:25252ScopedFILE CreateAndOpenTemporaryStream(FilePath* path) {
brettw@chromium.org03d9afc02013-12-03 17:55:52253 FilePath directory;
254 if (!GetTempDir(&directory))
Ivan Kotenkova16212a52017-11-08 12:37:33255 return nullptr;
brettw@chromium.org03d9afc02013-12-03 17:55:52256
Greg Thompsonf75f5fb2020-04-30 08:13:25257 return CreateAndOpenTemporaryStreamInDir(directory, path);
brettw@chromium.org03d9afc02013-12-03 17:55:52258}
259
brettw@chromium.org426d1c92013-12-03 20:08:54260bool CreateDirectory(const FilePath& full_path) {
Ivan Kotenkova16212a52017-11-08 12:37:33261 return CreateDirectoryAndGetError(full_path, nullptr);
brettw@chromium.org426d1c92013-12-03 20:08:54262}
263
avi543540e2015-12-24 05:15:32264bool GetFileSize(const FilePath& file_path, int64_t* file_size) {
rvargas@chromium.org54124ed02014-01-07 10:06:58265 File::Info info;
brettw@chromium.org9eae4e62013-12-04 20:56:49266 if (!GetFileInfo(file_path, &info))
brettw@chromium.org56285702013-12-04 18:22:49267 return false;
268 *file_size = info.size;
269 return true;
270}
271
brettw@chromium.orgc0d508162013-12-04 22:49:00272bool TouchFile(const FilePath& path,
273 const Time& last_accessed,
274 const Time& last_modified) {
rvargas@chromium.org54124ed02014-01-07 10:06:58275 int flags = File::FLAG_OPEN | File::FLAG_WRITE_ATTRIBUTES;
brettw@chromium.orgc0d508162013-12-04 22:49:00276
277#if defined(OS_WIN)
278 // On Windows, FILE_FLAG_BACKUP_SEMANTICS is needed to open a directory.
279 if (DirectoryExists(path))
rvargas@chromium.org54124ed02014-01-07 10:06:58280 flags |= File::FLAG_BACKUP_SEMANTICS;
Wez432ea8d892019-03-31 01:17:08281#elif defined(OS_FUCHSIA)
282 // On Fuchsia, we need O_RDONLY for directories, or O_WRONLY for files.
283 // TODO(https://crbug.com/947802): Find a cleaner workaround for this.
284 flags |= (DirectoryExists(path) ? File::FLAG_READ : File::FLAG_WRITE);
285#endif
brettw@chromium.orgc0d508162013-12-04 22:49:00286
rvargas@chromium.org54124ed02014-01-07 10:06:58287 File file(path, flags);
288 if (!file.IsValid())
289 return false;
brettw@chromium.orgc0d508162013-12-04 22:49:00290
rvargas@chromium.org54124ed02014-01-07 10:06:58291 return file.SetTimes(last_accessed, last_modified);
brettw@chromium.orgc0d508162013-12-04 22:49:00292}
hidehiko8fc7c822015-06-09 02:50:57293#endif // !defined(OS_NACL_NONSFI)
brettw@chromium.orgc0d508162013-12-04 22:49:00294
mark@chromium.org836f1342008-10-01 17:40:13295bool CloseFile(FILE* file) {
Ivan Kotenkova16212a52017-11-08 12:37:33296 if (file == nullptr)
sidchat@google.coma1a19502008-10-21 17:14:45297 return true;
mark@chromium.org836f1342008-10-01 17:40:13298 return fclose(file) == 0;
299}
300
hidehiko8fc7c822015-06-09 02:50:57301#if !defined(OS_NACL_NONSFI)
jeremy@chromium.orgc2c998c2009-01-27 19:08:39302bool TruncateFile(FILE* file) {
Ivan Kotenkova16212a52017-11-08 12:37:33303 if (file == nullptr)
jeremy@chromium.orgc2c998c2009-01-27 19:08:39304 return false;
305 long current_offset = ftell(file);
306 if (current_offset == -1)
307 return false;
308#if defined(OS_WIN)
309 int fd = _fileno(file);
310 if (_chsize(fd, current_offset) != 0)
311 return false;
312#else
313 int fd = fileno(file);
314 if (ftruncate(fd, current_offset) != 0)
315 return false;
316#endif
317 return true;
318}
319
Lei Zhangeebbef62020-05-05 20:16:05320bool WriteFile(const FilePath& filename, span<const uint8_t> data) {
321 int size = checked_cast<int>(data.size());
322 return WriteFile(filename, reinterpret_cast<const char*>(data.data()),
323 size) == size;
324}
325
326bool WriteFile(const FilePath& filename, StringPiece data) {
327 int size = checked_cast<int>(data.size());
328 return WriteFile(filename, data.data(), size) == size;
329}
330
Greg Thompsonb4abcb42019-08-23 01:42:56331int GetUniquePathNumber(const FilePath& path) {
332 DCHECK(!path.empty());
333 if (!PathExists(path))
Greg Thompson42373544a2019-08-14 10:11:10334 return 0;
335
336 std::string number;
337 for (int count = 1; count <= kMaxUniqueFiles; ++count) {
338 StringAppendF(&number, " (%d)", count);
Greg Thompsonb4abcb42019-08-23 01:42:56339 if (!PathExists(path.InsertBeforeExtensionASCII(number)))
Greg Thompson42373544a2019-08-14 10:11:10340 return count;
341 number.clear();
jam@chromium.orge285afa2012-01-31 23:16:39342 }
343
344 return -1;
345}
Bruce Longd096e482019-02-28 17:50:00346
347FilePath GetUniquePath(const FilePath& path) {
Greg Thompsonb4abcb42019-08-23 01:42:56348 DCHECK(!path.empty());
349 const int uniquifier = GetUniquePathNumber(path);
350 if (uniquifier > 0)
351 return path.InsertBeforeExtensionASCII(StringPrintf(" (%d)", uniquifier));
352 return uniquifier == 0 ? path : base::FilePath();
Bruce Longd096e482019-02-28 17:50:00353}
Victor Costanb5a0a97002019-09-08 04:55:15354
355namespace internal {
356
357bool PreReadFileSlow(const FilePath& file_path, int64_t max_bytes) {
358 DCHECK_GE(max_bytes, 0);
359
360 File file(file_path, File::FLAG_OPEN | File::FLAG_READ |
361 File::FLAG_SEQUENTIAL_SCAN |
362 File::FLAG_SHARE_DELETE);
363 if (!file.IsValid())
364 return false;
365
366 constexpr int kBufferSize = 1024 * 1024;
367 // Ensures the buffer is deallocated at function exit.
368 std::unique_ptr<char[]> buffer_deleter(new char[kBufferSize]);
369 char* const buffer = buffer_deleter.get();
370
371 while (max_bytes > 0) {
372 // The static_cast<int> is safe because kBufferSize is int, and both values
373 // are non-negative. So, the minimum is guaranteed to fit in int.
374 const int read_size =
375 static_cast<int>(std::min<int64_t>(max_bytes, kBufferSize));
376 DCHECK_GE(read_size, 0);
377 DCHECK_LE(read_size, kBufferSize);
378
379 const int read_bytes = file.ReadAtCurrentPos(buffer, read_size);
380 if (read_bytes < 0)
381 return false;
382 if (read_bytes == 0)
383 break;
384
385 max_bytes -= read_bytes;
386 }
387
388 return true;
389}
390
391} // namespace internal
392
hidehiko8fc7c822015-06-09 02:50:57393#endif // !defined(OS_NACL_NONSFI)
jam@chromium.orge285afa2012-01-31 23:16:39394
brettw@chromium.orga26f4ae2014-03-13 17:26:21395} // namespace base