blob: c1bf50abc45f720bca415d1bc56d5fb9bf35abda [file] [log] [blame]
thestig@chromium.orgf1a9ce12012-03-03 10:54:35 +09001// Copyright (c) 2012 The Chromium Authors. All rights reserved.
license.botf003cfe2008-08-24 09:55:55 +09002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit3f4a7322008-07-27 06:49:38 +09004
5#include "base/file_util.h"
6
jeremy@chromium.orga5f404d2009-01-28 04:08:39 +09007#if defined(OS_WIN)
8#include <io.h>
9#endif
mark@chromium.orgd1bafc62008-10-02 02:40:13 +090010#include <stdio.h>
11
initial.commit3f4a7322008-07-27 06:49:38 +090012#include <fstream>
kaliamoorthi@chromium.org8d3c40d2014-02-19 01:31:51 +090013#include <limits>
initial.commit3f4a7322008-07-27 06:49:38 +090014
brettw@chromium.org56946722013-06-08 13:53:36 +090015#include "base/files/file_enumerator.h"
brettw@chromium.org59eef1f2013-02-24 14:40:52 +090016#include "base/files/file_path.h"
initial.commit3f4a7322008-07-27 06:49:38 +090017#include "base/logging.h"
tfarina@chromium.orgb6d49112013-03-30 23:29:00 +090018#include "base/strings/string_piece.h"
avi@chromium.org94bd5732013-06-11 22:36:37 +090019#include "base/strings/string_util.h"
20#include "base/strings/stringprintf.h"
avi@chromium.org17f60622013-06-08 03:37:07 +090021#include "base/strings/utf_string_conversions.h"
estade@chromium.org97e37822008-11-27 13:03:57 +090022
brettw@chromium.org55d5ee62013-06-23 07:15:46 +090023namespace base {
brettw@chromium.orgc02b6032013-02-16 13:12:26 +090024
estade@chromium.org63343202008-12-05 05:46:06 +090025namespace {
26
jam@chromium.orgc693fe32012-02-01 08:16:39 +090027// The maximum number of 'uniquified' files we will try to create.
28// This is used when the filename we're trying to download is already in use,
29// so we create a new unique filename by appending " (nnn)" before the
30// extension, where 1 <= nnn <= kMaxUniqueFiles.
31// Also used by code that cleans up said files.
32static const int kMaxUniqueFiles = 100;
33
willchan@chromium.org2f0b26b2009-04-25 02:44:39 +090034} // namespace
estade@chromium.org63343202008-12-05 05:46:06 +090035
brettw@chromium.org55d5ee62013-06-23 07:15:46 +090036int64 ComputeDirectorySize(const FilePath& root_path) {
37 int64 running_size = 0;
38 FileEnumerator file_iter(root_path, true, FileEnumerator::FILES);
39 while (!file_iter.Next().empty())
40 running_size += file_iter.GetInfo().GetSize();
41 return running_size;
42}
43
brettw@chromium.org0878fea2013-07-02 08:07:36 +090044bool Move(const FilePath& from_path, const FilePath& to_path) {
45 if (from_path.ReferencesParent() || to_path.ReferencesParent())
46 return false;
brettw@chromium.orgaecf7a32013-07-10 02:42:26 +090047 return internal::MoveUnsafe(from_path, to_path);
48}
49
50bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
51 if (from_path.ReferencesParent() || to_path.ReferencesParent())
52 return false;
53 return internal::CopyFileUnsafe(from_path, to_path);
brettw@chromium.org0878fea2013-07-02 08:07:36 +090054}
55
evanm@google.com874d1672008-10-31 08:54:04 +090056bool ContentsEqual(const FilePath& filename1, const FilePath& filename2) {
initial.commit3f4a7322008-07-27 06:49:38 +090057 // 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.
evanm@google.com874d1672008-10-31 08:54:04 +090060 std::ifstream file1(filename1.value().c_str(),
erikkay@google.com9fc57d02008-08-09 05:16:08 +090061 std::ios::in | std::ios::binary);
evanm@google.com874d1672008-10-31 08:54:04 +090062 std::ifstream file2(filename2.value().c_str(),
erikkay@google.com9fc57d02008-08-09 05:16:08 +090063 std::ios::in | std::ios::binary);
estade@chromium.org97e37822008-11-27 13:03:57 +090064
initial.commit3f4a7322008-07-27 06:49:38 +090065 // Even if both files aren't openable (and thus, in some sense, "equal"),
66 // any unusable file yields a result of "false".
67 if (!file1.is_open() || !file2.is_open())
68 return false;
69
70 const int BUFFER_SIZE = 2056;
71 char buffer1[BUFFER_SIZE], buffer2[BUFFER_SIZE];
72 do {
73 file1.read(buffer1, BUFFER_SIZE);
74 file2.read(buffer2, BUFFER_SIZE);
75
mark@chromium.org95c9ec92009-06-27 06:17:24 +090076 if ((file1.eof() != file2.eof()) ||
initial.commit3f4a7322008-07-27 06:49:38 +090077 (file1.gcount() != file2.gcount()) ||
78 (memcmp(buffer1, buffer2, file1.gcount()))) {
79 file1.close();
80 file2.close();
81 return false;
82 }
mark@chromium.org95c9ec92009-06-27 06:17:24 +090083 } while (!file1.eof() || !file2.eof());
initial.commit3f4a7322008-07-27 06:49:38 +090084
85 file1.close();
86 file2.close();
87 return true;
88}
89
mark@chromium.org95c9ec92009-06-27 06:17:24 +090090bool TextContentsEqual(const FilePath& filename1, const FilePath& filename2) {
91 std::ifstream file1(filename1.value().c_str(), std::ios::in);
92 std::ifstream file2(filename2.value().c_str(), std::ios::in);
93
94 // Even if both files aren't openable (and thus, in some sense, "equal"),
95 // any unusable file yields a result of "false".
96 if (!file1.is_open() || !file2.is_open())
97 return false;
98
99 do {
100 std::string line1, line2;
101 getline(file1, line1);
102 getline(file2, line2);
103
104 // Check for mismatched EOF states, or any error state.
105 if ((file1.eof() != file2.eof()) ||
106 file1.bad() || file2.bad()) {
107 return false;
108 }
109
110 // Trim all '\r' and '\n' characters from the end of the line.
111 std::string::size_type end1 = line1.find_last_not_of("\r\n");
112 if (end1 == std::string::npos)
113 line1.clear();
114 else if (end1 + 1 < line1.length())
115 line1.erase(end1 + 1);
116
117 std::string::size_type end2 = line2.find_last_not_of("\r\n");
118 if (end2 == std::string::npos)
119 line2.clear();
120 else if (end2 + 1 < line2.length())
121 line2.erase(end2 + 1);
122
123 if (line1 != line2)
124 return false;
125 } while (!file1.eof() || !file2.eof());
126
127 return true;
128}
129
kaliamoorthi@chromium.org8d3c40d2014-02-19 01:31:51 +0900130bool ReadFileToString(const FilePath& path,
131 std::string* contents,
132 size_t max_size) {
133 if (contents)
134 contents->clear();
cpu@chromium.org93db53b2013-01-09 09:38:59 +0900135 if (path.ReferencesParent())
136 return false;
thakis@chromium.orgf01de7e2013-12-09 06:43:30 +0900137 FILE* file = OpenFile(path, "rb");
mark@chromium.orgd1bafc62008-10-02 02:40:13 +0900138 if (!file) {
initial.commit3f4a7322008-07-27 06:49:38 +0900139 return false;
mark@chromium.orgd1bafc62008-10-02 02:40:13 +0900140 }
initial.commit3f4a7322008-07-27 06:49:38 +0900141
142 char buf[1 << 16];
143 size_t len;
kaliamoorthi@chromium.org8d3c40d2014-02-19 01:31:51 +0900144 size_t size = 0;
145 bool read_status = true;
146
147 // Many files supplied in |path| have incorrect size (proc files etc).
148 // Hence, the file is read sequentially as opposed to a one-shot read.
initial.commit3f4a7322008-07-27 06:49:38 +0900149 while ((len = fread(buf, 1, sizeof(buf), file)) > 0) {
evan@chromium.orga75b2e82010-05-19 20:07:55 +0900150 if (contents)
kaliamoorthi@chromium.org8d3c40d2014-02-19 01:31:51 +0900151 contents->append(buf, std::min(len, max_size - size));
152
153 if ((max_size - size) < len) {
154 read_status = false;
155 break;
156 }
157
158 size += len;
initial.commit3f4a7322008-07-27 06:49:38 +0900159 }
thakis@chromium.orgf01de7e2013-12-09 06:43:30 +0900160 CloseFile(file);
initial.commit3f4a7322008-07-27 06:49:38 +0900161
kaliamoorthi@chromium.org8d3c40d2014-02-19 01:31:51 +0900162 return read_status;
163}
164
165bool ReadFileToString(const FilePath& path, std::string* contents) {
166 return ReadFileToString(path, contents, std::numeric_limits<size_t>::max());
initial.commit3f4a7322008-07-27 06:49:38 +0900167}
168
brettw@chromium.org83c44c82013-12-03 03:55:49 +0900169bool IsDirectoryEmpty(const FilePath& dir_path) {
170 FileEnumerator files(dir_path, false,
171 FileEnumerator::FILES | FileEnumerator::DIRECTORIES);
172 if (files.Next().empty())
173 return true;
174 return false;
175}
176
brettw@chromium.org735d11d2013-12-04 02:55:52 +0900177FILE* CreateAndOpenTemporaryFile(FilePath* path) {
178 FilePath directory;
179 if (!GetTempDir(&directory))
180 return NULL;
181
182 return CreateAndOpenTemporaryFileInDir(directory, path);
183}
184
brettw@chromium.org738669a2013-12-04 05:08:54 +0900185bool CreateDirectory(const FilePath& full_path) {
186 return CreateDirectoryAndGetError(full_path, NULL);
187}
188
brettw@chromium.org70684242013-12-05 03:22:49 +0900189bool GetFileSize(const FilePath& file_path, int64* file_size) {
rvargas@chromium.orgb005b382014-01-07 19:06:58 +0900190 File::Info info;
brettw@chromium.orga9154032013-12-05 05:56:49 +0900191 if (!GetFileInfo(file_path, &info))
brettw@chromium.org70684242013-12-05 03:22:49 +0900192 return false;
193 *file_size = info.size;
194 return true;
195}
196
brettw@chromium.org458d1e32013-12-05 07:49:00 +0900197bool TouchFile(const FilePath& path,
198 const Time& last_accessed,
199 const Time& last_modified) {
rvargas@chromium.orgb005b382014-01-07 19:06:58 +0900200 int flags = File::FLAG_OPEN | File::FLAG_WRITE_ATTRIBUTES;
brettw@chromium.org458d1e32013-12-05 07:49:00 +0900201
202#if defined(OS_WIN)
203 // On Windows, FILE_FLAG_BACKUP_SEMANTICS is needed to open a directory.
204 if (DirectoryExists(path))
rvargas@chromium.orgb005b382014-01-07 19:06:58 +0900205 flags |= File::FLAG_BACKUP_SEMANTICS;
brettw@chromium.org458d1e32013-12-05 07:49:00 +0900206#endif // OS_WIN
207
rvargas@chromium.orgb005b382014-01-07 19:06:58 +0900208 File file(path, flags);
209 if (!file.IsValid())
210 return false;
brettw@chromium.org458d1e32013-12-05 07:49:00 +0900211
rvargas@chromium.orgb005b382014-01-07 19:06:58 +0900212 return file.SetTimes(last_accessed, last_modified);
brettw@chromium.org458d1e32013-12-05 07:49:00 +0900213}
214
mark@chromium.orgd1bafc62008-10-02 02:40:13 +0900215bool CloseFile(FILE* file) {
sidchat@google.comd3b26432008-10-22 02:14:45 +0900216 if (file == NULL)
217 return true;
mark@chromium.orgd1bafc62008-10-02 02:40:13 +0900218 return fclose(file) == 0;
219}
220
jeremy@chromium.orga5f404d2009-01-28 04:08:39 +0900221bool TruncateFile(FILE* file) {
222 if (file == NULL)
223 return false;
224 long current_offset = ftell(file);
225 if (current_offset == -1)
226 return false;
227#if defined(OS_WIN)
228 int fd = _fileno(file);
229 if (_chsize(fd, current_offset) != 0)
230 return false;
231#else
232 int fd = fileno(file);
233 if (ftruncate(fd, current_offset) != 0)
234 return false;
235#endif
236 return true;
237}
238
brettw@chromium.orgaa82a772014-03-14 02:26:21 +0900239int GetUniquePathNumber(const FilePath& path,
240 const FilePath::StringType& suffix) {
jam@chromium.orgc693fe32012-02-01 08:16:39 +0900241 bool have_suffix = !suffix.empty();
242 if (!PathExists(path) &&
243 (!have_suffix || !PathExists(FilePath(path.value() + suffix)))) {
244 return 0;
245 }
246
247 FilePath new_path;
248 for (int count = 1; count <= kMaxUniqueFiles; ++count) {
brettw@chromium.orgaa82a772014-03-14 02:26:21 +0900249 new_path = path.InsertBeforeExtensionASCII(StringPrintf(" (%d)", count));
jam@chromium.orgc693fe32012-02-01 08:16:39 +0900250 if (!PathExists(new_path) &&
251 (!have_suffix || !PathExists(FilePath(new_path.value() + suffix)))) {
252 return count;
253 }
254 }
255
256 return -1;
257}
258
brettw@chromium.orgaa82a772014-03-14 02:26:21 +0900259} // namespace base