1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/files/file_util.h"
6
7 #if defined(OS_WIN)
8 #include <io.h>
9 #endif
10 #include <stdio.h>
11
12 #include <fstream>
13 #include <limits>
14
15 #include "base/files/file_enumerator.h"
16 #include "base/files/file_path.h"
17 #include "base/logging.h"
18 #include "base/strings/string_piece.h"
19 #include "base/strings/string_util.h"
20 #include "base/strings/stringprintf.h"
21 #include "base/strings/utf_string_conversions.h"
22 #include "build/build_config.h"
23
24 namespace base {
25
26 #if !defined(OS_NACL_NONSFI)
27 namespace {
28
29 // The maximum number of 'uniquified' files we will try to create.
30 // This is used when the filename we're trying to download is already in use,
31 // so we create a new unique filename by appending " (nnn)" before the
32 // extension, where 1 <= nnn <= kMaxUniqueFiles.
33 // Also used by code that cleans up said files.
34 static const int kMaxUniqueFiles = 100;
35
36 } // namespace
37
ComputeDirectorySize(const FilePath & root_path)38 int64_t ComputeDirectorySize(const FilePath& root_path) {
39 int64_t running_size = 0;
40 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
Move(const FilePath & from_path,const FilePath & to_path)46 bool Move(const FilePath& from_path, const FilePath& to_path) {
47 if (from_path.ReferencesParent() || to_path.ReferencesParent())
48 return false;
49 return internal::MoveUnsafe(from_path, to_path);
50 }
51
ContentsEqual(const FilePath & filename1,const FilePath & filename2)52 bool ContentsEqual(const FilePath& filename1, const FilePath& filename2) {
53 // We open the file in binary format even if they are text files because
54 // we are just comparing that bytes are exactly same in both files and not
55 // doing anything smart with text formatting.
56 std::ifstream file1(filename1.value().c_str(),
57 std::ios::in | std::ios::binary);
58 std::ifstream file2(filename2.value().c_str(),
59 std::ios::in | std::ios::binary);
60
61 // Even if both files aren't openable (and thus, in some sense, "equal"),
62 // any unusable file yields a result of "false".
63 if (!file1.is_open() || !file2.is_open())
64 return false;
65
66 const int BUFFER_SIZE = 2056;
67 char buffer1[BUFFER_SIZE], buffer2[BUFFER_SIZE];
68 do {
69 file1.read(buffer1, BUFFER_SIZE);
70 file2.read(buffer2, BUFFER_SIZE);
71
72 if ((file1.eof() != file2.eof()) ||
73 (file1.gcount() != file2.gcount()) ||
74 (memcmp(buffer1, buffer2, static_cast<size_t>(file1.gcount())))) {
75 file1.close();
76 file2.close();
77 return false;
78 }
79 } while (!file1.eof() || !file2.eof());
80
81 file1.close();
82 file2.close();
83 return true;
84 }
85
TextContentsEqual(const FilePath & filename1,const FilePath & filename2)86 bool TextContentsEqual(const FilePath& filename1, const FilePath& filename2) {
87 std::ifstream file1(filename1.value().c_str(), std::ios::in);
88 std::ifstream file2(filename2.value().c_str(), std::ios::in);
89
90 // Even if both files aren't openable (and thus, in some sense, "equal"),
91 // any unusable file yields a result of "false".
92 if (!file1.is_open() || !file2.is_open())
93 return false;
94
95 do {
96 std::string line1, line2;
97 getline(file1, line1);
98 getline(file2, line2);
99
100 // Check for mismatched EOF states, or any error state.
101 if ((file1.eof() != file2.eof()) ||
102 file1.bad() || file2.bad()) {
103 return false;
104 }
105
106 // Trim all '\r' and '\n' characters from the end of the line.
107 std::string::size_type end1 = line1.find_last_not_of("\r\n");
108 if (end1 == std::string::npos)
109 line1.clear();
110 else if (end1 + 1 < line1.length())
111 line1.erase(end1 + 1);
112
113 std::string::size_type end2 = line2.find_last_not_of("\r\n");
114 if (end2 == std::string::npos)
115 line2.clear();
116 else if (end2 + 1 < line2.length())
117 line2.erase(end2 + 1);
118
119 if (line1 != line2)
120 return false;
121 } while (!file1.eof() || !file2.eof());
122
123 return true;
124 }
125 #endif // !defined(OS_NACL_NONSFI)
126
ReadFileToString(const FilePath & path,std::string * contents,size_t max_size)127 bool ReadFileToString(const FilePath& path,
128 std::string* contents,
129 size_t max_size) {
130 if (contents)
131 contents->clear();
132 if (path.ReferencesParent())
133 return false;
134 FILE* file = OpenFile(path, "rb");
135 if (!file) {
136 return false;
137 }
138
139 const size_t kBufferSize = 1 << 16;
140 scoped_ptr<char[]> buf(new char[kBufferSize]);
141 size_t len;
142 size_t size = 0;
143 bool read_status = true;
144
145 // Many files supplied in |path| have incorrect size (proc files etc).
146 // Hence, the file is read sequentially as opposed to a one-shot read.
147 while ((len = fread(buf.get(), 1, kBufferSize, file)) > 0) {
148 if (contents)
149 contents->append(buf.get(), std::min(len, max_size - size));
150
151 if ((max_size - size) < len) {
152 read_status = false;
153 break;
154 }
155
156 size += len;
157 }
158 read_status = read_status && !ferror(file);
159 CloseFile(file);
160
161 return read_status;
162 }
163
ReadFileToString(const FilePath & path,std::string * contents)164 bool ReadFileToString(const FilePath& path, std::string* contents) {
165 return ReadFileToString(path, contents, std::numeric_limits<size_t>::max());
166 }
167
168 #if !defined(OS_NACL_NONSFI)
IsDirectoryEmpty(const FilePath & dir_path)169 bool 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
CreateAndOpenTemporaryFile(FilePath * path)177 FILE* CreateAndOpenTemporaryFile(FilePath* path) {
178 FilePath directory;
179 if (!GetTempDir(&directory))
180 return NULL;
181
182 return CreateAndOpenTemporaryFileInDir(directory, path);
183 }
184
CreateDirectory(const FilePath & full_path)185 bool CreateDirectory(const FilePath& full_path) {
186 return CreateDirectoryAndGetError(full_path, NULL);
187 }
188
GetFileSize(const FilePath & file_path,int64_t * file_size)189 bool GetFileSize(const FilePath& file_path, int64_t* file_size) {
190 File::Info info;
191 if (!GetFileInfo(file_path, &info))
192 return false;
193 *file_size = info.size;
194 return true;
195 }
196
TouchFile(const FilePath & path,const Time & last_accessed,const Time & last_modified)197 bool TouchFile(const FilePath& path,
198 const Time& last_accessed,
199 const Time& last_modified) {
200 int flags = File::FLAG_OPEN | File::FLAG_WRITE_ATTRIBUTES;
201
202 #if defined(OS_WIN)
203 // On Windows, FILE_FLAG_BACKUP_SEMANTICS is needed to open a directory.
204 if (DirectoryExists(path))
205 flags |= File::FLAG_BACKUP_SEMANTICS;
206 #endif // OS_WIN
207
208 File file(path, flags);
209 if (!file.IsValid())
210 return false;
211
212 return file.SetTimes(last_accessed, last_modified);
213 }
214 #endif // !defined(OS_NACL_NONSFI)
215
CloseFile(FILE * file)216 bool CloseFile(FILE* file) {
217 if (file == NULL)
218 return true;
219 return fclose(file) == 0;
220 }
221
222 #if !defined(OS_NACL_NONSFI)
TruncateFile(FILE * file)223 bool TruncateFile(FILE* file) {
224 if (file == NULL)
225 return false;
226 long current_offset = ftell(file);
227 if (current_offset == -1)
228 return false;
229 #if defined(OS_WIN)
230 int fd = _fileno(file);
231 if (_chsize(fd, current_offset) != 0)
232 return false;
233 #else
234 int fd = fileno(file);
235 if (ftruncate(fd, current_offset) != 0)
236 return false;
237 #endif
238 return true;
239 }
240
GetUniquePathNumber(const FilePath & path,const FilePath::StringType & suffix)241 int GetUniquePathNumber(const FilePath& path,
242 const FilePath::StringType& suffix) {
243 bool have_suffix = !suffix.empty();
244 if (!PathExists(path) &&
245 (!have_suffix || !PathExists(FilePath(path.value() + suffix)))) {
246 return 0;
247 }
248
249 FilePath new_path;
250 for (int count = 1; count <= kMaxUniqueFiles; ++count) {
251 new_path = path.InsertBeforeExtensionASCII(StringPrintf(" (%d)", count));
252 if (!PathExists(new_path) &&
253 (!have_suffix || !PathExists(FilePath(new_path.value() + suffix)))) {
254 return count;
255 }
256 }
257
258 return -1;
259 }
260 #endif // !defined(OS_NACL_NONSFI)
261
262 } // namespace base
263