[go: nahoru, domu]

blob: c406696d06b0083a0e3984b24a034fce1b6f1eaf [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:2330OnceCallback<void(const FilePath&)> GetDeleteFileCallback() {
Lei Zhang9382efe2020-07-25 20:52:1431 return BindOnce(IgnoreResult(&DeleteFile));
Lei Zhange3aa0b9a2020-06-11 08:59:2332}
33
Lei Zhang3190449f2020-06-12 05:14:0434OnceCallback<void(const FilePath&)> GetDeletePathRecursivelyCallback() {
Lei Zhang746ce472020-07-01 04:39:4535 return BindOnce(IgnoreResult(&DeletePathRecursively));
Lei Zhang3190449f2020-06-12 05:14:0436}
37
avi543540e2015-12-24 05:15:3238int64_t ComputeDirectorySize(const FilePath& root_path) {
39 int64_t running_size = 0;
brettw@chromium.org0408c752013-06-22 22:15:4640 FileEnumerator file_iter(root_path, true, FileEnumerator::FILES);
41 while (!file_iter.Next().empty())
42 running_size += file_iter.GetInfo().GetSize();
43 return running_size;
44}
45
brettw@chromium.org5553d5b2013-07-01 23:07:3646bool Move(const FilePath& from_path, const FilePath& to_path) {
47 if (from_path.ReferencesParent() || to_path.ReferencesParent())
48 return false;
brettw@chromium.orgf0ff2ad2013-07-09 17:42:2649 return internal::MoveUnsafe(from_path, to_path);
50}
51
Alexander Bolodurin53bfc89c22020-11-25 22:43:2952bool CopyFileContents(File& infile, File& outfile) {
53 static constexpr size_t kBufferSize = 32768;
54 std::vector<char> buffer(kBufferSize);
55
56 for (;;) {
57 int bytes_read = infile.ReadAtCurrentPos(buffer.data(), buffer.size());
58 if (bytes_read < 0) {
59 return false;
60 }
61 if (bytes_read == 0) {
62 return true;
63 }
64 // Allow for partial writes
65 int bytes_written_per_read = 0;
66 do {
67 int bytes_written_partial = outfile.WriteAtCurrentPos(
68 &buffer[bytes_written_per_read], bytes_read - bytes_written_per_read);
69 if (bytes_written_partial < 0) {
70 return false;
71 }
72
73 bytes_written_per_read += bytes_written_partial;
74 } while (bytes_written_per_read < bytes_read);
75 }
76
77 NOTREACHED();
78 return false;
79}
80
evanm@google.com640517f2008-10-30 23:54:0481bool ContentsEqual(const FilePath& filename1, const FilePath& filename2) {
initial.commitd7cae122008-07-26 21:49:3882 // We open the file in binary format even if they are text files because
83 // we are just comparing that bytes are exactly same in both files and not
84 // doing anything smart with text formatting.
jdoerrie983968a2019-01-29 12:54:4185#if defined(OS_WIN)
Jan Wilken Dörrie9bb441d2019-11-01 17:48:4086 std::ifstream file1(filename1.value().c_str(),
erikkay@google.com5af2edb92008-08-08 20:16:0887 std::ios::in | std::ios::binary);
Jan Wilken Dörrie9bb441d2019-11-01 17:48:4088 std::ifstream file2(filename2.value().c_str(),
erikkay@google.com5af2edb92008-08-08 20:16:0889 std::ios::in | std::ios::binary);
jdoerrie983968a2019-01-29 12:54:4190#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
91 std::ifstream file1(filename1.value(), std::ios::in | std::ios::binary);
92 std::ifstream file2(filename2.value(), std::ios::in | std::ios::binary);
93#endif // OS_WIN
estade@chromium.orgb9e04f02008-11-27 04:03:5794
initial.commitd7cae122008-07-26 21:49:3895 // Even if both files aren't openable (and thus, in some sense, "equal"),
96 // any unusable file yields a result of "false".
97 if (!file1.is_open() || !file2.is_open())
98 return false;
99
100 const int BUFFER_SIZE = 2056;
101 char buffer1[BUFFER_SIZE], buffer2[BUFFER_SIZE];
102 do {
103 file1.read(buffer1, BUFFER_SIZE);
104 file2.read(buffer2, BUFFER_SIZE);
105
mark@chromium.orgb81637c32009-06-26 21:17:24106 if ((file1.eof() != file2.eof()) ||
initial.commitd7cae122008-07-26 21:49:38107 (file1.gcount() != file2.gcount()) ||
pkasting9cf9b942014-10-01 22:18:43108 (memcmp(buffer1, buffer2, static_cast<size_t>(file1.gcount())))) {
initial.commitd7cae122008-07-26 21:49:38109 file1.close();
110 file2.close();
111 return false;
112 }
mark@chromium.orgb81637c32009-06-26 21:17:24113 } while (!file1.eof() || !file2.eof());
initial.commitd7cae122008-07-26 21:49:38114
115 file1.close();
116 file2.close();
117 return true;
118}
119
mark@chromium.orgb81637c32009-06-26 21:17:24120bool TextContentsEqual(const FilePath& filename1, const FilePath& filename2) {
jdoerrie983968a2019-01-29 12:54:41121#if defined(OS_WIN)
Jan Wilken Dörrie9bb441d2019-11-01 17:48:40122 std::ifstream file1(filename1.value().c_str(), std::ios::in);
123 std::ifstream file2(filename2.value().c_str(), std::ios::in);
jdoerrie983968a2019-01-29 12:54:41124#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
125 std::ifstream file1(filename1.value(), std::ios::in);
126 std::ifstream file2(filename2.value(), std::ios::in);
127#endif // OS_WIN
mark@chromium.orgb81637c32009-06-26 21:17:24128
129 // Even if both files aren't openable (and thus, in some sense, "equal"),
130 // any unusable file yields a result of "false".
131 if (!file1.is_open() || !file2.is_open())
132 return false;
133
134 do {
135 std::string line1, line2;
136 getline(file1, line1);
137 getline(file2, line2);
138
139 // Check for mismatched EOF states, or any error state.
140 if ((file1.eof() != file2.eof()) ||
141 file1.bad() || file2.bad()) {
142 return false;
143 }
144
145 // Trim all '\r' and '\n' characters from the end of the line.
146 std::string::size_type end1 = line1.find_last_not_of("\r\n");
147 if (end1 == std::string::npos)
148 line1.clear();
149 else if (end1 + 1 < line1.length())
150 line1.erase(end1 + 1);
151
152 std::string::size_type end2 = line2.find_last_not_of("\r\n");
153 if (end2 == std::string::npos)
154 line2.clear();
155 else if (end2 + 1 < line2.length())
156 line2.erase(end2 + 1);
157
158 if (line1 != line2)
159 return false;
160 } while (!file1.eof() || !file2.eof());
161
162 return true;
163}
hidehiko8fc7c822015-06-09 02:50:57164#endif // !defined(OS_NACL_NONSFI)
mark@chromium.orgb81637c32009-06-26 21:17:24165
Greg Thompson3f7e20f42020-05-02 19:01:11166bool ReadStreamToString(FILE* stream, std::string* contents) {
167 return ReadStreamToStringWithMaxSize(
168 stream, std::numeric_limits<size_t>::max(), contents);
169}
170
171bool ReadStreamToStringWithMaxSize(FILE* stream,
172 size_t max_size,
173 std::string* contents) {
kaliamoorthi@chromium.org0710fdd2014-02-18 16:31:51174 if (contents)
175 contents->clear();
initial.commitd7cae122008-07-26 21:49:38176
Greg Thompson3f7e20f42020-05-02 19:01:11177 // Seeking to the beginning is best-effort -- it is expected to fail for
178 // certain non-file stream (e.g., pipes).
179 HANDLE_EINTR(fseek(stream, 0, SEEK_SET));
180
181 // Many files have incorrect size (proc files etc). Hence, the file is read
182 // sequentially as opposed to a one-shot read, using file size as a hint for
183 // chunk size if available.
Mikhail Istomin1ede1552018-05-16 17:40:24184 constexpr int64_t kDefaultChunkSize = 1 << 16;
Greg Thompson3f7e20f42020-05-02 19:01:11185 int64_t chunk_size = kDefaultChunkSize - 1;
Mikhail Istomin1ede1552018-05-16 17:40:24186#if !defined(OS_NACL_NONSFI)
Greg Thompson3f7e20f42020-05-02 19:01:11187 ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
188#if defined(OS_WIN)
189 BY_HANDLE_FILE_INFORMATION file_info = {};
190 if (::GetFileInformationByHandle(
191 reinterpret_cast<HANDLE>(_get_osfhandle(_fileno(stream))),
192 &file_info)) {
193 LARGE_INTEGER size;
194 size.HighPart = file_info.nFileSizeHigh;
195 size.LowPart = file_info.nFileSizeLow;
196 if (size.QuadPart > 0)
197 chunk_size = size.QuadPart;
198 }
199#else // defined(OS_WIN)
200 stat_wrapper_t file_info = {};
201 if (!File::Fstat(fileno(stream), &file_info) && file_info.st_size > 0)
202 chunk_size = file_info.st_size;
203#endif // defined(OS_WIN)
Mikhail Istomin1ede1552018-05-16 17:40:24204 // We need to attempt to read at EOF for feof flag to be set so here we
205 // use |chunk_size| + 1.
206 chunk_size = std::min<uint64_t>(chunk_size, max_size) + 1;
Greg Thompson3f7e20f42020-05-02 19:01:11207#else // !defined(OS_NACL_NONSFI)
Mikhail Istomin1ede1552018-05-16 17:40:24208 chunk_size = kDefaultChunkSize;
209#endif // !defined(OS_NACL_NONSFI)
210 size_t bytes_read_this_pass;
211 size_t bytes_read_so_far = 0;
212 bool read_status = true;
213 std::string local_contents;
214 local_contents.resize(chunk_size);
kaliamoorthi@chromium.org0710fdd2014-02-18 16:31:51215
Mikhail Istomin1ede1552018-05-16 17:40:24216 while ((bytes_read_this_pass = fread(&local_contents[bytes_read_so_far], 1,
Greg Thompson3f7e20f42020-05-02 19:01:11217 chunk_size, stream)) > 0) {
Mikhail Istomin1ede1552018-05-16 17:40:24218 if ((max_size - bytes_read_so_far) < bytes_read_this_pass) {
219 // Read more than max_size bytes, bail out.
220 bytes_read_so_far = max_size;
kaliamoorthi@chromium.org0710fdd2014-02-18 16:31:51221 read_status = false;
222 break;
223 }
Mikhail Istomin1ede1552018-05-16 17:40:24224 // In case EOF was not reached, iterate again but revert to the default
225 // chunk size.
226 if (bytes_read_so_far == 0)
227 chunk_size = kDefaultChunkSize;
kaliamoorthi@chromium.org0710fdd2014-02-18 16:31:51228
Mikhail Istomin1ede1552018-05-16 17:40:24229 bytes_read_so_far += bytes_read_this_pass;
230 // Last fread syscall (after EOF) can be avoided via feof, which is just a
231 // flag check.
Greg Thompson3f7e20f42020-05-02 19:01:11232 if (feof(stream))
Mikhail Istomin1ede1552018-05-16 17:40:24233 break;
234 local_contents.resize(bytes_read_so_far + chunk_size);
initial.commitd7cae122008-07-26 21:49:38235 }
Greg Thompson3f7e20f42020-05-02 19:01:11236 read_status = read_status && !ferror(stream);
Mikhail Istomin1ede1552018-05-16 17:40:24237 if (contents) {
238 contents->swap(local_contents);
239 contents->resize(bytes_read_so_far);
240 }
initial.commitd7cae122008-07-26 21:49:38241
kaliamoorthi@chromium.org0710fdd2014-02-18 16:31:51242 return read_status;
243}
244
245bool ReadFileToString(const FilePath& path, std::string* contents) {
hashimoto6da2fef2016-02-24 03:39:58246 return ReadFileToStringWithMaxSize(path, contents,
247 std::numeric_limits<size_t>::max());
initial.commitd7cae122008-07-26 21:49:38248}
249
Greg Thompson3f7e20f42020-05-02 19:01:11250bool ReadFileToStringWithMaxSize(const FilePath& path,
251 std::string* contents,
252 size_t max_size) {
253 if (contents)
254 contents->clear();
255 if (path.ReferencesParent())
256 return false;
257 ScopedFILE file_stream(OpenFile(path, "rb"));
258 if (!file_stream)
259 return false;
260 return ReadStreamToStringWithMaxSize(file_stream.get(), max_size, contents);
261}
262
hidehiko8fc7c822015-06-09 02:50:57263#if !defined(OS_NACL_NONSFI)
brettw@chromium.orgfb4bcfa32013-12-02 18:55:49264bool IsDirectoryEmpty(const FilePath& dir_path) {
265 FileEnumerator files(dir_path, false,
266 FileEnumerator::FILES | FileEnumerator::DIRECTORIES);
267 if (files.Next().empty())
268 return true;
269 return false;
270}
271
Greg Thompson3f7e20f42020-05-02 19:01:11272bool CreateTemporaryFile(FilePath* path) {
273 FilePath temp_dir;
274 return GetTempDir(&temp_dir) && CreateTemporaryFileInDir(temp_dir, path);
275}
276
Greg Thompsonf75f5fb2020-04-30 08:13:25277ScopedFILE CreateAndOpenTemporaryStream(FilePath* path) {
brettw@chromium.org03d9afc02013-12-03 17:55:52278 FilePath directory;
279 if (!GetTempDir(&directory))
Ivan Kotenkova16212a52017-11-08 12:37:33280 return nullptr;
brettw@chromium.org03d9afc02013-12-03 17:55:52281
Greg Thompsonf75f5fb2020-04-30 08:13:25282 return CreateAndOpenTemporaryStreamInDir(directory, path);
brettw@chromium.org03d9afc02013-12-03 17:55:52283}
284
brettw@chromium.org426d1c92013-12-03 20:08:54285bool CreateDirectory(const FilePath& full_path) {
Ivan Kotenkova16212a52017-11-08 12:37:33286 return CreateDirectoryAndGetError(full_path, nullptr);
brettw@chromium.org426d1c92013-12-03 20:08:54287}
288
avi543540e2015-12-24 05:15:32289bool GetFileSize(const FilePath& file_path, int64_t* file_size) {
rvargas@chromium.org54124ed02014-01-07 10:06:58290 File::Info info;
brettw@chromium.org9eae4e62013-12-04 20:56:49291 if (!GetFileInfo(file_path, &info))
brettw@chromium.org56285702013-12-04 18:22:49292 return false;
293 *file_size = info.size;
294 return true;
295}
296
brettw@chromium.orgc0d508162013-12-04 22:49:00297bool TouchFile(const FilePath& path,
298 const Time& last_accessed,
299 const Time& last_modified) {
rvargas@chromium.org54124ed02014-01-07 10:06:58300 int flags = File::FLAG_OPEN | File::FLAG_WRITE_ATTRIBUTES;
brettw@chromium.orgc0d508162013-12-04 22:49:00301
302#if defined(OS_WIN)
303 // On Windows, FILE_FLAG_BACKUP_SEMANTICS is needed to open a directory.
304 if (DirectoryExists(path))
rvargas@chromium.org54124ed02014-01-07 10:06:58305 flags |= File::FLAG_BACKUP_SEMANTICS;
Wez432ea8d892019-03-31 01:17:08306#elif defined(OS_FUCHSIA)
307 // On Fuchsia, we need O_RDONLY for directories, or O_WRONLY for files.
308 // TODO(https://crbug.com/947802): Find a cleaner workaround for this.
309 flags |= (DirectoryExists(path) ? File::FLAG_READ : File::FLAG_WRITE);
310#endif
brettw@chromium.orgc0d508162013-12-04 22:49:00311
rvargas@chromium.org54124ed02014-01-07 10:06:58312 File file(path, flags);
313 if (!file.IsValid())
314 return false;
brettw@chromium.orgc0d508162013-12-04 22:49:00315
rvargas@chromium.org54124ed02014-01-07 10:06:58316 return file.SetTimes(last_accessed, last_modified);
brettw@chromium.orgc0d508162013-12-04 22:49:00317}
hidehiko8fc7c822015-06-09 02:50:57318#endif // !defined(OS_NACL_NONSFI)
brettw@chromium.orgc0d508162013-12-04 22:49:00319
mark@chromium.org836f1342008-10-01 17:40:13320bool CloseFile(FILE* file) {
Ivan Kotenkova16212a52017-11-08 12:37:33321 if (file == nullptr)
sidchat@google.coma1a19502008-10-21 17:14:45322 return true;
mark@chromium.org836f1342008-10-01 17:40:13323 return fclose(file) == 0;
324}
325
hidehiko8fc7c822015-06-09 02:50:57326#if !defined(OS_NACL_NONSFI)
jeremy@chromium.orgc2c998c2009-01-27 19:08:39327bool TruncateFile(FILE* file) {
Ivan Kotenkova16212a52017-11-08 12:37:33328 if (file == nullptr)
jeremy@chromium.orgc2c998c2009-01-27 19:08:39329 return false;
330 long current_offset = ftell(file);
331 if (current_offset == -1)
332 return false;
333#if defined(OS_WIN)
334 int fd = _fileno(file);
335 if (_chsize(fd, current_offset) != 0)
336 return false;
337#else
338 int fd = fileno(file);
339 if (ftruncate(fd, current_offset) != 0)
340 return false;
341#endif
342 return true;
343}
344
Lei Zhangeebbef62020-05-05 20:16:05345bool WriteFile(const FilePath& filename, span<const uint8_t> data) {
346 int size = checked_cast<int>(data.size());
347 return WriteFile(filename, reinterpret_cast<const char*>(data.data()),
348 size) == size;
349}
350
351bool WriteFile(const FilePath& filename, StringPiece data) {
352 int size = checked_cast<int>(data.size());
353 return WriteFile(filename, data.data(), size) == size;
354}
355
Greg Thompsonb4abcb42019-08-23 01:42:56356int GetUniquePathNumber(const FilePath& path) {
357 DCHECK(!path.empty());
358 if (!PathExists(path))
Greg Thompson42373544a2019-08-14 10:11:10359 return 0;
360
361 std::string number;
362 for (int count = 1; count <= kMaxUniqueFiles; ++count) {
363 StringAppendF(&number, " (%d)", count);
Greg Thompsonb4abcb42019-08-23 01:42:56364 if (!PathExists(path.InsertBeforeExtensionASCII(number)))
Greg Thompson42373544a2019-08-14 10:11:10365 return count;
366 number.clear();
jam@chromium.orge285afa2012-01-31 23:16:39367 }
368
369 return -1;
370}
Bruce Longd096e482019-02-28 17:50:00371
372FilePath GetUniquePath(const FilePath& path) {
Greg Thompsonb4abcb42019-08-23 01:42:56373 DCHECK(!path.empty());
374 const int uniquifier = GetUniquePathNumber(path);
375 if (uniquifier > 0)
376 return path.InsertBeforeExtensionASCII(StringPrintf(" (%d)", uniquifier));
377 return uniquifier == 0 ? path : base::FilePath();
Bruce Longd096e482019-02-28 17:50:00378}
Victor Costanb5a0a97002019-09-08 04:55:15379
380namespace internal {
381
382bool PreReadFileSlow(const FilePath& file_path, int64_t max_bytes) {
383 DCHECK_GE(max_bytes, 0);
384
385 File file(file_path, File::FLAG_OPEN | File::FLAG_READ |
386 File::FLAG_SEQUENTIAL_SCAN |
387 File::FLAG_SHARE_DELETE);
388 if (!file.IsValid())
389 return false;
390
391 constexpr int kBufferSize = 1024 * 1024;
392 // Ensures the buffer is deallocated at function exit.
393 std::unique_ptr<char[]> buffer_deleter(new char[kBufferSize]);
394 char* const buffer = buffer_deleter.get();
395
396 while (max_bytes > 0) {
397 // The static_cast<int> is safe because kBufferSize is int, and both values
398 // are non-negative. So, the minimum is guaranteed to fit in int.
399 const int read_size =
400 static_cast<int>(std::min<int64_t>(max_bytes, kBufferSize));
401 DCHECK_GE(read_size, 0);
402 DCHECK_LE(read_size, kBufferSize);
403
404 const int read_bytes = file.ReadAtCurrentPos(buffer, read_size);
405 if (read_bytes < 0)
406 return false;
407 if (read_bytes == 0)
408 break;
409
410 max_bytes -= read_bytes;
411 }
412
413 return true;
414}
415
416} // namespace internal
417
hidehiko8fc7c822015-06-09 02:50:57418#endif // !defined(OS_NACL_NONSFI)
jam@chromium.orge285afa2012-01-31 23:16:39419
brettw@chromium.orga26f4ae2014-03-13 17:26:21420} // namespace base