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