[go: nahoru, domu]

blob: 0528ad26e63bd0f8f67d88b67c0921b43f33dc6f [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
Xiaohan Wangb705a64a2022-01-15 18:31:137#include "build/build_config.h"
8
9#if BUILDFLAG(IS_WIN)
jeremy@chromium.orgc2c998c2009-01-27 19:08:3910#include <io.h>
11#endif
mark@chromium.org836f1342008-10-01 17:40:1312#include <stdio.h>
13
initial.commitd7cae122008-07-26 21:49:3814#include <fstream>
kaliamoorthi@chromium.org0710fdd2014-02-18 16:31:5115#include <limits>
Victor Costanb5a0a97002019-09-08 04:55:1516#include <memory>
Xiaohan Wang12bd22202022-05-19 15:38:0217#include <utility>
Victor Hugo Vianna Silva05f14542021-08-05 16:08:4818#include <vector>
initial.commitd7cae122008-07-26 21:49:3819
Hans Wennborgc3cffa62020-04-27 10:09:1220#include "base/check_op.h"
brettw@chromium.org25a4c1c2013-06-08 04:53:3621#include "base/files/file_enumerator.h"
brettw@chromium.org57999812013-02-24 05:40:5222#include "base/files/file_path.h"
David Sanders83f8ae42022-04-04 23:15:3923#include "base/notreached.h"
Greg Thompson3f7e20f42020-05-02 19:01:1124#include "base/posix/eintr_wrapper.h"
tfarina@chromium.orgeb62f7262013-03-30 14:29:0025#include "base/strings/string_piece.h"
avi@chromium.org251cd6e52013-06-11 13:36:3726#include "base/strings/string_util.h"
27#include "base/strings/stringprintf.h"
avi@chromium.orga4ea1f12013-06-07 18:37:0728#include "base/strings/utf_string_conversions.h"
Xiaohan Wang12bd22202022-05-19 15:38:0229#include "base/task/bind_post_task.h"
Etienne Pierre-Doray1da58592018-09-21 14:47:2030#include "base/threading/scoped_blocking_call.h"
Xiaohan Wang12bd22202022-05-19 15:38:0231#include "base/threading/sequenced_task_runner_handle.h"
avi543540e2015-12-24 05:15:3232#include "build/build_config.h"
estade@chromium.orgb9e04f02008-11-27 04:03:5733
Xiaohan Wangb705a64a2022-01-15 18:31:1334#if BUILDFLAG(IS_WIN)
Bruce Dawson1ad438d2021-07-09 20:10:0335#include <windows.h>
36#endif
37
brettw@chromium.org0408c752013-06-22 22:15:4638namespace base {
brettw@chromium.org04af979a2013-02-16 04:12:2639
Xiaohan Wang12bd22202022-05-19 15:38:0240namespace {
41
42void RunAndReply(OnceCallback<bool()> action_callback,
43 OnceCallback<void(bool)> reply_callback) {
44 bool result = std::move(action_callback).Run();
45 if (!reply_callback.is_null())
46 std::move(reply_callback).Run(result);
47}
48
49} // namespace
50
Xiaohan Wangb705a64a2022-01-15 18:31:1351#if !BUILDFLAG(IS_WIN)
Xiaohan Wang12bd22202022-05-19 15:38:0252OnceClosure GetDeleteFileCallback(const FilePath& path,
53 OnceCallback<void(bool)> reply_callback) {
54 return BindOnce(&RunAndReply, BindOnce(&DeleteFile, path),
55 reply_callback.is_null()
56 ? std::move(reply_callback)
57 : BindPostTask(SequencedTaskRunnerHandle::Get(),
58 std::move(reply_callback)));
Lei Zhange3aa0b9a2020-06-11 08:59:2359}
Xiaohan Wangb705a64a2022-01-15 18:31:1360#endif // !BUILDFLAG(IS_WIN)
Lei Zhange3aa0b9a2020-06-11 08:59:2361
Xiaohan Wang12bd22202022-05-19 15:38:0262OnceClosure GetDeletePathRecursivelyCallback(
63 const FilePath& path,
64 OnceCallback<void(bool)> reply_callback) {
65 return BindOnce(&RunAndReply, BindOnce(&DeletePathRecursively, path),
66 reply_callback.is_null()
67 ? std::move(reply_callback)
68 : BindPostTask(SequencedTaskRunnerHandle::Get(),
69 std::move(reply_callback)));
Lei Zhang3190449f2020-06-12 05:14:0470}
71
avi543540e2015-12-24 05:15:3272int64_t ComputeDirectorySize(const FilePath& root_path) {
73 int64_t running_size = 0;
brettw@chromium.org0408c752013-06-22 22:15:4674 FileEnumerator file_iter(root_path, true, FileEnumerator::FILES);
75 while (!file_iter.Next().empty())
76 running_size += file_iter.GetInfo().GetSize();
77 return running_size;
78}
79
brettw@chromium.org5553d5b2013-07-01 23:07:3680bool Move(const FilePath& from_path, const FilePath& to_path) {
81 if (from_path.ReferencesParent() || to_path.ReferencesParent())
82 return false;
brettw@chromium.orgf0ff2ad2013-07-09 17:42:2683 return internal::MoveUnsafe(from_path, to_path);
84}
85
Alexander Bolodurin53bfc89c22020-11-25 22:43:2986bool CopyFileContents(File& infile, File& outfile) {
Xiaohan Wangb705a64a2022-01-15 18:31:1387#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
Brian Geffon591e8f22021-04-08 18:33:2388 bool retry_slow = false;
89 bool res =
90 internal::CopyFileContentsWithSendfile(infile, outfile, retry_slow);
91 if (res || !retry_slow) {
92 return res;
93 }
94 // Any failures which allow retrying using read/write will not have modified
95 // either file offset or size.
96#endif
97
Alexander Bolodurin53bfc89c22020-11-25 22:43:2998 static constexpr size_t kBufferSize = 32768;
99 std::vector<char> buffer(kBufferSize);
100
101 for (;;) {
102 int bytes_read = infile.ReadAtCurrentPos(buffer.data(), buffer.size());
103 if (bytes_read < 0) {
104 return false;
105 }
106 if (bytes_read == 0) {
107 return true;
108 }
109 // Allow for partial writes
110 int bytes_written_per_read = 0;
111 do {
112 int bytes_written_partial = outfile.WriteAtCurrentPos(
113 &buffer[bytes_written_per_read], bytes_read - bytes_written_per_read);
114 if (bytes_written_partial < 0) {
115 return false;
116 }
117
118 bytes_written_per_read += bytes_written_partial;
119 } while (bytes_written_per_read < bytes_read);
120 }
121
122 NOTREACHED();
123 return false;
124}
125
evanm@google.com640517f2008-10-30 23:54:04126bool ContentsEqual(const FilePath& filename1, const FilePath& filename2) {
initial.commitd7cae122008-07-26 21:49:38127 // We open the file in binary format even if they are text files because
128 // we are just comparing that bytes are exactly same in both files and not
129 // doing anything smart with text formatting.
Xiaohan Wangb705a64a2022-01-15 18:31:13130#if BUILDFLAG(IS_WIN)
Jan Wilken Dörrie9bb441d2019-11-01 17:48:40131 std::ifstream file1(filename1.value().c_str(),
erikkay@google.com5af2edb92008-08-08 20:16:08132 std::ios::in | std::ios::binary);
Jan Wilken Dörrie9bb441d2019-11-01 17:48:40133 std::ifstream file2(filename2.value().c_str(),
erikkay@google.com5af2edb92008-08-08 20:16:08134 std::ios::in | std::ios::binary);
Xiaohan Wangb705a64a2022-01-15 18:31:13135#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
jdoerrie983968a2019-01-29 12:54:41136 std::ifstream file1(filename1.value(), std::ios::in | std::ios::binary);
137 std::ifstream file2(filename2.value(), std::ios::in | std::ios::binary);
Xiaohan Wangb705a64a2022-01-15 18:31:13138#endif // BUILDFLAG(IS_WIN)
estade@chromium.orgb9e04f02008-11-27 04:03:57139
initial.commitd7cae122008-07-26 21:49:38140 // Even if both files aren't openable (and thus, in some sense, "equal"),
141 // any unusable file yields a result of "false".
142 if (!file1.is_open() || !file2.is_open())
143 return false;
144
145 const int BUFFER_SIZE = 2056;
146 char buffer1[BUFFER_SIZE], buffer2[BUFFER_SIZE];
147 do {
148 file1.read(buffer1, BUFFER_SIZE);
149 file2.read(buffer2, BUFFER_SIZE);
150
mark@chromium.orgb81637c32009-06-26 21:17:24151 if ((file1.eof() != file2.eof()) ||
initial.commitd7cae122008-07-26 21:49:38152 (file1.gcount() != file2.gcount()) ||
pkasting9cf9b942014-10-01 22:18:43153 (memcmp(buffer1, buffer2, static_cast<size_t>(file1.gcount())))) {
initial.commitd7cae122008-07-26 21:49:38154 file1.close();
155 file2.close();
156 return false;
157 }
mark@chromium.orgb81637c32009-06-26 21:17:24158 } while (!file1.eof() || !file2.eof());
initial.commitd7cae122008-07-26 21:49:38159
160 file1.close();
161 file2.close();
162 return true;
163}
164
mark@chromium.orgb81637c32009-06-26 21:17:24165bool TextContentsEqual(const FilePath& filename1, const FilePath& filename2) {
Xiaohan Wangb705a64a2022-01-15 18:31:13166#if BUILDFLAG(IS_WIN)
Jan Wilken Dörrie9bb441d2019-11-01 17:48:40167 std::ifstream file1(filename1.value().c_str(), std::ios::in);
168 std::ifstream file2(filename2.value().c_str(), std::ios::in);
Xiaohan Wangb705a64a2022-01-15 18:31:13169#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
jdoerrie983968a2019-01-29 12:54:41170 std::ifstream file1(filename1.value(), std::ios::in);
171 std::ifstream file2(filename2.value(), std::ios::in);
Xiaohan Wangb705a64a2022-01-15 18:31:13172#endif // BUILDFLAG(IS_WIN)
mark@chromium.orgb81637c32009-06-26 21:17:24173
174 // Even if both files aren't openable (and thus, in some sense, "equal"),
175 // any unusable file yields a result of "false".
176 if (!file1.is_open() || !file2.is_open())
177 return false;
178
179 do {
180 std::string line1, line2;
181 getline(file1, line1);
182 getline(file2, line2);
183
184 // Check for mismatched EOF states, or any error state.
185 if ((file1.eof() != file2.eof()) ||
186 file1.bad() || file2.bad()) {
187 return false;
188 }
189
190 // Trim all '\r' and '\n' characters from the end of the line.
191 std::string::size_type end1 = line1.find_last_not_of("\r\n");
192 if (end1 == std::string::npos)
193 line1.clear();
194 else if (end1 + 1 < line1.length())
195 line1.erase(end1 + 1);
196
197 std::string::size_type end2 = line2.find_last_not_of("\r\n");
198 if (end2 == std::string::npos)
199 line2.clear();
200 else if (end2 + 1 < line2.length())
201 line2.erase(end2 + 1);
202
203 if (line1 != line2)
204 return false;
205 } while (!file1.eof() || !file2.eof());
206
207 return true;
208}
209
Greg Thompson3f7e20f42020-05-02 19:01:11210bool ReadStreamToString(FILE* stream, std::string* contents) {
211 return ReadStreamToStringWithMaxSize(
212 stream, std::numeric_limits<size_t>::max(), contents);
213}
214
215bool ReadStreamToStringWithMaxSize(FILE* stream,
216 size_t max_size,
217 std::string* contents) {
kaliamoorthi@chromium.org0710fdd2014-02-18 16:31:51218 if (contents)
219 contents->clear();
Abhijith Nair1b5b6ee22021-11-18 21:01:59220 if (!stream)
221 return false;
Greg Thompson3f7e20f42020-05-02 19:01:11222 // Seeking to the beginning is best-effort -- it is expected to fail for
223 // certain non-file stream (e.g., pipes).
224 HANDLE_EINTR(fseek(stream, 0, SEEK_SET));
225
226 // Many files have incorrect size (proc files etc). Hence, the file is read
227 // sequentially as opposed to a one-shot read, using file size as a hint for
228 // chunk size if available.
Mikhail Istomin1ede1552018-05-16 17:40:24229 constexpr int64_t kDefaultChunkSize = 1 << 16;
Greg Thompson3f7e20f42020-05-02 19:01:11230 int64_t chunk_size = kDefaultChunkSize - 1;
Greg Thompson3f7e20f42020-05-02 19:01:11231 ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
Xiaohan Wangb705a64a2022-01-15 18:31:13232#if BUILDFLAG(IS_WIN)
Greg Thompson3f7e20f42020-05-02 19:01:11233 BY_HANDLE_FILE_INFORMATION file_info = {};
234 if (::GetFileInformationByHandle(
235 reinterpret_cast<HANDLE>(_get_osfhandle(_fileno(stream))),
236 &file_info)) {
237 LARGE_INTEGER size;
238 size.HighPart = file_info.nFileSizeHigh;
239 size.LowPart = file_info.nFileSizeLow;
240 if (size.QuadPart > 0)
241 chunk_size = size.QuadPart;
242 }
Xiaohan Wangb705a64a2022-01-15 18:31:13243#else // BUILDFLAG(IS_WIN)
Anand K Mistry53fa72d2021-07-15 01:15:26244 // In cases where the reported file size is 0, use a smaller chunk size to
245 // minimize memory allocated and cost of string::resize() in case the read
246 // size is small (i.e. proc files). If the file is larger than this, the read
247 // loop will reset |chunk_size| to kDefaultChunkSize.
248 constexpr int64_t kSmallChunkSize = 4096;
249 chunk_size = kSmallChunkSize - 1;
Greg Thompson3f7e20f42020-05-02 19:01:11250 stat_wrapper_t file_info = {};
251 if (!File::Fstat(fileno(stream), &file_info) && file_info.st_size > 0)
252 chunk_size = file_info.st_size;
Xiaohan Wangb705a64a2022-01-15 18:31:13253#endif // BUILDFLAG(IS_WIN)
Mikhail Istomin1ede1552018-05-16 17:40:24254 // We need to attempt to read at EOF for feof flag to be set so here we
255 // use |chunk_size| + 1.
256 chunk_size = std::min<uint64_t>(chunk_size, max_size) + 1;
Mikhail Istomin1ede1552018-05-16 17:40:24257 size_t bytes_read_this_pass;
258 size_t bytes_read_so_far = 0;
259 bool read_status = true;
260 std::string local_contents;
261 local_contents.resize(chunk_size);
kaliamoorthi@chromium.org0710fdd2014-02-18 16:31:51262
Mikhail Istomin1ede1552018-05-16 17:40:24263 while ((bytes_read_this_pass = fread(&local_contents[bytes_read_so_far], 1,
Greg Thompson3f7e20f42020-05-02 19:01:11264 chunk_size, stream)) > 0) {
Mikhail Istomin1ede1552018-05-16 17:40:24265 if ((max_size - bytes_read_so_far) < bytes_read_this_pass) {
266 // Read more than max_size bytes, bail out.
267 bytes_read_so_far = max_size;
kaliamoorthi@chromium.org0710fdd2014-02-18 16:31:51268 read_status = false;
269 break;
270 }
Mikhail Istomin1ede1552018-05-16 17:40:24271 // In case EOF was not reached, iterate again but revert to the default
272 // chunk size.
273 if (bytes_read_so_far == 0)
274 chunk_size = kDefaultChunkSize;
kaliamoorthi@chromium.org0710fdd2014-02-18 16:31:51275
Mikhail Istomin1ede1552018-05-16 17:40:24276 bytes_read_so_far += bytes_read_this_pass;
277 // Last fread syscall (after EOF) can be avoided via feof, which is just a
278 // flag check.
Greg Thompson3f7e20f42020-05-02 19:01:11279 if (feof(stream))
Mikhail Istomin1ede1552018-05-16 17:40:24280 break;
281 local_contents.resize(bytes_read_so_far + chunk_size);
initial.commitd7cae122008-07-26 21:49:38282 }
Greg Thompson3f7e20f42020-05-02 19:01:11283 read_status = read_status && !ferror(stream);
Mikhail Istomin1ede1552018-05-16 17:40:24284 if (contents) {
285 contents->swap(local_contents);
286 contents->resize(bytes_read_so_far);
287 }
initial.commitd7cae122008-07-26 21:49:38288
kaliamoorthi@chromium.org0710fdd2014-02-18 16:31:51289 return read_status;
290}
291
292bool ReadFileToString(const FilePath& path, std::string* contents) {
hashimoto6da2fef2016-02-24 03:39:58293 return ReadFileToStringWithMaxSize(path, contents,
294 std::numeric_limits<size_t>::max());
initial.commitd7cae122008-07-26 21:49:38295}
296
Greg Thompson3f7e20f42020-05-02 19:01:11297bool ReadFileToStringWithMaxSize(const FilePath& path,
298 std::string* contents,
299 size_t max_size) {
300 if (contents)
301 contents->clear();
302 if (path.ReferencesParent())
303 return false;
304 ScopedFILE file_stream(OpenFile(path, "rb"));
305 if (!file_stream)
306 return false;
307 return ReadStreamToStringWithMaxSize(file_stream.get(), max_size, contents);
308}
309
brettw@chromium.orgfb4bcfa32013-12-02 18:55:49310bool IsDirectoryEmpty(const FilePath& dir_path) {
311 FileEnumerator files(dir_path, false,
312 FileEnumerator::FILES | FileEnumerator::DIRECTORIES);
313 if (files.Next().empty())
314 return true;
315 return false;
316}
317
Greg Thompson3f7e20f42020-05-02 19:01:11318bool CreateTemporaryFile(FilePath* path) {
319 FilePath temp_dir;
320 return GetTempDir(&temp_dir) && CreateTemporaryFileInDir(temp_dir, path);
321}
322
Greg Thompsonf75f5fb2020-04-30 08:13:25323ScopedFILE CreateAndOpenTemporaryStream(FilePath* path) {
brettw@chromium.org03d9afc02013-12-03 17:55:52324 FilePath directory;
325 if (!GetTempDir(&directory))
Ivan Kotenkova16212a52017-11-08 12:37:33326 return nullptr;
brettw@chromium.org03d9afc02013-12-03 17:55:52327
Greg Thompsonf75f5fb2020-04-30 08:13:25328 return CreateAndOpenTemporaryStreamInDir(directory, path);
brettw@chromium.org03d9afc02013-12-03 17:55:52329}
330
brettw@chromium.org426d1c92013-12-03 20:08:54331bool CreateDirectory(const FilePath& full_path) {
Ivan Kotenkova16212a52017-11-08 12:37:33332 return CreateDirectoryAndGetError(full_path, nullptr);
brettw@chromium.org426d1c92013-12-03 20:08:54333}
334
avi543540e2015-12-24 05:15:32335bool GetFileSize(const FilePath& file_path, int64_t* file_size) {
rvargas@chromium.org54124ed02014-01-07 10:06:58336 File::Info info;
brettw@chromium.org9eae4e62013-12-04 20:56:49337 if (!GetFileInfo(file_path, &info))
brettw@chromium.org56285702013-12-04 18:22:49338 return false;
339 *file_size = info.size;
340 return true;
341}
342
brettw@chromium.orgc0d508162013-12-04 22:49:00343bool TouchFile(const FilePath& path,
344 const Time& last_accessed,
345 const Time& last_modified) {
Alexei Svitkine670d67ee2021-11-01 21:51:49346 int flags = File::FLAG_OPEN | File::FLAG_WRITE_ATTRIBUTES;
brettw@chromium.orgc0d508162013-12-04 22:49:00347
Xiaohan Wangb705a64a2022-01-15 18:31:13348#if BUILDFLAG(IS_WIN)
brettw@chromium.orgc0d508162013-12-04 22:49:00349 // On Windows, FILE_FLAG_BACKUP_SEMANTICS is needed to open a directory.
350 if (DirectoryExists(path))
Alexei Svitkinec417b2cd2021-10-21 14:22:40351 flags |= File::FLAG_WIN_BACKUP_SEMANTICS;
Xiaohan Wangb705a64a2022-01-15 18:31:13352#elif BUILDFLAG(IS_FUCHSIA)
Wez432ea8d892019-03-31 01:17:08353 // On Fuchsia, we need O_RDONLY for directories, or O_WRONLY for files.
354 // TODO(https://crbug.com/947802): Find a cleaner workaround for this.
355 flags |= (DirectoryExists(path) ? File::FLAG_READ : File::FLAG_WRITE);
356#endif
brettw@chromium.orgc0d508162013-12-04 22:49:00357
rvargas@chromium.org54124ed02014-01-07 10:06:58358 File file(path, flags);
359 if (!file.IsValid())
360 return false;
brettw@chromium.orgc0d508162013-12-04 22:49:00361
rvargas@chromium.org54124ed02014-01-07 10:06:58362 return file.SetTimes(last_accessed, last_modified);
brettw@chromium.orgc0d508162013-12-04 22:49:00363}
364
mark@chromium.org836f1342008-10-01 17:40:13365bool CloseFile(FILE* file) {
Ivan Kotenkova16212a52017-11-08 12:37:33366 if (file == nullptr)
sidchat@google.coma1a19502008-10-21 17:14:45367 return true;
mark@chromium.org836f1342008-10-01 17:40:13368 return fclose(file) == 0;
369}
370
jeremy@chromium.orgc2c998c2009-01-27 19:08:39371bool TruncateFile(FILE* file) {
Ivan Kotenkova16212a52017-11-08 12:37:33372 if (file == nullptr)
jeremy@chromium.orgc2c998c2009-01-27 19:08:39373 return false;
374 long current_offset = ftell(file);
375 if (current_offset == -1)
376 return false;
Xiaohan Wangb705a64a2022-01-15 18:31:13377#if BUILDFLAG(IS_WIN)
jeremy@chromium.orgc2c998c2009-01-27 19:08:39378 int fd = _fileno(file);
379 if (_chsize(fd, current_offset) != 0)
380 return false;
381#else
382 int fd = fileno(file);
383 if (ftruncate(fd, current_offset) != 0)
384 return false;
385#endif
386 return true;
387}
388
Lei Zhangeebbef62020-05-05 20:16:05389bool WriteFile(const FilePath& filename, span<const uint8_t> data) {
390 int size = checked_cast<int>(data.size());
391 return WriteFile(filename, reinterpret_cast<const char*>(data.data()),
392 size) == size;
393}
394
395bool WriteFile(const FilePath& filename, StringPiece data) {
396 int size = checked_cast<int>(data.size());
397 return WriteFile(filename, data.data(), size) == size;
398}
399
Greg Thompsonb4abcb42019-08-23 01:42:56400int GetUniquePathNumber(const FilePath& path) {
401 DCHECK(!path.empty());
402 if (!PathExists(path))
Greg Thompson42373544a2019-08-14 10:11:10403 return 0;
404
405 std::string number;
406 for (int count = 1; count <= kMaxUniqueFiles; ++count) {
407 StringAppendF(&number, " (%d)", count);
Greg Thompsonb4abcb42019-08-23 01:42:56408 if (!PathExists(path.InsertBeforeExtensionASCII(number)))
Greg Thompson42373544a2019-08-14 10:11:10409 return count;
410 number.clear();
jam@chromium.orge285afa2012-01-31 23:16:39411 }
412
413 return -1;
414}
Bruce Longd096e482019-02-28 17:50:00415
416FilePath GetUniquePath(const FilePath& path) {
Greg Thompsonb4abcb42019-08-23 01:42:56417 DCHECK(!path.empty());
418 const int uniquifier = GetUniquePathNumber(path);
419 if (uniquifier > 0)
420 return path.InsertBeforeExtensionASCII(StringPrintf(" (%d)", uniquifier));
Xiaohan Wang12bd22202022-05-19 15:38:02421 return uniquifier == 0 ? path : FilePath();
Bruce Longd096e482019-02-28 17:50:00422}
Victor Costanb5a0a97002019-09-08 04:55:15423
424namespace internal {
425
426bool PreReadFileSlow(const FilePath& file_path, int64_t max_bytes) {
427 DCHECK_GE(max_bytes, 0);
428
429 File file(file_path, File::FLAG_OPEN | File::FLAG_READ |
Alexei Svitkinec417b2cd2021-10-21 14:22:40430 File::FLAG_WIN_SEQUENTIAL_SCAN |
431 File::FLAG_WIN_SHARE_DELETE);
Victor Costanb5a0a97002019-09-08 04:55:15432 if (!file.IsValid())
433 return false;
434
435 constexpr int kBufferSize = 1024 * 1024;
436 // Ensures the buffer is deallocated at function exit.
437 std::unique_ptr<char[]> buffer_deleter(new char[kBufferSize]);
438 char* const buffer = buffer_deleter.get();
439
440 while (max_bytes > 0) {
441 // The static_cast<int> is safe because kBufferSize is int, and both values
442 // are non-negative. So, the minimum is guaranteed to fit in int.
443 const int read_size =
444 static_cast<int>(std::min<int64_t>(max_bytes, kBufferSize));
445 DCHECK_GE(read_size, 0);
446 DCHECK_LE(read_size, kBufferSize);
447
448 const int read_bytes = file.ReadAtCurrentPos(buffer, read_size);
449 if (read_bytes < 0)
450 return false;
451 if (read_bytes == 0)
452 break;
453
454 max_bytes -= read_bytes;
455 }
456
457 return true;
458}
459
460} // namespace internal
461
brettw@chromium.orga26f4ae2014-03-13 17:26:21462} // namespace base