[go: nahoru, domu]

blob: 4c25acf1d63309776341b879c04f540cf63aed28 [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>
initial.commitd7cae122008-07-26 21:49:3814
brettw@chromium.org25a4c1c2013-06-08 04:53:3615#include "base/files/file_enumerator.h"
brettw@chromium.org57999812013-02-24 05:40:5216#include "base/files/file_path.h"
initial.commitd7cae122008-07-26 21:49:3817#include "base/logging.h"
tfarina@chromium.orgeb62f7262013-03-30 14:29:0018#include "base/strings/string_piece.h"
avi@chromium.org251cd6e52013-06-11 13:36:3719#include "base/strings/string_util.h"
20#include "base/strings/stringprintf.h"
avi@chromium.orga4ea1f12013-06-07 18:37:0721#include "base/strings/utf_string_conversions.h"
Etienne Pierre-Doray1da58592018-09-21 14:47:2022#include "base/threading/scoped_blocking_call.h"
avi543540e2015-12-24 05:15:3223#include "build/build_config.h"
estade@chromium.orgb9e04f02008-11-27 04:03:5724
brettw@chromium.org0408c752013-06-22 22:15:4625namespace base {
brettw@chromium.org04af979a2013-02-16 04:12:2626
hidehiko8fc7c822015-06-09 02:50:5727#if !defined(OS_NACL_NONSFI)
estade@chromium.orgceeb87e2008-12-04 20:46:0628namespace {
29
jam@chromium.orge285afa2012-01-31 23:16:3930// The maximum number of 'uniquified' files we will try to create.
31// This is used when the filename we're trying to download is already in use,
32// so we create a new unique filename by appending " (nnn)" before the
33// extension, where 1 <= nnn <= kMaxUniqueFiles.
34// Also used by code that cleans up said files.
35static const int kMaxUniqueFiles = 100;
36
willchan@chromium.orgc145cbdd2009-04-24 17:44:3937} // namespace
estade@chromium.orgceeb87e2008-12-04 20:46:0638
avi543540e2015-12-24 05:15:3239int64_t ComputeDirectorySize(const FilePath& root_path) {
40 int64_t running_size = 0;
brettw@chromium.org0408c752013-06-22 22:15:4641 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
evanm@google.com640517f2008-10-30 23:54:0453bool ContentsEqual(const FilePath& filename1, const FilePath& filename2) {
initial.commitd7cae122008-07-26 21:49:3854 // We open the file in binary format even if they are text files because
55 // we are just comparing that bytes are exactly same in both files and not
56 // doing anything smart with text formatting.
jdoerrie983968a2019-01-29 12:54:4157#if defined(OS_WIN)
58 std::ifstream file1(base::wdata(filename1.value()),
erikkay@google.com5af2edb92008-08-08 20:16:0859 std::ios::in | std::ios::binary);
jdoerrie983968a2019-01-29 12:54:4160 std::ifstream file2(base::wdata(filename2.value()),
erikkay@google.com5af2edb92008-08-08 20:16:0861 std::ios::in | std::ios::binary);
jdoerrie983968a2019-01-29 12:54:4162#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
63 std::ifstream file1(filename1.value(), std::ios::in | std::ios::binary);
64 std::ifstream file2(filename2.value(), std::ios::in | std::ios::binary);
65#endif // OS_WIN
estade@chromium.orgb9e04f02008-11-27 04:03:5766
initial.commitd7cae122008-07-26 21:49:3867 // Even if both files aren't openable (and thus, in some sense, "equal"),
68 // any unusable file yields a result of "false".
69 if (!file1.is_open() || !file2.is_open())
70 return false;
71
72 const int BUFFER_SIZE = 2056;
73 char buffer1[BUFFER_SIZE], buffer2[BUFFER_SIZE];
74 do {
75 file1.read(buffer1, BUFFER_SIZE);
76 file2.read(buffer2, BUFFER_SIZE);
77
mark@chromium.orgb81637c32009-06-26 21:17:2478 if ((file1.eof() != file2.eof()) ||
initial.commitd7cae122008-07-26 21:49:3879 (file1.gcount() != file2.gcount()) ||
pkasting9cf9b942014-10-01 22:18:4380 (memcmp(buffer1, buffer2, static_cast<size_t>(file1.gcount())))) {
initial.commitd7cae122008-07-26 21:49:3881 file1.close();
82 file2.close();
83 return false;
84 }
mark@chromium.orgb81637c32009-06-26 21:17:2485 } while (!file1.eof() || !file2.eof());
initial.commitd7cae122008-07-26 21:49:3886
87 file1.close();
88 file2.close();
89 return true;
90}
91
mark@chromium.orgb81637c32009-06-26 21:17:2492bool TextContentsEqual(const FilePath& filename1, const FilePath& filename2) {
jdoerrie983968a2019-01-29 12:54:4193#if defined(OS_WIN)
94 std::ifstream file1(base::wdata(filename1.value()), std::ios::in);
95 std::ifstream file2(base::wdata(filename2.value()), std::ios::in);
96#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
97 std::ifstream file1(filename1.value(), std::ios::in);
98 std::ifstream file2(filename2.value(), std::ios::in);
99#endif // OS_WIN
mark@chromium.orgb81637c32009-06-26 21:17:24100
101 // Even if both files aren't openable (and thus, in some sense, "equal"),
102 // any unusable file yields a result of "false".
103 if (!file1.is_open() || !file2.is_open())
104 return false;
105
106 do {
107 std::string line1, line2;
108 getline(file1, line1);
109 getline(file2, line2);
110
111 // Check for mismatched EOF states, or any error state.
112 if ((file1.eof() != file2.eof()) ||
113 file1.bad() || file2.bad()) {
114 return false;
115 }
116
117 // Trim all '\r' and '\n' characters from the end of the line.
118 std::string::size_type end1 = line1.find_last_not_of("\r\n");
119 if (end1 == std::string::npos)
120 line1.clear();
121 else if (end1 + 1 < line1.length())
122 line1.erase(end1 + 1);
123
124 std::string::size_type end2 = line2.find_last_not_of("\r\n");
125 if (end2 == std::string::npos)
126 line2.clear();
127 else if (end2 + 1 < line2.length())
128 line2.erase(end2 + 1);
129
130 if (line1 != line2)
131 return false;
132 } while (!file1.eof() || !file2.eof());
133
134 return true;
135}
hidehiko8fc7c822015-06-09 02:50:57136#endif // !defined(OS_NACL_NONSFI)
mark@chromium.orgb81637c32009-06-26 21:17:24137
hashimoto6da2fef2016-02-24 03:39:58138bool ReadFileToStringWithMaxSize(const FilePath& path,
139 std::string* contents,
140 size_t max_size) {
kaliamoorthi@chromium.org0710fdd2014-02-18 16:31:51141 if (contents)
142 contents->clear();
cpu@chromium.org9fea5a92013-01-09 00:38:59143 if (path.ReferencesParent())
144 return false;
thakis@chromium.org7600d0b2013-12-08 21:43:30145 FILE* file = OpenFile(path, "rb");
mark@chromium.org836f1342008-10-01 17:40:13146 if (!file) {
initial.commitd7cae122008-07-26 21:49:38147 return false;
mark@chromium.org836f1342008-10-01 17:40:13148 }
initial.commitd7cae122008-07-26 21:49:38149
kaliamoorthi@chromium.org0710fdd2014-02-18 16:31:51150 // Many files supplied in |path| have incorrect size (proc files etc).
Mikhail Istomin1ede1552018-05-16 17:40:24151 // Hence, the file is read sequentially as opposed to a one-shot read, using
152 // file size as a hint for chunk size if available.
153 constexpr int64_t kDefaultChunkSize = 1 << 16;
154 int64_t chunk_size;
155#if !defined(OS_NACL_NONSFI)
156 if (!GetFileSize(path, &chunk_size) || chunk_size <= 0)
157 chunk_size = kDefaultChunkSize - 1;
158 // We need to attempt to read at EOF for feof flag to be set so here we
159 // use |chunk_size| + 1.
160 chunk_size = std::min<uint64_t>(chunk_size, max_size) + 1;
161#else
162 chunk_size = kDefaultChunkSize;
163#endif // !defined(OS_NACL_NONSFI)
164 size_t bytes_read_this_pass;
165 size_t bytes_read_so_far = 0;
166 bool read_status = true;
167 std::string local_contents;
168 local_contents.resize(chunk_size);
kaliamoorthi@chromium.org0710fdd2014-02-18 16:31:51169
Etienne Pierre-Doray1da58592018-09-21 14:47:20170 ScopedBlockingCall scoped_blocking_call(BlockingType::MAY_BLOCK);
Mikhail Istomin1ede1552018-05-16 17:40:24171 while ((bytes_read_this_pass = fread(&local_contents[bytes_read_so_far], 1,
172 chunk_size, file)) > 0) {
173 if ((max_size - bytes_read_so_far) < bytes_read_this_pass) {
174 // Read more than max_size bytes, bail out.
175 bytes_read_so_far = max_size;
kaliamoorthi@chromium.org0710fdd2014-02-18 16:31:51176 read_status = false;
177 break;
178 }
Mikhail Istomin1ede1552018-05-16 17:40:24179 // In case EOF was not reached, iterate again but revert to the default
180 // chunk size.
181 if (bytes_read_so_far == 0)
182 chunk_size = kDefaultChunkSize;
kaliamoorthi@chromium.org0710fdd2014-02-18 16:31:51183
Mikhail Istomin1ede1552018-05-16 17:40:24184 bytes_read_so_far += bytes_read_this_pass;
185 // Last fread syscall (after EOF) can be avoided via feof, which is just a
186 // flag check.
187 if (feof(file))
188 break;
189 local_contents.resize(bytes_read_so_far + chunk_size);
initial.commitd7cae122008-07-26 21:49:38190 }
tnagel@chromium.org731daa12014-05-01 10:40:51191 read_status = read_status && !ferror(file);
thakis@chromium.org7600d0b2013-12-08 21:43:30192 CloseFile(file);
Mikhail Istomin1ede1552018-05-16 17:40:24193 if (contents) {
194 contents->swap(local_contents);
195 contents->resize(bytes_read_so_far);
196 }
initial.commitd7cae122008-07-26 21:49:38197
kaliamoorthi@chromium.org0710fdd2014-02-18 16:31:51198 return read_status;
199}
200
201bool ReadFileToString(const FilePath& path, std::string* contents) {
hashimoto6da2fef2016-02-24 03:39:58202 return ReadFileToStringWithMaxSize(path, contents,
203 std::numeric_limits<size_t>::max());
initial.commitd7cae122008-07-26 21:49:38204}
205
hidehiko8fc7c822015-06-09 02:50:57206#if !defined(OS_NACL_NONSFI)
brettw@chromium.orgfb4bcfa32013-12-02 18:55:49207bool IsDirectoryEmpty(const FilePath& dir_path) {
208 FileEnumerator files(dir_path, false,
209 FileEnumerator::FILES | FileEnumerator::DIRECTORIES);
210 if (files.Next().empty())
211 return true;
212 return false;
213}
214
brettw@chromium.org03d9afc02013-12-03 17:55:52215FILE* CreateAndOpenTemporaryFile(FilePath* path) {
216 FilePath directory;
217 if (!GetTempDir(&directory))
Ivan Kotenkova16212a52017-11-08 12:37:33218 return nullptr;
brettw@chromium.org03d9afc02013-12-03 17:55:52219
220 return CreateAndOpenTemporaryFileInDir(directory, path);
221}
222
brettw@chromium.org426d1c92013-12-03 20:08:54223bool CreateDirectory(const FilePath& full_path) {
Ivan Kotenkova16212a52017-11-08 12:37:33224 return CreateDirectoryAndGetError(full_path, nullptr);
brettw@chromium.org426d1c92013-12-03 20:08:54225}
226
avi543540e2015-12-24 05:15:32227bool GetFileSize(const FilePath& file_path, int64_t* file_size) {
rvargas@chromium.org54124ed02014-01-07 10:06:58228 File::Info info;
brettw@chromium.org9eae4e62013-12-04 20:56:49229 if (!GetFileInfo(file_path, &info))
brettw@chromium.org56285702013-12-04 18:22:49230 return false;
231 *file_size = info.size;
232 return true;
233}
234
brettw@chromium.orgc0d508162013-12-04 22:49:00235bool TouchFile(const FilePath& path,
236 const Time& last_accessed,
237 const Time& last_modified) {
rvargas@chromium.org54124ed02014-01-07 10:06:58238 int flags = File::FLAG_OPEN | File::FLAG_WRITE_ATTRIBUTES;
brettw@chromium.orgc0d508162013-12-04 22:49:00239
240#if defined(OS_WIN)
241 // On Windows, FILE_FLAG_BACKUP_SEMANTICS is needed to open a directory.
242 if (DirectoryExists(path))
rvargas@chromium.org54124ed02014-01-07 10:06:58243 flags |= File::FLAG_BACKUP_SEMANTICS;
brettw@chromium.orgc0d508162013-12-04 22:49:00244#endif // OS_WIN
245
rvargas@chromium.org54124ed02014-01-07 10:06:58246 File file(path, flags);
247 if (!file.IsValid())
248 return false;
brettw@chromium.orgc0d508162013-12-04 22:49:00249
rvargas@chromium.org54124ed02014-01-07 10:06:58250 return file.SetTimes(last_accessed, last_modified);
brettw@chromium.orgc0d508162013-12-04 22:49:00251}
hidehiko8fc7c822015-06-09 02:50:57252#endif // !defined(OS_NACL_NONSFI)
brettw@chromium.orgc0d508162013-12-04 22:49:00253
mark@chromium.org836f1342008-10-01 17:40:13254bool CloseFile(FILE* file) {
Ivan Kotenkova16212a52017-11-08 12:37:33255 if (file == nullptr)
sidchat@google.coma1a19502008-10-21 17:14:45256 return true;
mark@chromium.org836f1342008-10-01 17:40:13257 return fclose(file) == 0;
258}
259
hidehiko8fc7c822015-06-09 02:50:57260#if !defined(OS_NACL_NONSFI)
jeremy@chromium.orgc2c998c2009-01-27 19:08:39261bool TruncateFile(FILE* file) {
Ivan Kotenkova16212a52017-11-08 12:37:33262 if (file == nullptr)
jeremy@chromium.orgc2c998c2009-01-27 19:08:39263 return false;
264 long current_offset = ftell(file);
265 if (current_offset == -1)
266 return false;
267#if defined(OS_WIN)
268 int fd = _fileno(file);
269 if (_chsize(fd, current_offset) != 0)
270 return false;
271#else
272 int fd = fileno(file);
273 if (ftruncate(fd, current_offset) != 0)
274 return false;
275#endif
276 return true;
277}
278
brettw@chromium.orga26f4ae2014-03-13 17:26:21279int GetUniquePathNumber(const FilePath& path,
280 const FilePath::StringType& suffix) {
jam@chromium.orge285afa2012-01-31 23:16:39281 bool have_suffix = !suffix.empty();
282 if (!PathExists(path) &&
283 (!have_suffix || !PathExists(FilePath(path.value() + suffix)))) {
284 return 0;
285 }
286
287 FilePath new_path;
288 for (int count = 1; count <= kMaxUniqueFiles; ++count) {
brettw@chromium.orga26f4ae2014-03-13 17:26:21289 new_path = path.InsertBeforeExtensionASCII(StringPrintf(" (%d)", count));
jam@chromium.orge285afa2012-01-31 23:16:39290 if (!PathExists(new_path) &&
291 (!have_suffix || !PathExists(FilePath(new_path.value() + suffix)))) {
292 return count;
293 }
294 }
295
296 return -1;
297}
hidehiko8fc7c822015-06-09 02:50:57298#endif // !defined(OS_NACL_NONSFI)
jam@chromium.orge285afa2012-01-31 23:16:39299
brettw@chromium.orga26f4ae2014-03-13 17:26:21300} // namespace base