• 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 #include <string_view>
15 
16 #include "base/files/file_enumerator.h"
17 #include "base/files/file_path.h"
18 #include "base/logging.h"
19 #include "base/strings/string_util.h"
20 #include "base/strings/stringprintf.h"
21 #include "base/strings/utf_string_conversions.h"
22 #include "util/build_config.h"
23 
24 namespace base {
25 
26 namespace {
27 
28 // The maximum number of 'uniquified' files we will try to create.
29 // This is used when the filename we're trying to download is already in use,
30 // so we create a new unique filename by appending " (nnn)" before the
31 // extension, where 1 <= nnn <= kMaxUniqueFiles.
32 // Also used by code that cleans up said files.
33 static const int kMaxUniqueFiles = 100;
34 
35 }  // namespace
36 
ComputeDirectorySize(const FilePath & root_path)37 int64_t ComputeDirectorySize(const FilePath& root_path) {
38   int64_t running_size = 0;
39   FileEnumerator file_iter(root_path, true, FileEnumerator::FILES);
40   while (!file_iter.Next().empty())
41     running_size += file_iter.GetInfo().GetSize();
42   return running_size;
43 }
44 
ContentsEqual(const FilePath & filename1,const FilePath & filename2)45 bool ContentsEqual(const FilePath& filename1, const FilePath& filename2) {
46   // We open the file in binary format even if they are text files because
47   // we are just comparing that bytes are exactly same in both files and not
48   // doing anything smart with text formatting.
49   std::ifstream file1(filename1.As8Bit().c_str(),
50                       std::ios::in | std::ios::binary);
51   std::ifstream file2(filename2.As8Bit().c_str(),
52                       std::ios::in | std::ios::binary);
53 
54   // Even if both files aren't openable (and thus, in some sense, "equal"),
55   // any unusable file yields a result of "false".
56   if (!file1.is_open() || !file2.is_open())
57     return false;
58 
59   const int BUFFER_SIZE = 2056;
60   char buffer1[BUFFER_SIZE], buffer2[BUFFER_SIZE];
61   do {
62     file1.read(buffer1, BUFFER_SIZE);
63     file2.read(buffer2, BUFFER_SIZE);
64 
65     if ((file1.eof() != file2.eof()) || (file1.gcount() != file2.gcount()) ||
66         (memcmp(buffer1, buffer2, static_cast<size_t>(file1.gcount())))) {
67       file1.close();
68       file2.close();
69       return false;
70     }
71   } while (!file1.eof() || !file2.eof());
72 
73   file1.close();
74   file2.close();
75   return true;
76 }
77 
TextContentsEqual(const FilePath & filename1,const FilePath & filename2)78 bool TextContentsEqual(const FilePath& filename1, const FilePath& filename2) {
79   std::ifstream file1(filename1.As8Bit().c_str(), std::ios::in);
80   std::ifstream file2(filename2.As8Bit().c_str(), std::ios::in);
81 
82   // Even if both files aren't openable (and thus, in some sense, "equal"),
83   // any unusable file yields a result of "false".
84   if (!file1.is_open() || !file2.is_open())
85     return false;
86 
87   do {
88     std::string line1, line2;
89     getline(file1, line1);
90     getline(file2, line2);
91 
92     // Check for mismatched EOF states, or any error state.
93     if ((file1.eof() != file2.eof()) || file1.bad() || file2.bad()) {
94       return false;
95     }
96 
97     // Trim all '\r' and '\n' characters from the end of the line.
98     std::string::size_type end1 = line1.find_last_not_of("\r\n");
99     if (end1 == std::string::npos)
100       line1.clear();
101     else if (end1 + 1 < line1.length())
102       line1.erase(end1 + 1);
103 
104     std::string::size_type end2 = line2.find_last_not_of("\r\n");
105     if (end2 == std::string::npos)
106       line2.clear();
107     else if (end2 + 1 < line2.length())
108       line2.erase(end2 + 1);
109 
110     if (line1 != line2)
111       return false;
112   } while (!file1.eof() || !file2.eof());
113 
114   return true;
115 }
116 
ReadFileToStringWithMaxSize(const FilePath & path,std::string * contents,size_t max_size)117 bool ReadFileToStringWithMaxSize(const FilePath& path,
118                                  std::string* contents,
119                                  size_t max_size) {
120   if (contents)
121     contents->clear();
122   if (path.ReferencesParent())
123     return false;
124   FILE* file = OpenFile(path, "rb");
125   if (!file) {
126     return false;
127   }
128 
129   // Many files supplied in |path| have incorrect size (proc files etc).
130   // Hence, the file is read sequentially as opposed to a one-shot read, using
131   // file size as a hint for chunk size if available.
132   constexpr int64_t kDefaultChunkSize = 1 << 16;
133   int64_t chunk_size;
134   if (!GetFileSize(path, &chunk_size) || chunk_size <= 0)
135     chunk_size = kDefaultChunkSize - 1;
136   // We need to attempt to read at EOF for feof flag to be set so here we
137   // use |chunk_size| + 1.
138   chunk_size = std::min<uint64_t>(chunk_size, max_size) + 1;
139   size_t bytes_read_this_pass;
140   size_t bytes_read_so_far = 0;
141   bool read_status = true;
142   std::string local_contents;
143   local_contents.resize(chunk_size);
144 
145   while ((bytes_read_this_pass = fread(&local_contents[bytes_read_so_far], 1,
146                                        chunk_size, file)) > 0) {
147     if ((max_size - bytes_read_so_far) < bytes_read_this_pass) {
148       // Read more than max_size bytes, bail out.
149       bytes_read_so_far = max_size;
150       read_status = false;
151       break;
152     }
153     // In case EOF was not reached, iterate again but revert to the default
154     // chunk size.
155     if (bytes_read_so_far == 0)
156       chunk_size = kDefaultChunkSize;
157 
158     bytes_read_so_far += bytes_read_this_pass;
159     // Last fread syscall (after EOF) can be avoided via feof, which is just a
160     // flag check.
161     if (feof(file))
162       break;
163     local_contents.resize(bytes_read_so_far + chunk_size);
164   }
165   read_status = read_status && !ferror(file);
166   CloseFile(file);
167   if (contents) {
168     contents->swap(local_contents);
169     contents->resize(bytes_read_so_far);
170   }
171 
172   return read_status;
173 }
174 
ReadFileToString(const FilePath & path,std::string * contents)175 bool ReadFileToString(const FilePath& path, std::string* contents) {
176   return ReadFileToStringWithMaxSize(path, contents,
177                                      std::numeric_limits<size_t>::max());
178 }
179 
IsDirectoryEmpty(const FilePath & dir_path)180 bool IsDirectoryEmpty(const FilePath& dir_path) {
181   FileEnumerator files(dir_path, false,
182                        FileEnumerator::FILES | FileEnumerator::DIRECTORIES);
183   if (files.Next().empty())
184     return true;
185   return false;
186 }
187 
CreateDirectory(const FilePath & full_path)188 bool CreateDirectory(const FilePath& full_path) {
189   return CreateDirectoryAndGetError(full_path, nullptr);
190 }
191 
GetFileSize(const FilePath & file_path,int64_t * file_size)192 bool GetFileSize(const FilePath& file_path, int64_t* file_size) {
193   File::Info info;
194   if (!GetFileInfo(file_path, &info))
195     return false;
196   *file_size = info.size;
197   return true;
198 }
199 
CloseFile(FILE * file)200 bool CloseFile(FILE* file) {
201   if (file == nullptr)
202     return true;
203   return fclose(file) == 0;
204 }
205 
TruncateFile(FILE * file)206 bool TruncateFile(FILE* file) {
207   if (file == nullptr)
208     return false;
209   long current_offset = ftell(file);
210   if (current_offset == -1)
211     return false;
212 #if defined(OS_WIN)
213   int fd = _fileno(file);
214   if (_chsize(fd, current_offset) != 0)
215     return false;
216 #else
217   int fd = fileno(file);
218   if (ftruncate(fd, current_offset) != 0)
219     return false;
220 #endif
221   return true;
222 }
223 
GetUniquePathNumber(const FilePath & path,const FilePath::StringType & suffix)224 int GetUniquePathNumber(const FilePath& path,
225                         const FilePath::StringType& suffix) {
226   bool have_suffix = !suffix.empty();
227   if (!PathExists(path) &&
228       (!have_suffix || !PathExists(FilePath(path.value() + suffix)))) {
229     return 0;
230   }
231 
232   FilePath new_path;
233   for (int count = 1; count <= kMaxUniqueFiles; ++count) {
234     new_path = path.InsertBeforeExtensionASCII(StringPrintf(" (%d)", count));
235     if (!PathExists(new_path) &&
236         (!have_suffix || !PathExists(FilePath(new_path.value() + suffix)))) {
237       return count;
238     }
239   }
240 
241   return -1;
242 }
243 
244 }  // namespace base
245