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 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 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 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 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 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 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 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 166 bool ReadFileToString(const FilePath& path, std::string* contents) { 167 return ReadFileToString(path, contents, std::numeric_limits<size_t>::max()); 168 } 169 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 178 FILE* CreateAndOpenTemporaryFile(FilePath* path) { 179 FilePath directory; 180 if (!GetTempDir(&directory)) 181 return NULL; 182 183 return CreateAndOpenTemporaryFileInDir(directory, path); 184 } 185 186 bool CreateDirectory(const FilePath& full_path) { 187 return CreateDirectoryAndGetError(full_path, NULL); 188 } 189 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 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 216 bool CloseFile(FILE* file) { 217 if (file == NULL) 218 return true; 219 return fclose(file) == 0; 220 } 221 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 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