• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ReadFileToStringWithMaxSize(const FilePath & path,std::string * contents,size_t max_size)127 bool ReadFileToStringWithMaxSize(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   // Many files supplied in |path| have incorrect size (proc files etc).
140   // Hence, the file is read sequentially as opposed to a one-shot read, using
141   // file size as a hint for chunk size if available.
142   constexpr int64_t kDefaultChunkSize = 1 << 16;
143   int64_t chunk_size;
144 #if !defined(OS_NACL_NONSFI)
145   if (!GetFileSize(path, &chunk_size) || chunk_size <= 0)
146     chunk_size = kDefaultChunkSize - 1;
147   // We need to attempt to read at EOF for feof flag to be set so here we
148   // use |chunk_size| + 1.
149   chunk_size = std::min<uint64_t>(chunk_size, max_size) + 1;
150 #else
151   chunk_size = kDefaultChunkSize;
152 #endif  // !defined(OS_NACL_NONSFI)
153   size_t bytes_read_this_pass;
154   size_t bytes_read_so_far = 0;
155   bool read_status = true;
156   std::string local_contents;
157   local_contents.resize(chunk_size);
158 
159   while ((bytes_read_this_pass = fread(&local_contents[bytes_read_so_far], 1,
160                                        chunk_size, file)) > 0) {
161     if ((max_size - bytes_read_so_far) < bytes_read_this_pass) {
162       // Read more than max_size bytes, bail out.
163       bytes_read_so_far = max_size;
164       read_status = false;
165       break;
166     }
167     // In case EOF was not reached, iterate again but revert to the default
168     // chunk size.
169     if (bytes_read_so_far == 0)
170       chunk_size = kDefaultChunkSize;
171 
172     bytes_read_so_far += bytes_read_this_pass;
173     // Last fread syscall (after EOF) can be avoided via feof, which is just a
174     // flag check.
175     if (feof(file))
176       break;
177     local_contents.resize(bytes_read_so_far + chunk_size);
178   }
179   read_status = read_status && !ferror(file);
180   CloseFile(file);
181   if (contents) {
182     contents->swap(local_contents);
183     contents->resize(bytes_read_so_far);
184   }
185 
186   return read_status;
187 }
188 
ReadFileToString(const FilePath & path,std::string * contents)189 bool ReadFileToString(const FilePath& path, std::string* contents) {
190   return ReadFileToStringWithMaxSize(path, contents,
191                                      std::numeric_limits<size_t>::max());
192 }
193 
194 #if !defined(OS_NACL_NONSFI)
IsDirectoryEmpty(const FilePath & dir_path)195 bool IsDirectoryEmpty(const FilePath& dir_path) {
196   FileEnumerator files(dir_path, false,
197       FileEnumerator::FILES | FileEnumerator::DIRECTORIES);
198   if (files.Next().empty())
199     return true;
200   return false;
201 }
202 
CreateAndOpenTemporaryFile(FilePath * path)203 FILE* CreateAndOpenTemporaryFile(FilePath* path) {
204   FilePath directory;
205   if (!GetTempDir(&directory))
206     return nullptr;
207 
208   return CreateAndOpenTemporaryFileInDir(directory, path);
209 }
210 
CreateDirectory(const FilePath & full_path)211 bool CreateDirectory(const FilePath& full_path) {
212   return CreateDirectoryAndGetError(full_path, nullptr);
213 }
214 
GetFileSize(const FilePath & file_path,int64_t * file_size)215 bool GetFileSize(const FilePath& file_path, int64_t* file_size) {
216   File::Info info;
217   if (!GetFileInfo(file_path, &info))
218     return false;
219   *file_size = info.size;
220   return true;
221 }
222 
TouchFile(const FilePath & path,const Time & last_accessed,const Time & last_modified)223 bool TouchFile(const FilePath& path,
224                const Time& last_accessed,
225                const Time& last_modified) {
226   int flags = File::FLAG_OPEN | File::FLAG_WRITE_ATTRIBUTES;
227 
228 #if defined(OS_WIN)
229   // On Windows, FILE_FLAG_BACKUP_SEMANTICS is needed to open a directory.
230   if (DirectoryExists(path))
231     flags |= File::FLAG_BACKUP_SEMANTICS;
232 #endif  // OS_WIN
233 
234   File file(path, flags);
235   if (!file.IsValid())
236     return false;
237 
238   return file.SetTimes(last_accessed, last_modified);
239 }
240 #endif  // !defined(OS_NACL_NONSFI)
241 
CloseFile(FILE * file)242 bool CloseFile(FILE* file) {
243   if (file == nullptr)
244     return true;
245   return fclose(file) == 0;
246 }
247 
248 #if !defined(OS_NACL_NONSFI)
TruncateFile(FILE * file)249 bool TruncateFile(FILE* file) {
250   if (file == nullptr)
251     return false;
252   long current_offset = ftell(file);
253   if (current_offset == -1)
254     return false;
255 #if defined(OS_WIN)
256   int fd = _fileno(file);
257   if (_chsize(fd, current_offset) != 0)
258     return false;
259 #else
260   int fd = fileno(file);
261   if (ftruncate(fd, current_offset) != 0)
262     return false;
263 #endif
264   return true;
265 }
266 
GetUniquePathNumber(const FilePath & path,const FilePath::StringType & suffix)267 int GetUniquePathNumber(const FilePath& path,
268                         const FilePath::StringType& suffix) {
269   bool have_suffix = !suffix.empty();
270   if (!PathExists(path) &&
271       (!have_suffix || !PathExists(FilePath(path.value() + suffix)))) {
272     return 0;
273   }
274 
275   FilePath new_path;
276   for (int count = 1; count <= kMaxUniqueFiles; ++count) {
277     new_path = path.InsertBeforeExtensionASCII(StringPrintf(" (%d)", count));
278     if (!PathExists(new_path) &&
279         (!have_suffix || !PathExists(FilePath(new_path.value() + suffix)))) {
280       return count;
281     }
282   }
283 
284   return -1;
285 }
286 #endif  // !defined(OS_NACL_NONSFI)
287 
288 }  // namespace base
289