• 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/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 
23 namespace base {
24 
25 namespace {
26 
27 // 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.
32 static const int kMaxUniqueFiles = 100;
33 
34 }  // namespace
35 
ComputeDirectorySize(const FilePath & root_path)36 int64 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 
Move(const FilePath & from_path,const FilePath & to_path)44 bool Move(const FilePath& from_path, const FilePath& to_path) {
45   if (from_path.ReferencesParent() || to_path.ReferencesParent())
46     return false;
47   return internal::MoveUnsafe(from_path, to_path);
48 }
49 
CopyFile(const FilePath & from_path,const FilePath & to_path)50 bool 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);
54 }
55 
ContentsEqual(const FilePath & filename1,const FilePath & filename2)56 bool ContentsEqual(const FilePath& filename1, const FilePath& filename2) {
57   // 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.
60   std::ifstream file1(filename1.value().c_str(),
61                       std::ios::in | std::ios::binary);
62   std::ifstream file2(filename2.value().c_str(),
63                       std::ios::in | std::ios::binary);
64 
65   // 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 
76     if ((file1.eof() != file2.eof()) ||
77         (file1.gcount() != file2.gcount()) ||
78         (memcmp(buffer1, buffer2, file1.gcount()))) {
79       file1.close();
80       file2.close();
81       return false;
82     }
83   } while (!file1.eof() || !file2.eof());
84 
85   file1.close();
86   file2.close();
87   return true;
88 }
89 
TextContentsEqual(const FilePath & filename1,const FilePath & filename2)90 bool 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 
ReadFileToString(const FilePath & path,std::string * contents,size_t max_size)130 bool ReadFileToString(const FilePath& path,
131                       std::string* contents,
132                       size_t max_size) {
133   if (contents)
134     contents->clear();
135   if (path.ReferencesParent())
136     return false;
137   FILE* file = OpenFile(path, "rb");
138   if (!file) {
139     return false;
140   }
141 
142   char buf[1 << 16];
143   size_t len;
144   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.
149   while ((len = fread(buf, 1, sizeof(buf), file)) > 0) {
150     if (contents)
151       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;
159   }
160   read_status = read_status && !ferror(file);
161   CloseFile(file);
162 
163   return read_status;
164 }
165 
ReadFileToString(const FilePath & path,std::string * contents)166 bool ReadFileToString(const FilePath& path, std::string* contents) {
167   return ReadFileToString(path, contents, std::numeric_limits<size_t>::max());
168 }
169 
IsDirectoryEmpty(const FilePath & dir_path)170 bool IsDirectoryEmpty(const FilePath& dir_path) {
171   FileEnumerator files(dir_path, false,
172       FileEnumerator::FILES | FileEnumerator::DIRECTORIES);
173   if (files.Next().empty())
174     return true;
175   return false;
176 }
177 
CreateAndOpenTemporaryFile(FilePath * path)178 FILE* CreateAndOpenTemporaryFile(FilePath* path) {
179   FilePath directory;
180   if (!GetTempDir(&directory))
181     return NULL;
182 
183   return CreateAndOpenTemporaryFileInDir(directory, path);
184 }
185 
CreateDirectory(const FilePath & full_path)186 bool CreateDirectory(const FilePath& full_path) {
187   return CreateDirectoryAndGetError(full_path, NULL);
188 }
189 
GetFileSize(const FilePath & file_path,int64 * file_size)190 bool GetFileSize(const FilePath& file_path, int64* file_size) {
191   File::Info info;
192   if (!GetFileInfo(file_path, &info))
193     return false;
194   *file_size = info.size;
195   return true;
196 }
197 
TouchFile(const FilePath & path,const Time & last_accessed,const Time & last_modified)198 bool TouchFile(const FilePath& path,
199                const Time& last_accessed,
200                const Time& last_modified) {
201   int flags = File::FLAG_OPEN | File::FLAG_WRITE_ATTRIBUTES;
202 
203 #if defined(OS_WIN)
204   // On Windows, FILE_FLAG_BACKUP_SEMANTICS is needed to open a directory.
205   if (DirectoryExists(path))
206     flags |= File::FLAG_BACKUP_SEMANTICS;
207 #endif  // OS_WIN
208 
209   File file(path, flags);
210   if (!file.IsValid())
211     return false;
212 
213   return file.SetTimes(last_accessed, last_modified);
214 }
215 
CloseFile(FILE * file)216 bool CloseFile(FILE* file) {
217   if (file == NULL)
218     return true;
219   return fclose(file) == 0;
220 }
221 
TruncateFile(FILE * file)222 bool TruncateFile(FILE* file) {
223   if (file == NULL)
224     return false;
225   long current_offset = ftell(file);
226   if (current_offset == -1)
227     return false;
228 #if defined(OS_WIN)
229   int fd = _fileno(file);
230   if (_chsize(fd, current_offset) != 0)
231     return false;
232 #else
233   int fd = fileno(file);
234   if (ftruncate(fd, current_offset) != 0)
235     return false;
236 #endif
237   return true;
238 }
239 
GetUniquePathNumber(const FilePath & path,const FilePath::StringType & suffix)240 int GetUniquePathNumber(const FilePath& path,
241                         const FilePath::StringType& suffix) {
242   bool have_suffix = !suffix.empty();
243   if (!PathExists(path) &&
244       (!have_suffix || !PathExists(FilePath(path.value() + suffix)))) {
245     return 0;
246   }
247 
248   FilePath new_path;
249   for (int count = 1; count <= kMaxUniqueFiles; ++count) {
250     new_path = path.InsertBeforeExtensionASCII(StringPrintf(" (%d)", count));
251     if (!PathExists(new_path) &&
252         (!have_suffix || !PathExists(FilePath(new_path.value() + suffix)))) {
253       return count;
254     }
255   }
256 
257   return -1;
258 }
259 
260 }  // namespace base
261