Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/chromeos/drive/file_cache.h" | 5 #include "chrome/browser/chromeos/drive/file_cache.h" |
| 6 | 6 |
| 7 #include <vector> | 7 #include <vector> |
| 8 | 8 |
| 9 #include "base/file_util.h" | 9 #include "base/file_util.h" |
| 10 #include "base/files/file_enumerator.h" | 10 #include "base/files/file_enumerator.h" |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 21 #include "content/public/browser/browser_thread.h" | 21 #include "content/public/browser/browser_thread.h" |
| 22 | 22 |
| 23 using content::BrowserThread; | 23 using content::BrowserThread; |
| 24 | 24 |
| 25 namespace drive { | 25 namespace drive { |
| 26 namespace internal { | 26 namespace internal { |
| 27 namespace { | 27 namespace { |
| 28 | 28 |
| 29 typedef std::map<std::string, FileCacheEntry> CacheMap; | 29 typedef std::map<std::string, FileCacheEntry> CacheMap; |
| 30 | 30 |
| 31 typedef std::map<std::string, base::FilePath> ResourceIdToFilePathMap; | |
| 32 | |
| 33 const base::FilePath::CharType kFileCacheMetaDir[] = FILE_PATH_LITERAL("meta"); | 31 const base::FilePath::CharType kFileCacheMetaDir[] = FILE_PATH_LITERAL("meta"); |
| 34 const base::FilePath::CharType kFileCachePersistentDir[] = | 32 const base::FilePath::CharType kFileCacheFilesDir[] = |
| 35 FILE_PATH_LITERAL("persistent"); | 33 FILE_PATH_LITERAL("files"); |
| 36 const base::FilePath::CharType kFileCacheTmpDir[] = FILE_PATH_LITERAL("tmp"); | |
| 37 const base::FilePath::CharType kFileCacheTmpDownloadsDir[] = | 34 const base::FilePath::CharType kFileCacheTmpDownloadsDir[] = |
| 38 FILE_PATH_LITERAL("tmp/downloads"); | 35 FILE_PATH_LITERAL("tmp/downloads"); |
| 39 const base::FilePath::CharType kFileCacheTmpDocumentsDir[] = | 36 const base::FilePath::CharType kFileCacheTmpDocumentsDir[] = |
| 40 FILE_PATH_LITERAL("tmp/documents"); | 37 FILE_PATH_LITERAL("tmp/documents"); |
| 41 | 38 |
| 42 // Returns true if |md5| matches the one in |cache_entry| with some | 39 // Returns true if |md5| matches the one in |cache_entry| with some |
| 43 // exceptions. See the function definition for details. | 40 // exceptions. See the function definition for details. |
| 44 bool CheckIfMd5Matches(const std::string& md5, | 41 bool CheckIfMd5Matches(const std::string& md5, |
| 45 const FileCacheEntry& cache_entry) { | 42 const FileCacheEntry& cache_entry) { |
| 46 if (cache_entry.is_dirty()) { | 43 if (cache_entry.is_dirty()) { |
| 47 // If the entry is dirty, its MD5 may have been replaced by "local" | 44 // If the entry is dirty, its MD5 may have been replaced by "local" |
| 48 // during cache initialization, so we don't compare MD5. | 45 // during cache initialization, so we don't compare MD5. |
| 49 return true; | 46 return true; |
| 50 } else if (cache_entry.is_pinned() && cache_entry.md5().empty()) { | 47 } else if (cache_entry.is_pinned() && cache_entry.md5().empty()) { |
| 51 // If the entry is pinned, it's ok for the entry to have an empty | 48 // If the entry is pinned, it's ok for the entry to have an empty |
| 52 // MD5. This can happen if the pinned file is not fetched. MD5 for pinned | 49 // MD5. This can happen if the pinned file is not fetched. |
| 53 // files are collected from files in "persistent" directory, but the | |
| 54 // persistent files do not exist if these are not fetched yet. | |
| 55 return true; | 50 return true; |
| 56 } else if (md5.empty()) { | 51 } else if (md5.empty()) { |
| 57 // If the MD5 matching is not requested, don't check MD5. | 52 // If the MD5 matching is not requested, don't check MD5. |
| 58 return true; | 53 return true; |
| 59 } else if (md5 == cache_entry.md5()) { | 54 } else if (md5 == cache_entry.md5()) { |
| 60 // Otherwise, compare the MD5. | 55 // Otherwise, compare the MD5. |
| 61 return true; | 56 return true; |
| 62 } | 57 } |
| 63 return false; | 58 return false; |
| 64 } | 59 } |
| 65 | 60 |
| 66 // Scans cache subdirectory and build or update |cache_map| with found files. | 61 // Scans cache subdirectory and insert found files to |cache_map|. |
| 67 // | 62 void ScanCacheDirectory(const base::FilePath& directory_path, |
| 68 // The resource IDs and file paths of discovered files are collected as a | 63 CacheMap* cache_map) { |
| 69 // ResourceIdToFilePathMap, if these are processed properly. | 64 base::FileEnumerator enumerator(directory_path, |
| 70 void ScanCacheDirectory(const std::vector<base::FilePath>& cache_paths, | |
| 71 FileCache::CacheSubDirectoryType sub_dir_type, | |
| 72 CacheMap* cache_map, | |
| 73 ResourceIdToFilePathMap* processed_file_map) { | |
| 74 DCHECK(cache_map); | |
| 75 DCHECK(processed_file_map); | |
| 76 | |
| 77 base::FileEnumerator enumerator(cache_paths[sub_dir_type], | |
| 78 false, // not recursive | 65 false, // not recursive |
| 79 base::FileEnumerator::FILES, | 66 base::FileEnumerator::FILES); |
| 80 util::kWildCard); | |
| 81 for (base::FilePath current = enumerator.Next(); !current.empty(); | 67 for (base::FilePath current = enumerator.Next(); !current.empty(); |
| 82 current = enumerator.Next()) { | 68 current = enumerator.Next()) { |
| 83 // Extract resource_id and md5 from filename. | 69 // Extract resource_id and md5 from filename. |
| 84 std::string resource_id; | 70 std::string resource_id; |
| 85 std::string md5; | 71 std::string md5; |
| 86 std::string extra_extension; | 72 std::string extra_extension; |
| 87 util::ParseCacheFilePath(current, &resource_id, &md5, &extra_extension); | 73 util::ParseCacheFilePath(current, &resource_id, &md5, &extra_extension); |
| 88 | 74 |
| 75 if (extra_extension == util::kMountedArchiveFileExtension) { | |
| 76 // Mounted archives in cache should be unmounted upon logout/shutdown. | |
| 77 // But if we encounter a mounted file at start, delete it. | |
| 78 file_util::Delete(current, false); | |
| 79 continue; | |
| 80 } | |
| 81 | |
| 89 // Determine cache state. | 82 // Determine cache state. |
| 90 FileCacheEntry cache_entry; | 83 FileCacheEntry cache_entry; |
| 91 cache_entry.set_md5(md5); | 84 cache_entry.set_md5(md5); |
| 92 if (sub_dir_type == FileCache::CACHE_TYPE_PERSISTENT) | 85 cache_entry.set_is_present(true); |
| 93 cache_entry.set_is_persistent(true); | |
| 94 | 86 |
| 95 if (extra_extension == util::kMountedArchiveFileExtension) { | 87 // Add the dirty bit if |md5| indicates that the file is dirty. |
| 96 // Mounted archives in cache should be unmounted upon logout/shutdown. | 88 if (md5 == util::kLocallyModifiedFileExtension) |
| 97 // But if we encounter a mounted file at start, delete it and create an | 89 cache_entry.set_is_dirty(true); |
| 98 // entry with not PRESENT state. | |
| 99 DCHECK(sub_dir_type == FileCache::CACHE_TYPE_PERSISTENT); | |
| 100 file_util::Delete(current, false); | |
| 101 } else { | |
| 102 // The cache file is present. | |
| 103 cache_entry.set_is_present(true); | |
| 104 | |
| 105 // Adds the dirty bit if |md5| indicates that the file is dirty, and | |
| 106 // the file is in the persistent directory. | |
| 107 if (md5 == util::kLocallyModifiedFileExtension) { | |
| 108 if (sub_dir_type == FileCache::CACHE_TYPE_PERSISTENT) { | |
| 109 cache_entry.set_is_dirty(true); | |
| 110 } else { | |
| 111 LOG(WARNING) << "Removing a dirty file in tmp directory: " | |
| 112 << current.value(); | |
| 113 file_util::Delete(current, false); | |
| 114 continue; | |
| 115 } | |
| 116 } | |
| 117 } | |
| 118 | 90 |
| 119 // Create and insert new entry into cache map. | 91 // Create and insert new entry into cache map. |
| 120 cache_map->insert(std::make_pair(resource_id, cache_entry)); | 92 cache_map->insert(std::make_pair(resource_id, cache_entry)); |
| 121 processed_file_map->insert(std::make_pair(resource_id, current)); | |
| 122 } | 93 } |
| 123 } | 94 } |
| 124 | 95 |
| 125 void ScanCachePaths(const std::vector<base::FilePath>& cache_paths, | |
| 126 CacheMap* cache_map) { | |
| 127 DVLOG(1) << "Scanning directories"; | |
| 128 | |
| 129 // Scan cache persistent and tmp directories to enumerate all files and create | |
| 130 // corresponding entries for cache map. | |
| 131 ResourceIdToFilePathMap persistent_file_map; | |
| 132 ScanCacheDirectory(cache_paths, | |
| 133 FileCache::CACHE_TYPE_PERSISTENT, | |
| 134 cache_map, | |
| 135 &persistent_file_map); | |
| 136 ResourceIdToFilePathMap tmp_file_map; | |
| 137 ScanCacheDirectory(cache_paths, | |
| 138 FileCache::CACHE_TYPE_TMP, | |
| 139 cache_map, | |
| 140 &tmp_file_map); | |
| 141 | |
| 142 // On DB corruption, keep only dirty-and-committed files in persistent | |
| 143 // directory. Other files are deleted or moved to temporary directory. | |
| 144 for (ResourceIdToFilePathMap::const_iterator iter = | |
| 145 persistent_file_map.begin(); | |
| 146 iter != persistent_file_map.end(); ++iter) { | |
| 147 const std::string& resource_id = iter->first; | |
| 148 const base::FilePath& file_path = iter->second; | |
| 149 | |
| 150 CacheMap::iterator cache_map_iter = cache_map->find(resource_id); | |
| 151 if (cache_map_iter != cache_map->end()) { | |
| 152 FileCacheEntry* cache_entry = &cache_map_iter->second; | |
| 153 const bool is_dirty = cache_entry->is_dirty(); | |
| 154 if (!is_dirty) { | |
| 155 // If the file is not dirty, move to temporary directory. | |
| 156 base::FilePath new_file_path = | |
| 157 cache_paths[FileCache::CACHE_TYPE_TMP].Append( | |
| 158 file_path.BaseName()); | |
| 159 DLOG(WARNING) << "Moving: " << file_path.value() | |
| 160 << " to: " << new_file_path.value(); | |
| 161 file_util::Move(file_path, new_file_path); | |
| 162 cache_entry->set_is_persistent(false); | |
| 163 } | |
| 164 } | |
| 165 } | |
| 166 DVLOG(1) << "Directory scan finished"; | |
| 167 } | |
| 168 | |
| 169 // Create cache directory paths and set permissions. | 96 // Create cache directory paths and set permissions. |
| 170 bool InitCachePaths(const std::vector<base::FilePath>& cache_paths) { | 97 bool InitCachePaths(const std::vector<base::FilePath>& cache_paths) { |
| 171 if (cache_paths.size() < FileCache::NUM_CACHE_TYPES) { | 98 if (cache_paths.size() < FileCache::NUM_CACHE_TYPES) { |
| 172 NOTREACHED(); | 99 NOTREACHED(); |
| 173 LOG(ERROR) << "Size of cache_paths is invalid."; | 100 LOG(ERROR) << "Size of cache_paths is invalid."; |
| 174 return false; | 101 return false; |
| 175 } | 102 } |
| 176 | 103 |
| 177 if (!FileCache::CreateCacheDirectories(cache_paths)) | 104 if (!FileCache::CreateCacheDirectories(cache_paths)) |
| 178 return false; | 105 return false; |
| 179 | 106 |
| 180 // Change permissions of cache persistent directory to u+rwx,og+x (711) in | 107 // Change permissions of cache file directory to u+rwx,og+x (711) in order to |
| 181 // order to allow archive files in that directory to be mounted by cros-disks. | 108 // allow archive files in that directory to be mounted by cros-disks. |
| 182 file_util::SetPosixFilePermissions( | 109 file_util::SetPosixFilePermissions( |
| 183 cache_paths[FileCache::CACHE_TYPE_PERSISTENT], | 110 cache_paths[FileCache::CACHE_TYPE_FILES], |
| 184 file_util::FILE_PERMISSION_USER_MASK | | 111 file_util::FILE_PERMISSION_USER_MASK | |
| 185 file_util::FILE_PERMISSION_EXECUTE_BY_GROUP | | 112 file_util::FILE_PERMISSION_EXECUTE_BY_GROUP | |
| 186 file_util::FILE_PERMISSION_EXECUTE_BY_OTHERS); | 113 file_util::FILE_PERMISSION_EXECUTE_BY_OTHERS); |
| 187 | 114 |
| 188 return true; | 115 return true; |
| 189 } | 116 } |
| 190 | 117 |
| 191 // Remove all files under the given directory, non-recursively. | |
| 192 // Do not remove recursively as we don't want to touch <gcache>/tmp/downloads, | |
| 193 // which is used for user initiated downloads like "Save As" | |
| 194 void RemoveAllFiles(const base::FilePath& directory) { | |
| 195 base::FileEnumerator enumerator(directory, false /* recursive */, | |
| 196 base::FileEnumerator::FILES); | |
| 197 for (base::FilePath file_path = enumerator.Next(); !file_path.empty(); | |
| 198 file_path = enumerator.Next()) { | |
| 199 DVLOG(1) << "Removing " << file_path.value(); | |
| 200 if (!file_util::Delete(file_path, false /* recursive */)) | |
| 201 LOG(WARNING) << "Failed to delete " << file_path.value(); | |
| 202 } | |
| 203 } | |
| 204 | |
| 205 // Moves the file. | 118 // Moves the file. |
| 206 bool MoveFile(const base::FilePath& source_path, | 119 bool MoveFile(const base::FilePath& source_path, |
| 207 const base::FilePath& dest_path) { | 120 const base::FilePath& dest_path) { |
| 208 if (!file_util::Move(source_path, dest_path)) { | 121 if (!file_util::Move(source_path, dest_path)) { |
| 209 LOG(ERROR) << "Failed to move " << source_path.value() | 122 LOG(ERROR) << "Failed to move " << source_path.value() |
| 210 << " to " << dest_path.value(); | 123 << " to " << dest_path.value(); |
| 211 return false; | 124 return false; |
| 212 } | 125 } |
| 213 DVLOG(1) << "Moved " << source_path.value() << " to " << dest_path.value(); | 126 DVLOG(1) << "Moved " << source_path.value() << " to " << dest_path.value(); |
| 214 return true; | 127 return true; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 248 continue; | 161 continue; |
| 249 | 162 |
| 250 success = file_util::Delete(current, false); | 163 success = file_util::Delete(current, false); |
| 251 if (!success) | 164 if (!success) |
| 252 DVLOG(1) << "Error deleting " << current.value(); | 165 DVLOG(1) << "Error deleting " << current.value(); |
| 253 else | 166 else |
| 254 DVLOG(1) << "Deleted " << current.value(); | 167 DVLOG(1) << "Deleted " << current.value(); |
| 255 } | 168 } |
| 256 } | 169 } |
| 257 | 170 |
| 171 // Moves all files under |directory_from| to |directory_to|. | |
| 172 void MoveAllFilesFromDirectory(const base::FilePath& directory_from, | |
| 173 const base::FilePath& directory_to) { | |
| 174 base::FileEnumerator enumerator(directory_from, false, // not recursive | |
| 175 base::FileEnumerator::FILES); | |
| 176 for (base::FilePath file_from = enumerator.Next(); !file_from.empty(); | |
| 177 file_from = enumerator.Next()) { | |
| 178 const base::FilePath file_to = directory_to.Append(file_from.BaseName()); | |
| 179 if (!file_util::PathExists(file_to)) // Do not overwrite existing files. | |
| 180 file_util::Move(file_from, file_to); | |
| 181 } | |
| 182 } | |
| 183 | |
| 258 // Runs callback with pointers dereferenced. | 184 // Runs callback with pointers dereferenced. |
| 259 // Used to implement GetFile, MarkAsMounted. | 185 // Used to implement GetFile, MarkAsMounted. |
| 260 void RunGetFileFromCacheCallback( | 186 void RunGetFileFromCacheCallback( |
| 261 const GetFileFromCacheCallback& callback, | 187 const GetFileFromCacheCallback& callback, |
| 262 base::FilePath* file_path, | 188 base::FilePath* file_path, |
| 263 FileError error) { | 189 FileError error) { |
| 264 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 190 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 265 DCHECK(!callback.is_null()); | 191 DCHECK(!callback.is_null()); |
| 266 DCHECK(file_path); | 192 DCHECK(file_path); |
| 267 | 193 |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 298 AssertOnSequencedWorkerPool(); | 224 AssertOnSequencedWorkerPool(); |
| 299 } | 225 } |
| 300 | 226 |
| 301 base::FilePath FileCache::GetCacheDirectoryPath( | 227 base::FilePath FileCache::GetCacheDirectoryPath( |
| 302 CacheSubDirectoryType sub_dir_type) const { | 228 CacheSubDirectoryType sub_dir_type) const { |
| 303 DCHECK_LE(0, sub_dir_type); | 229 DCHECK_LE(0, sub_dir_type); |
| 304 DCHECK_GT(NUM_CACHE_TYPES, sub_dir_type); | 230 DCHECK_GT(NUM_CACHE_TYPES, sub_dir_type); |
| 305 return cache_paths_[sub_dir_type]; | 231 return cache_paths_[sub_dir_type]; |
| 306 } | 232 } |
| 307 | 233 |
| 308 base::FilePath FileCache::GetCacheFilePath( | 234 base::FilePath FileCache::GetCacheFilePath(const std::string& resource_id, |
| 309 const std::string& resource_id, | 235 const std::string& md5, |
| 310 const std::string& md5, | 236 CachedFileOrigin file_origin) const { |
| 311 CacheSubDirectoryType sub_dir_type, | |
| 312 CachedFileOrigin file_origin) const { | |
| 313 DCHECK(sub_dir_type != CACHE_TYPE_META); | |
| 314 | |
| 315 // Runs on any thread. | 237 // Runs on any thread. |
| 316 // Filename is formatted as resource_id.md5, i.e. resource_id is the base | 238 // Filename is formatted as resource_id.md5, i.e. resource_id is the base |
| 317 // name and md5 is the extension. | 239 // name and md5 is the extension. |
| 318 std::string base_name = util::EscapeCacheFileName(resource_id); | 240 std::string base_name = util::EscapeCacheFileName(resource_id); |
| 319 if (file_origin == CACHED_FILE_LOCALLY_MODIFIED) { | 241 if (file_origin == CACHED_FILE_LOCALLY_MODIFIED) { |
| 320 DCHECK(sub_dir_type == CACHE_TYPE_PERSISTENT); | |
| 321 base_name += base::FilePath::kExtensionSeparator; | 242 base_name += base::FilePath::kExtensionSeparator; |
| 322 base_name += util::kLocallyModifiedFileExtension; | 243 base_name += util::kLocallyModifiedFileExtension; |
| 323 } else if (!md5.empty()) { | 244 } else if (!md5.empty()) { |
| 324 base_name += base::FilePath::kExtensionSeparator; | 245 base_name += base::FilePath::kExtensionSeparator; |
| 325 base_name += util::EscapeCacheFileName(md5); | 246 base_name += util::EscapeCacheFileName(md5); |
| 326 } | 247 } |
| 327 // For mounted archives the filename is formatted as resource_id.md5.mounted, | 248 // For mounted archives the filename is formatted as resource_id.md5.mounted, |
| 328 // i.e. resource_id.md5 is the base name and ".mounted" is the extension | 249 // i.e. resource_id.md5 is the base name and ".mounted" is the extension |
| 329 if (file_origin == CACHED_FILE_MOUNTED) { | 250 if (file_origin == CACHED_FILE_MOUNTED) { |
| 330 DCHECK(sub_dir_type == CACHE_TYPE_PERSISTENT); | |
| 331 base_name += base::FilePath::kExtensionSeparator; | 251 base_name += base::FilePath::kExtensionSeparator; |
| 332 base_name += util::kMountedArchiveFileExtension; | 252 base_name += util::kMountedArchiveFileExtension; |
| 333 } | 253 } |
| 334 return GetCacheDirectoryPath(sub_dir_type).Append( | 254 return GetCacheDirectoryPath(CACHE_TYPE_FILES).Append( |
| 335 base::FilePath::FromUTF8Unsafe(base_name)); | 255 base::FilePath::FromUTF8Unsafe(base_name)); |
| 336 } | 256 } |
| 337 | 257 |
| 338 void FileCache::AssertOnSequencedWorkerPool() { | 258 void FileCache::AssertOnSequencedWorkerPool() { |
| 339 DCHECK(!blocking_task_runner_ || | 259 DCHECK(!blocking_task_runner_ || |
| 340 blocking_task_runner_->RunsTasksOnCurrentThread()); | 260 blocking_task_runner_->RunsTasksOnCurrentThread()); |
| 341 } | 261 } |
| 342 | 262 |
| 343 bool FileCache::IsUnderFileCacheDirectory(const base::FilePath& path) const { | 263 bool FileCache::IsUnderFileCacheDirectory(const base::FilePath& path) const { |
| 344 return cache_root_path_ == path || cache_root_path_.IsParent(path); | 264 return cache_root_path_ == path || cache_root_path_.IsParent(path); |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 412 bool FileCache::FreeDiskSpaceIfNeededFor(int64 num_bytes) { | 332 bool FileCache::FreeDiskSpaceIfNeededFor(int64 num_bytes) { |
| 413 AssertOnSequencedWorkerPool(); | 333 AssertOnSequencedWorkerPool(); |
| 414 | 334 |
| 415 // Do nothing and return if we have enough space. | 335 // Do nothing and return if we have enough space. |
| 416 if (HasEnoughSpaceFor(num_bytes, cache_root_path_)) | 336 if (HasEnoughSpaceFor(num_bytes, cache_root_path_)) |
| 417 return true; | 337 return true; |
| 418 | 338 |
| 419 // Otherwise, try to free up the disk space. | 339 // Otherwise, try to free up the disk space. |
| 420 DVLOG(1) << "Freeing up disk space for " << num_bytes; | 340 DVLOG(1) << "Freeing up disk space for " << num_bytes; |
| 421 | 341 |
| 422 // First remove temporary files from the metadata. | 342 // Remove all entries unless specially marked. |
| 423 scoped_ptr<FileCacheMetadata::Iterator> it = metadata_->GetIterator(); | 343 scoped_ptr<FileCacheMetadata::Iterator> it = metadata_->GetIterator(); |
| 424 for (; !it->IsAtEnd(); it->Advance()) { | 344 for (; !it->IsAtEnd(); it->Advance()) { |
| 425 if (!it->GetValue().is_persistent()) | 345 const FileCacheEntry& entry = it->GetValue(); |
| 346 if (!entry.is_pinned() && !entry.is_dirty() && !entry.is_mounted()) | |
| 426 metadata_->RemoveCacheEntry(it->GetKey()); | 347 metadata_->RemoveCacheEntry(it->GetKey()); |
| 427 } | 348 } |
| 428 DCHECK(!it->HasError()); | 349 DCHECK(!it->HasError()); |
| 429 | 350 |
| 430 // Then remove all files under "tmp" directory. | 351 // Remove all files which have no corresponding cache entries. |
| 431 RemoveAllFiles(GetCacheDirectoryPath(CACHE_TYPE_TMP)); | 352 base::FileEnumerator enumerator(cache_paths_[CACHE_TYPE_FILES], |
| 353 false, // not recursive | |
| 354 base::FileEnumerator::FILES); | |
| 355 std::string resource_id; | |
| 356 std::string md5; | |
| 357 std::string extra_extension; | |
| 358 FileCacheEntry entry; | |
| 359 for (base::FilePath current = enumerator.Next(); !current.empty(); | |
| 360 current = enumerator.Next()) { | |
| 361 util::ParseCacheFilePath(current, &resource_id, &md5, &extra_extension); | |
| 362 if (!GetCacheEntry(resource_id, md5, &entry)) | |
| 363 file_util::Delete(current, false /* recursive */); | |
| 364 } | |
| 432 | 365 |
| 433 // Check the disk space again. | 366 // Check the disk space again. |
| 434 return HasEnoughSpaceFor(num_bytes, cache_root_path_); | 367 return HasEnoughSpaceFor(num_bytes, cache_root_path_); |
| 435 } | 368 } |
| 436 | 369 |
| 437 void FileCache::GetFileOnUIThread(const std::string& resource_id, | 370 void FileCache::GetFileOnUIThread(const std::string& resource_id, |
| 438 const std::string& md5, | 371 const std::string& md5, |
| 439 const GetFileFromCacheCallback& callback) { | 372 const GetFileFromCacheCallback& callback) { |
| 440 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 373 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 441 DCHECK(!callback.is_null()); | 374 DCHECK(!callback.is_null()); |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 463 | 396 |
| 464 CachedFileOrigin file_origin; | 397 CachedFileOrigin file_origin; |
| 465 if (cache_entry.is_mounted()) { | 398 if (cache_entry.is_mounted()) { |
| 466 file_origin = CACHED_FILE_MOUNTED; | 399 file_origin = CACHED_FILE_MOUNTED; |
| 467 } else if (cache_entry.is_dirty()) { | 400 } else if (cache_entry.is_dirty()) { |
| 468 file_origin = CACHED_FILE_LOCALLY_MODIFIED; | 401 file_origin = CACHED_FILE_LOCALLY_MODIFIED; |
| 469 } else { | 402 } else { |
| 470 file_origin = CACHED_FILE_FROM_SERVER; | 403 file_origin = CACHED_FILE_FROM_SERVER; |
| 471 } | 404 } |
| 472 | 405 |
| 473 *cache_file_path = GetCacheFilePath(resource_id, | 406 *cache_file_path = GetCacheFilePath(resource_id, cache_entry.md5(), |
| 474 cache_entry.md5(), | |
| 475 GetSubDirectoryType(cache_entry), | |
| 476 file_origin); | 407 file_origin); |
| 477 return FILE_ERROR_OK; | 408 return FILE_ERROR_OK; |
| 478 } | 409 } |
| 479 | 410 |
| 480 void FileCache::StoreOnUIThread(const std::string& resource_id, | 411 void FileCache::StoreOnUIThread(const std::string& resource_id, |
| 481 const std::string& md5, | 412 const std::string& md5, |
| 482 const base::FilePath& source_path, | 413 const base::FilePath& source_path, |
| 483 FileOperationType file_operation_type, | 414 FileOperationType file_operation_type, |
| 484 const FileOperationCallback& callback) { | 415 const FileOperationCallback& callback) { |
| 485 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 416 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 512 blocking_task_runner_, | 443 blocking_task_runner_, |
| 513 FROM_HERE, | 444 FROM_HERE, |
| 514 base::Bind(&FileCache::Pin, base::Unretained(this), resource_id, md5), | 445 base::Bind(&FileCache::Pin, base::Unretained(this), resource_id, md5), |
| 515 callback); | 446 callback); |
| 516 } | 447 } |
| 517 | 448 |
| 518 FileError FileCache::Pin(const std::string& resource_id, | 449 FileError FileCache::Pin(const std::string& resource_id, |
| 519 const std::string& md5) { | 450 const std::string& md5) { |
| 520 AssertOnSequencedWorkerPool(); | 451 AssertOnSequencedWorkerPool(); |
| 521 | 452 |
| 522 bool is_persistent = true; | |
| 523 FileCacheEntry cache_entry; | 453 FileCacheEntry cache_entry; |
| 524 if (!GetCacheEntry(resource_id, md5, &cache_entry)) { | 454 if (!GetCacheEntry(resource_id, md5, &cache_entry)) |
| 525 // The file will be first downloaded in 'tmp', then moved to 'persistent'. | 455 cache_entry.set_md5(md5); |
| 526 is_persistent = false; | |
| 527 } else { // File exists in cache, determines destination path. | |
| 528 // Determine source and destination paths. | |
| 529 | |
| 530 // If file is dirty or mounted, don't move it. | |
| 531 if (!cache_entry.is_dirty() && !cache_entry.is_mounted()) { | |
| 532 // If file was pinned before but actual file blob doesn't exist in cache: | |
| 533 // - don't need to move the file. | |
| 534 if (!cache_entry.is_present()) { | |
| 535 DCHECK(cache_entry.is_pinned()); | |
| 536 return FILE_ERROR_OK; | |
| 537 } | |
| 538 // File exists, move it to persistent dir. | |
| 539 // Gets the current path of the file in cache. | |
| 540 base::FilePath source_path = GetCacheFilePath( | |
| 541 resource_id, | |
| 542 md5, | |
| 543 GetSubDirectoryType(cache_entry), | |
| 544 CACHED_FILE_FROM_SERVER); | |
| 545 base::FilePath dest_path = GetCacheFilePath(resource_id, | |
| 546 md5, | |
| 547 CACHE_TYPE_PERSISTENT, | |
| 548 CACHED_FILE_FROM_SERVER); | |
| 549 if (!MoveFile(source_path, dest_path)) | |
| 550 return FILE_ERROR_FAILED; | |
| 551 } | |
| 552 } | |
| 553 | |
| 554 // Now that file operations have completed, update metadata. | |
| 555 cache_entry.set_md5(md5); | |
| 556 cache_entry.set_is_pinned(true); | 456 cache_entry.set_is_pinned(true); |
| 557 cache_entry.set_is_persistent(is_persistent); | |
| 558 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry); | 457 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry); |
| 559 return FILE_ERROR_OK; | 458 return FILE_ERROR_OK; |
| 560 } | 459 } |
| 561 | 460 |
| 562 void FileCache::UnpinOnUIThread(const std::string& resource_id, | 461 void FileCache::UnpinOnUIThread(const std::string& resource_id, |
| 563 const std::string& md5, | 462 const std::string& md5, |
| 564 const FileOperationCallback& callback) { | 463 const FileOperationCallback& callback) { |
| 565 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 464 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 566 DCHECK(!callback.is_null()); | 465 DCHECK(!callback.is_null()); |
| 567 | 466 |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 578 | 477 |
| 579 // Unpinning a file means its entry must exist in cache. | 478 // Unpinning a file means its entry must exist in cache. |
| 580 FileCacheEntry cache_entry; | 479 FileCacheEntry cache_entry; |
| 581 if (!GetCacheEntry(resource_id, md5, &cache_entry)) { | 480 if (!GetCacheEntry(resource_id, md5, &cache_entry)) { |
| 582 LOG(WARNING) << "Can't unpin a file that wasn't pinned or cached: res_id=" | 481 LOG(WARNING) << "Can't unpin a file that wasn't pinned or cached: res_id=" |
| 583 << resource_id | 482 << resource_id |
| 584 << ", md5=" << md5; | 483 << ", md5=" << md5; |
| 585 return FILE_ERROR_NOT_FOUND; | 484 return FILE_ERROR_NOT_FOUND; |
| 586 } | 485 } |
| 587 | 486 |
| 588 CacheSubDirectoryType sub_dir_type = CACHE_TYPE_TMP; | |
| 589 | |
| 590 // If file is dirty or mounted, don't move it. | |
| 591 if (cache_entry.is_dirty() || cache_entry.is_mounted()) { | |
| 592 sub_dir_type = CACHE_TYPE_PERSISTENT; | |
| 593 DCHECK(cache_entry.is_persistent()); | |
| 594 } else { | |
| 595 // If file was pinned but actual file blob still doesn't exist in cache, | |
| 596 // don't need to move the file. | |
| 597 if (cache_entry.is_present()) { | |
| 598 // Gets the current path of the file in cache. | |
| 599 base::FilePath source_path = GetCacheFilePath( | |
| 600 resource_id, | |
| 601 md5, | |
| 602 GetSubDirectoryType(cache_entry), | |
| 603 CACHED_FILE_FROM_SERVER); | |
| 604 // File exists, move it to tmp dir. | |
| 605 base::FilePath dest_path = GetCacheFilePath( | |
| 606 resource_id, | |
| 607 md5, | |
| 608 CACHE_TYPE_TMP, | |
| 609 CACHED_FILE_FROM_SERVER); | |
| 610 if (!MoveFile(source_path, dest_path)) | |
| 611 return FILE_ERROR_FAILED; | |
| 612 } | |
| 613 } | |
| 614 | |
| 615 // Now that file operations have completed, update metadata. | 487 // Now that file operations have completed, update metadata. |
| 616 if (cache_entry.is_present()) { | 488 if (cache_entry.is_present()) { |
| 617 cache_entry.set_md5(md5); | 489 cache_entry.set_md5(md5); |
| 618 cache_entry.set_is_pinned(false); | 490 cache_entry.set_is_pinned(false); |
| 619 cache_entry.set_is_persistent(sub_dir_type == CACHE_TYPE_PERSISTENT); | |
| 620 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry); | 491 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry); |
| 621 } else { | 492 } else { |
| 622 // Remove the existing entry if we are unpinning a non-present file. | 493 // Remove the existing entry if we are unpinning a non-present file. |
| 623 metadata_->RemoveCacheEntry(resource_id); | 494 metadata_->RemoveCacheEntry(resource_id); |
| 624 } | 495 } |
| 625 | 496 |
| 626 // Now the file is moved from "persistent" to "tmp" directory. | 497 // Now it's a chance to free up space if needed. |
| 627 // It's a chance to free up space if needed. | |
| 628 FreeDiskSpaceIfNeededFor(0); | 498 FreeDiskSpaceIfNeededFor(0); |
| 629 | 499 |
| 630 return FILE_ERROR_OK; | 500 return FILE_ERROR_OK; |
| 631 } | 501 } |
| 632 | 502 |
| 633 void FileCache::MarkAsMountedOnUIThread( | 503 void FileCache::MarkAsMountedOnUIThread( |
| 634 const std::string& resource_id, | 504 const std::string& resource_id, |
| 635 const GetFileFromCacheCallback& callback) { | 505 const GetFileFromCacheCallback& callback) { |
| 636 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 506 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 637 DCHECK(!callback.is_null()); | 507 DCHECK(!callback.is_null()); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 687 // cache. | 557 // cache. |
| 688 FileCacheEntry cache_entry; | 558 FileCacheEntry cache_entry; |
| 689 if (!metadata_->GetCacheEntry(resource_id, &cache_entry) || | 559 if (!metadata_->GetCacheEntry(resource_id, &cache_entry) || |
| 690 !cache_entry.is_present()) { | 560 !cache_entry.is_present()) { |
| 691 LOG(WARNING) << "Can't mark dirty a file that wasn't cached: res_id=" | 561 LOG(WARNING) << "Can't mark dirty a file that wasn't cached: res_id=" |
| 692 << resource_id | 562 << resource_id |
| 693 << ", md5=" << md5; | 563 << ", md5=" << md5; |
| 694 return FILE_ERROR_NOT_FOUND; | 564 return FILE_ERROR_NOT_FOUND; |
| 695 } | 565 } |
| 696 | 566 |
| 697 if (cache_entry.is_dirty()) { | 567 if (cache_entry.is_dirty()) |
| 698 // The file must be in persistent dir. | |
| 699 DCHECK(cache_entry.is_persistent()); | |
| 700 return FILE_ERROR_OK; | 568 return FILE_ERROR_OK; |
| 701 } | |
| 702 | |
| 703 // Move file to persistent dir with new .local extension. | |
| 704 | 569 |
| 705 // Get the current path of the file in cache. | 570 // Get the current path of the file in cache. |
| 706 base::FilePath source_path = GetCacheFilePath( | 571 base::FilePath source_path = GetCacheFilePath(resource_id, md5, |
| 707 resource_id, | 572 CACHED_FILE_FROM_SERVER); |
| 708 md5, | |
| 709 GetSubDirectoryType(cache_entry), | |
| 710 CACHED_FILE_FROM_SERVER); | |
| 711 // Determine destination path. | 573 // Determine destination path. |
| 712 const CacheSubDirectoryType sub_dir_type = CACHE_TYPE_PERSISTENT; | |
| 713 base::FilePath cache_file_path = GetCacheFilePath( | 574 base::FilePath cache_file_path = GetCacheFilePath( |
| 714 resource_id, | 575 resource_id, md5, CACHED_FILE_LOCALLY_MODIFIED); |
| 715 md5, | |
| 716 sub_dir_type, | |
| 717 CACHED_FILE_LOCALLY_MODIFIED); | |
| 718 | 576 |
| 719 if (!MoveFile(source_path, cache_file_path)) | 577 if (!MoveFile(source_path, cache_file_path)) |
| 720 return FILE_ERROR_FAILED; | 578 return FILE_ERROR_FAILED; |
| 721 | 579 |
| 722 // Now that file operations have completed, update metadata. | 580 // Now that file operations have completed, update metadata. |
| 723 cache_entry.set_md5(md5); | 581 cache_entry.set_md5(md5); |
| 724 cache_entry.set_is_dirty(true); | 582 cache_entry.set_is_dirty(true); |
| 725 cache_entry.set_is_persistent(sub_dir_type == CACHE_TYPE_PERSISTENT); | |
| 726 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry); | 583 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry); |
| 727 return FILE_ERROR_OK; | 584 return FILE_ERROR_OK; |
| 728 } | 585 } |
| 729 | 586 |
| 730 FileError FileCache::ClearDirty(const std::string& resource_id, | 587 FileError FileCache::ClearDirty(const std::string& resource_id, |
| 731 const std::string& md5) { | 588 const std::string& md5) { |
| 732 AssertOnSequencedWorkerPool(); | 589 AssertOnSequencedWorkerPool(); |
| 733 | 590 |
| 734 // |md5| is the new .<md5> extension to rename the file to. | 591 // |md5| is the new .<md5> extension to rename the file to. |
| 735 // So, search for entry in cache without comparing md5. | 592 // So, search for entry in cache without comparing md5. |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 747 | 604 |
| 748 // If a file is not dirty (it should have been marked dirty via | 605 // If a file is not dirty (it should have been marked dirty via |
| 749 // MarkDirtyInCache), clearing its dirty state is an invalid operation. | 606 // MarkDirtyInCache), clearing its dirty state is an invalid operation. |
| 750 if (!cache_entry.is_dirty()) { | 607 if (!cache_entry.is_dirty()) { |
| 751 LOG(WARNING) << "Can't clear dirty state of a non-dirty file: res_id=" | 608 LOG(WARNING) << "Can't clear dirty state of a non-dirty file: res_id=" |
| 752 << resource_id | 609 << resource_id |
| 753 << ", md5=" << md5; | 610 << ", md5=" << md5; |
| 754 return FILE_ERROR_INVALID_OPERATION; | 611 return FILE_ERROR_INVALID_OPERATION; |
| 755 } | 612 } |
| 756 | 613 |
| 757 // File must be dirty and hence in persistent dir. | 614 base::FilePath source_path = GetCacheFilePath(resource_id, md5, |
| 758 DCHECK(cache_entry.is_persistent()); | 615 CACHED_FILE_LOCALLY_MODIFIED); |
| 759 | 616 base::FilePath dest_path = GetCacheFilePath(resource_id, md5, |
| 760 // Get the current path of the file in cache. | |
| 761 base::FilePath source_path = | |
| 762 GetCacheFilePath(resource_id, | |
| 763 md5, | |
| 764 GetSubDirectoryType(cache_entry), | |
| 765 CACHED_FILE_LOCALLY_MODIFIED); | |
| 766 | |
| 767 // Determine destination path. | |
| 768 // If file is pinned, move it to persistent dir with .md5 extension; | |
| 769 // otherwise, move it to tmp dir with .md5 extension. | |
| 770 const CacheSubDirectoryType sub_dir_type = | |
| 771 cache_entry.is_pinned() ? CACHE_TYPE_PERSISTENT : CACHE_TYPE_TMP; | |
| 772 base::FilePath dest_path = GetCacheFilePath(resource_id, | |
| 773 md5, | |
| 774 sub_dir_type, | |
| 775 CACHED_FILE_FROM_SERVER); | 617 CACHED_FILE_FROM_SERVER); |
| 776 | |
| 777 if (!MoveFile(source_path, dest_path)) | 618 if (!MoveFile(source_path, dest_path)) |
| 778 return FILE_ERROR_FAILED; | 619 return FILE_ERROR_FAILED; |
| 779 | 620 |
| 780 // Now that file operations have completed, update metadata. | 621 // Now that file operations have completed, update metadata. |
| 781 cache_entry.set_md5(md5); | 622 cache_entry.set_md5(md5); |
| 782 cache_entry.set_is_dirty(false); | 623 cache_entry.set_is_dirty(false); |
| 783 cache_entry.set_is_persistent(sub_dir_type == CACHE_TYPE_PERSISTENT); | |
| 784 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry); | 624 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry); |
| 785 return FILE_ERROR_OK; | 625 return FILE_ERROR_OK; |
| 786 } | 626 } |
| 787 | 627 |
| 788 void FileCache::RemoveOnUIThread(const std::string& resource_id, | 628 void FileCache::RemoveOnUIThread(const std::string& resource_id, |
| 789 const FileOperationCallback& callback) { | 629 const FileOperationCallback& callback) { |
| 790 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 630 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 791 DCHECK(!callback.is_null()); | 631 DCHECK(!callback.is_null()); |
| 792 | 632 |
| 793 base::PostTaskAndReplyWithResult( | 633 base::PostTaskAndReplyWithResult( |
| 794 blocking_task_runner_, | 634 blocking_task_runner_, |
| 795 FROM_HERE, | 635 FROM_HERE, |
| 796 base::Bind(&FileCache::Remove, | 636 base::Bind(&FileCache::Remove, |
| 797 base::Unretained(this), resource_id), | 637 base::Unretained(this), resource_id), |
| 798 callback); | 638 callback); |
| 799 } | 639 } |
| 800 | 640 |
| 801 FileError FileCache::Remove(const std::string& resource_id) { | 641 FileError FileCache::Remove(const std::string& resource_id) { |
| 802 AssertOnSequencedWorkerPool(); | 642 AssertOnSequencedWorkerPool(); |
| 803 | 643 |
| 804 // MD5 is not passed into RemoveCacheEntry because we would delete all | 644 // MD5 is not passed into RemoveCacheEntry because we would delete all |
| 805 // cache files corresponding to <resource_id> regardless of the md5. | 645 // cache files corresponding to <resource_id> regardless of the md5. |
| 806 // So, search for entry in cache without taking md5 into account. | 646 // So, search for entry in cache without taking md5 into account. |
| 807 FileCacheEntry cache_entry; | 647 FileCacheEntry cache_entry; |
| 808 | 648 |
| 809 // If entry doesn't exist or is dirty or mounted in cache, nothing to do. | 649 // If entry doesn't exist or is dirty or mounted in cache, nothing to do. |
| 810 const bool entry_found = metadata_->GetCacheEntry(resource_id, &cache_entry); | 650 if (!metadata_->GetCacheEntry(resource_id, &cache_entry) || |
| 811 if (!entry_found || cache_entry.is_dirty() || cache_entry.is_mounted()) { | 651 cache_entry.is_dirty() || |
| 812 DVLOG(1) << "Entry is " | 652 cache_entry.is_mounted()) |
| 813 << (entry_found ? | |
| 814 (cache_entry.is_dirty() ? "dirty" : "mounted") : | |
| 815 "non-existent") | |
| 816 << " in cache, not removing"; | |
| 817 return FILE_ERROR_OK; | 653 return FILE_ERROR_OK; |
| 818 } | |
| 819 | 654 |
| 820 // Determine paths to delete all cache versions of |resource_id| in | 655 // Delete files that match "<resource_id>.*" unless modified locally. |
| 821 // persistent, tmp and pinned directories. | 656 base::FilePath path_to_delete = GetCacheFilePath(resource_id, util::kWildCard, |
| 822 std::vector<base::FilePath> paths_to_delete; | 657 CACHED_FILE_FROM_SERVER); |
| 823 | 658 base::FilePath path_to_keep = GetCacheFilePath(resource_id, std::string(), |
| 824 // For files in persistent and tmp dirs, delete files that match | |
| 825 // "<resource_id>.*". | |
| 826 paths_to_delete.push_back(GetCacheFilePath(resource_id, | |
| 827 util::kWildCard, | |
| 828 CACHE_TYPE_PERSISTENT, | |
| 829 CACHED_FILE_FROM_SERVER)); | |
| 830 paths_to_delete.push_back(GetCacheFilePath(resource_id, | |
| 831 util::kWildCard, | |
| 832 CACHE_TYPE_TMP, | |
| 833 CACHED_FILE_FROM_SERVER)); | |
| 834 | |
| 835 // Don't delete locally modified files. | |
| 836 base::FilePath path_to_keep = GetCacheFilePath(resource_id, | |
| 837 std::string(), | |
| 838 CACHE_TYPE_PERSISTENT, | |
| 839 CACHED_FILE_LOCALLY_MODIFIED); | 659 CACHED_FILE_LOCALLY_MODIFIED); |
| 840 | 660 DeleteFilesSelectively(path_to_delete, path_to_keep); |
| 841 for (size_t i = 0; i < paths_to_delete.size(); ++i) { | |
| 842 DeleteFilesSelectively(paths_to_delete[i], path_to_keep); | |
| 843 } | |
| 844 | 661 |
| 845 // Now that all file operations have completed, remove from metadata. | 662 // Now that all file operations have completed, remove from metadata. |
| 846 metadata_->RemoveCacheEntry(resource_id); | 663 metadata_->RemoveCacheEntry(resource_id); |
| 847 | 664 |
| 848 return FILE_ERROR_OK; | 665 return FILE_ERROR_OK; |
| 849 } | 666 } |
| 850 | 667 |
| 851 void FileCache::ClearAllOnUIThread(const InitializeCacheCallback& callback) { | 668 void FileCache::ClearAllOnUIThread(const InitializeCacheCallback& callback) { |
| 852 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 669 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 853 DCHECK(!callback.is_null()); | 670 DCHECK(!callback.is_null()); |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 880 // Note that base::DeletePointer<> cannot be used as the destructor of this | 697 // Note that base::DeletePointer<> cannot be used as the destructor of this |
| 881 // class is private. | 698 // class is private. |
| 882 blocking_task_runner_->PostTask( | 699 blocking_task_runner_->PostTask( |
| 883 FROM_HERE, | 700 FROM_HERE, |
| 884 base::Bind(&FileCache::DestroyOnBlockingPool, base::Unretained(this))); | 701 base::Bind(&FileCache::DestroyOnBlockingPool, base::Unretained(this))); |
| 885 } | 702 } |
| 886 | 703 |
| 887 bool FileCache::InitializeOnBlockingPool() { | 704 bool FileCache::InitializeOnBlockingPool() { |
| 888 AssertOnSequencedWorkerPool(); | 705 AssertOnSequencedWorkerPool(); |
| 889 | 706 |
| 707 MigrateFilesFromOldDirectories(); | |
|
kinaba
2013/06/14 01:59:33
How about moving this migration after InitCachePat
hashimoto
2013/06/14 04:04:46
Done.
| |
| 708 | |
| 890 if (!InitCachePaths(cache_paths_)) | 709 if (!InitCachePaths(cache_paths_)) |
| 891 return false; | 710 return false; |
| 892 | 711 |
| 893 metadata_.reset(new FileCacheMetadata(blocking_task_runner_)); | 712 metadata_.reset(new FileCacheMetadata(blocking_task_runner_)); |
| 894 | 713 |
| 895 switch (metadata_->Initialize(cache_paths_[CACHE_TYPE_META])) { | 714 switch (metadata_->Initialize(cache_paths_[CACHE_TYPE_META])) { |
| 896 case FileCacheMetadata::INITIALIZE_FAILED: | 715 case FileCacheMetadata::INITIALIZE_FAILED: |
| 897 return false; | 716 return false; |
| 898 | 717 |
| 899 case FileCacheMetadata::INITIALIZE_OPENED: // Do nothing. | 718 case FileCacheMetadata::INITIALIZE_OPENED: // Do nothing. |
| 900 break; | 719 break; |
| 901 | 720 |
| 902 case FileCacheMetadata::INITIALIZE_CREATED: { | 721 case FileCacheMetadata::INITIALIZE_CREATED: { |
| 903 CacheMap cache_map; | 722 CacheMap cache_map; |
| 904 ScanCachePaths(cache_paths_, &cache_map); | 723 ScanCacheDirectory(cache_paths_[CACHE_TYPE_FILES], &cache_map); |
| 905 for (CacheMap::const_iterator it = cache_map.begin(); | 724 for (CacheMap::const_iterator it = cache_map.begin(); |
| 906 it != cache_map.end(); ++it) { | 725 it != cache_map.end(); ++it) { |
| 907 metadata_->AddOrUpdateCacheEntry(it->first, it->second); | 726 metadata_->AddOrUpdateCacheEntry(it->first, it->second); |
| 908 } | 727 } |
| 909 break; | 728 break; |
| 910 } | 729 } |
| 911 } | 730 } |
| 912 return true; | 731 return true; |
| 913 } | 732 } |
| 914 | 733 |
| 915 void FileCache::DestroyOnBlockingPool() { | 734 void FileCache::DestroyOnBlockingPool() { |
| 916 AssertOnSequencedWorkerPool(); | 735 AssertOnSequencedWorkerPool(); |
| 917 delete this; | 736 delete this; |
| 918 } | 737 } |
| 919 | 738 |
| 739 void FileCache::MigrateFilesFromOldDirectories() { | |
| 740 const base::FilePath persistent_directory = | |
| 741 cache_root_path_.AppendASCII("persistent"); | |
| 742 const base::FilePath tmp_directory = cache_root_path_.AppendASCII("tmp"); | |
| 743 if (!file_util::PathExists(persistent_directory)) | |
| 744 return; | |
| 745 | |
| 746 // Create "files". | |
|
kinaba
2013/06/14 01:59:33
...then this creation is not needed.
| |
| 747 if (!file_util::CreateDirectory(cache_paths_[CACHE_TYPE_FILES])) | |
| 748 return; | |
| 749 | |
| 750 // Move all files inside "persistent" to "files". | |
| 751 MoveAllFilesFromDirectory(persistent_directory, | |
| 752 cache_paths_[CACHE_TYPE_FILES]); | |
| 753 file_util::Delete(persistent_directory, true /* recursive */); | |
| 754 | |
| 755 // Move all files inside "tmp" to "files". | |
| 756 MoveAllFilesFromDirectory(tmp_directory, cache_paths_[CACHE_TYPE_FILES]); | |
| 757 file_util::Delete(tmp_directory, true /* recursive */); | |
| 758 } | |
| 759 | |
| 920 FileError FileCache::StoreInternal(const std::string& resource_id, | 760 FileError FileCache::StoreInternal(const std::string& resource_id, |
| 921 const std::string& md5, | 761 const std::string& md5, |
| 922 const base::FilePath& source_path, | 762 const base::FilePath& source_path, |
| 923 FileOperationType file_operation_type) { | 763 FileOperationType file_operation_type) { |
| 924 AssertOnSequencedWorkerPool(); | 764 AssertOnSequencedWorkerPool(); |
| 925 | 765 |
| 926 int64 file_size = 0; | 766 int64 file_size = 0; |
| 927 if (file_operation_type == FILE_OPERATION_COPY) { | 767 if (file_operation_type == FILE_OPERATION_COPY) { |
| 928 if (!file_util::GetFileSize(source_path, &file_size)) { | 768 if (!file_util::GetFileSize(source_path, &file_size)) { |
| 929 LOG(WARNING) << "Couldn't get file size for: " << source_path.value(); | 769 LOG(WARNING) << "Couldn't get file size for: " << source_path.value(); |
| 930 return FILE_ERROR_FAILED; | 770 return FILE_ERROR_FAILED; |
| 931 } | 771 } |
| 932 } | 772 } |
| 933 if (!FreeDiskSpaceIfNeededFor(file_size)) | 773 if (!FreeDiskSpaceIfNeededFor(file_size)) |
| 934 return FILE_ERROR_NO_SPACE; | 774 return FILE_ERROR_NO_SPACE; |
| 935 | 775 |
| 936 FileCacheEntry cache_entry; | 776 FileCacheEntry cache_entry; |
| 937 metadata_->GetCacheEntry(resource_id, &cache_entry); | 777 metadata_->GetCacheEntry(resource_id, &cache_entry); |
| 938 | 778 |
| 939 CacheSubDirectoryType sub_dir_type = CACHE_TYPE_TMP; | |
| 940 // If file is dirty or mounted, return error. | 779 // If file is dirty or mounted, return error. |
| 941 if (cache_entry.is_dirty() || cache_entry.is_mounted()) { | 780 if (cache_entry.is_dirty() || cache_entry.is_mounted()) |
| 942 LOG(WARNING) << "Can't store a file to replace a " | |
| 943 << (cache_entry.is_dirty() ? "dirty" : "mounted") | |
| 944 << " file: res_id=" << resource_id | |
| 945 << ", md5=" << md5; | |
| 946 return FILE_ERROR_IN_USE; | 781 return FILE_ERROR_IN_USE; |
| 947 } | |
| 948 | 782 |
| 949 // If file was previously pinned, store it in persistent dir. | 783 base::FilePath dest_path = GetCacheFilePath(resource_id, md5, |
| 950 if (cache_entry.is_pinned()) | |
| 951 sub_dir_type = CACHE_TYPE_PERSISTENT; | |
| 952 | |
| 953 base::FilePath dest_path = GetCacheFilePath(resource_id, md5, sub_dir_type, | |
| 954 CACHED_FILE_FROM_SERVER); | 784 CACHED_FILE_FROM_SERVER); |
| 955 bool success = false; | 785 bool success = false; |
| 956 switch (file_operation_type) { | 786 switch (file_operation_type) { |
| 957 case FILE_OPERATION_MOVE: | 787 case FILE_OPERATION_MOVE: |
| 958 success = MoveFile(source_path, dest_path); | 788 success = MoveFile(source_path, dest_path); |
| 959 break; | 789 break; |
| 960 case FILE_OPERATION_COPY: | 790 case FILE_OPERATION_COPY: |
| 961 success = CopyFile(source_path, dest_path); | 791 success = CopyFile(source_path, dest_path); |
| 962 break; | 792 break; |
| 963 default: | 793 default: |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 983 stale_filenames_pattern = dest_path.ReplaceExtension(util::kWildCard); | 813 stale_filenames_pattern = dest_path.ReplaceExtension(util::kWildCard); |
| 984 } | 814 } |
| 985 | 815 |
| 986 // Delete files that match |stale_filenames_pattern| except for |dest_path|. | 816 // Delete files that match |stale_filenames_pattern| except for |dest_path|. |
| 987 DeleteFilesSelectively(stale_filenames_pattern, dest_path); | 817 DeleteFilesSelectively(stale_filenames_pattern, dest_path); |
| 988 | 818 |
| 989 if (success) { | 819 if (success) { |
| 990 // Now that file operations have completed, update metadata. | 820 // Now that file operations have completed, update metadata. |
| 991 cache_entry.set_md5(md5); | 821 cache_entry.set_md5(md5); |
| 992 cache_entry.set_is_present(true); | 822 cache_entry.set_is_present(true); |
| 993 cache_entry.set_is_persistent(sub_dir_type == CACHE_TYPE_PERSISTENT); | |
| 994 cache_entry.set_is_dirty(false); | 823 cache_entry.set_is_dirty(false); |
| 995 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry); | 824 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry); |
| 996 } | 825 } |
| 997 | 826 |
| 998 return success ? FILE_ERROR_OK : FILE_ERROR_FAILED; | 827 return success ? FILE_ERROR_OK : FILE_ERROR_FAILED; |
| 999 } | 828 } |
| 1000 | 829 |
| 1001 FileError FileCache::MarkAsMounted(const std::string& resource_id, | 830 FileError FileCache::MarkAsMounted(const std::string& resource_id, |
| 1002 base::FilePath* cache_file_path) { | 831 base::FilePath* cache_file_path) { |
| 1003 AssertOnSequencedWorkerPool(); | 832 AssertOnSequencedWorkerPool(); |
| 1004 DCHECK(cache_file_path); | 833 DCHECK(cache_file_path); |
| 1005 | 834 |
| 1006 // Get cache entry associated with the resource_id and md5 | 835 // Get cache entry associated with the resource_id and md5 |
| 1007 FileCacheEntry cache_entry; | 836 FileCacheEntry cache_entry; |
| 1008 if (!metadata_->GetCacheEntry(resource_id, &cache_entry)) | 837 if (!metadata_->GetCacheEntry(resource_id, &cache_entry)) |
| 1009 return FILE_ERROR_NOT_FOUND; | 838 return FILE_ERROR_NOT_FOUND; |
| 1010 | 839 |
| 1011 if (cache_entry.is_mounted()) | 840 if (cache_entry.is_mounted()) |
| 1012 return FILE_ERROR_INVALID_OPERATION; | 841 return FILE_ERROR_INVALID_OPERATION; |
| 1013 | 842 |
| 1014 // Get the subdir type and path for the unmounted state. | 843 // Move cache file. |
| 1015 CacheSubDirectoryType unmounted_subdir = | |
| 1016 cache_entry.is_pinned() ? CACHE_TYPE_PERSISTENT : CACHE_TYPE_TMP; | |
| 1017 base::FilePath unmounted_path = GetCacheFilePath( | 844 base::FilePath unmounted_path = GetCacheFilePath( |
| 1018 resource_id, cache_entry.md5(), unmounted_subdir, | 845 resource_id, cache_entry.md5(), CACHED_FILE_FROM_SERVER); |
| 1019 CACHED_FILE_FROM_SERVER); | |
| 1020 | |
| 1021 // Get the subdir type and path for the mounted state. | |
| 1022 CacheSubDirectoryType mounted_subdir = CACHE_TYPE_PERSISTENT; | |
| 1023 base::FilePath mounted_path = GetCacheFilePath( | 846 base::FilePath mounted_path = GetCacheFilePath( |
| 1024 resource_id, cache_entry.md5(), mounted_subdir, CACHED_FILE_MOUNTED); | 847 resource_id, cache_entry.md5(), CACHED_FILE_MOUNTED); |
| 1025 | |
| 1026 // Move cache file. | |
| 1027 if (!MoveFile(unmounted_path, mounted_path)) | 848 if (!MoveFile(unmounted_path, mounted_path)) |
| 1028 return FILE_ERROR_FAILED; | 849 return FILE_ERROR_FAILED; |
| 1029 | 850 |
| 1030 // Ensures the file is readable to cros_disks. See crbug.com/236994. | 851 // Ensures the file is readable to cros_disks. See crbug.com/236994. |
| 1031 file_util::SetPosixFilePermissions( | 852 file_util::SetPosixFilePermissions( |
| 1032 mounted_path, | 853 mounted_path, |
| 1033 file_util::FILE_PERMISSION_READ_BY_USER | | 854 file_util::FILE_PERMISSION_READ_BY_USER | |
| 1034 file_util::FILE_PERMISSION_WRITE_BY_USER | | 855 file_util::FILE_PERMISSION_WRITE_BY_USER | |
| 1035 file_util::FILE_PERMISSION_READ_BY_GROUP | | 856 file_util::FILE_PERMISSION_READ_BY_GROUP | |
| 1036 file_util::FILE_PERMISSION_READ_BY_OTHERS); | 857 file_util::FILE_PERMISSION_READ_BY_OTHERS); |
| 1037 | 858 |
| 1038 // Now that cache operation is complete, update metadata. | 859 // Now that cache operation is complete, update metadata. |
| 1039 cache_entry.set_is_mounted(true); | 860 cache_entry.set_is_mounted(true); |
| 1040 cache_entry.set_is_persistent(true); | |
| 1041 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry); | 861 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry); |
| 1042 | 862 |
| 1043 *cache_file_path = mounted_path; | 863 *cache_file_path = mounted_path; |
| 1044 return FILE_ERROR_OK; | 864 return FILE_ERROR_OK; |
| 1045 } | 865 } |
| 1046 | 866 |
| 1047 FileError FileCache::MarkAsUnmounted(const base::FilePath& file_path) { | 867 FileError FileCache::MarkAsUnmounted(const base::FilePath& file_path) { |
| 1048 AssertOnSequencedWorkerPool(); | 868 AssertOnSequencedWorkerPool(); |
| 1049 DCHECK(IsUnderFileCacheDirectory(file_path)); | 869 DCHECK(IsUnderFileCacheDirectory(file_path)); |
| 1050 | 870 |
| 1051 // Parse file path to obtain resource_id, md5 and extra_extension. | 871 // Parse file path to obtain resource_id, md5 and extra_extension. |
| 1052 std::string resource_id; | 872 std::string resource_id; |
| 1053 std::string md5; | 873 std::string md5; |
| 1054 std::string extra_extension; | 874 std::string extra_extension; |
| 1055 util::ParseCacheFilePath(file_path, &resource_id, &md5, &extra_extension); | 875 util::ParseCacheFilePath(file_path, &resource_id, &md5, &extra_extension); |
| 1056 // The extra_extension shall be ".mounted" iff we're unmounting. | 876 // The extra_extension shall be ".mounted" iff we're unmounting. |
| 1057 DCHECK_EQ(util::kMountedArchiveFileExtension, extra_extension); | 877 DCHECK_EQ(util::kMountedArchiveFileExtension, extra_extension); |
| 1058 | 878 |
| 1059 // Get cache entry associated with the resource_id and md5 | 879 // Get cache entry associated with the resource_id and md5 |
| 1060 FileCacheEntry cache_entry; | 880 FileCacheEntry cache_entry; |
| 1061 if (!GetCacheEntry(resource_id, md5, &cache_entry)) | 881 if (!GetCacheEntry(resource_id, md5, &cache_entry)) |
| 1062 return FILE_ERROR_NOT_FOUND; | 882 return FILE_ERROR_NOT_FOUND; |
| 1063 | 883 |
| 1064 if (!cache_entry.is_mounted()) | 884 if (!cache_entry.is_mounted()) |
| 1065 return FILE_ERROR_INVALID_OPERATION; | 885 return FILE_ERROR_INVALID_OPERATION; |
| 1066 | 886 |
| 1067 // Get the subdir type and path for the unmounted state. | 887 // Move cache file. |
| 1068 CacheSubDirectoryType unmounted_subdir = | |
| 1069 cache_entry.is_pinned() ? CACHE_TYPE_PERSISTENT : CACHE_TYPE_TMP; | |
| 1070 base::FilePath unmounted_path = GetCacheFilePath( | 888 base::FilePath unmounted_path = GetCacheFilePath( |
| 1071 resource_id, md5, unmounted_subdir, CACHED_FILE_FROM_SERVER); | 889 resource_id, md5, CACHED_FILE_FROM_SERVER); |
| 1072 | |
| 1073 // Get the subdir type and path for the mounted state. | |
| 1074 CacheSubDirectoryType mounted_subdir = CACHE_TYPE_PERSISTENT; | |
| 1075 base::FilePath mounted_path = GetCacheFilePath( | 890 base::FilePath mounted_path = GetCacheFilePath( |
| 1076 resource_id, md5, mounted_subdir, CACHED_FILE_MOUNTED); | 891 resource_id, md5, CACHED_FILE_MOUNTED); |
| 1077 | |
| 1078 // Move cache file. | |
| 1079 if (!MoveFile(mounted_path, unmounted_path)) | 892 if (!MoveFile(mounted_path, unmounted_path)) |
| 1080 return FILE_ERROR_FAILED; | 893 return FILE_ERROR_FAILED; |
| 1081 | 894 |
| 1082 // Now that cache operation is complete, update metadata. | 895 // Now that cache operation is complete, update metadata. |
| 1083 cache_entry.set_md5(md5); | 896 cache_entry.set_md5(md5); |
| 1084 cache_entry.set_is_mounted(false); | 897 cache_entry.set_is_mounted(false); |
| 1085 cache_entry.set_is_persistent(unmounted_subdir == CACHE_TYPE_PERSISTENT); | |
| 1086 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry); | 898 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry); |
| 1087 return FILE_ERROR_OK; | 899 return FILE_ERROR_OK; |
| 1088 } | 900 } |
| 1089 | 901 |
| 1090 bool FileCache::ClearAll() { | 902 bool FileCache::ClearAll() { |
| 1091 AssertOnSequencedWorkerPool(); | 903 AssertOnSequencedWorkerPool(); |
| 1092 | 904 |
| 1093 if (!file_util::Delete(cache_root_path_, true)) { | 905 if (!file_util::Delete(cache_root_path_, true)) { |
| 1094 LOG(WARNING) << "Failed to delete the cache directory"; | 906 LOG(WARNING) << "Failed to delete the cache directory"; |
| 1095 return false; | 907 return false; |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 1114 free_space -= kMinFreeSpace; | 926 free_space -= kMinFreeSpace; |
| 1115 return (free_space >= num_bytes); | 927 return (free_space >= num_bytes); |
| 1116 } | 928 } |
| 1117 | 929 |
| 1118 // static | 930 // static |
| 1119 std::vector<base::FilePath> FileCache::GetCachePaths( | 931 std::vector<base::FilePath> FileCache::GetCachePaths( |
| 1120 const base::FilePath& cache_root_path) { | 932 const base::FilePath& cache_root_path) { |
| 1121 std::vector<base::FilePath> cache_paths; | 933 std::vector<base::FilePath> cache_paths; |
| 1122 // The order should match FileCache::CacheSubDirectoryType enum. | 934 // The order should match FileCache::CacheSubDirectoryType enum. |
| 1123 cache_paths.push_back(cache_root_path.Append(kFileCacheMetaDir)); | 935 cache_paths.push_back(cache_root_path.Append(kFileCacheMetaDir)); |
| 1124 cache_paths.push_back(cache_root_path.Append(kFileCachePersistentDir)); | 936 cache_paths.push_back(cache_root_path.Append(kFileCacheFilesDir)); |
| 1125 cache_paths.push_back(cache_root_path.Append(kFileCacheTmpDir)); | |
| 1126 cache_paths.push_back(cache_root_path.Append(kFileCacheTmpDownloadsDir)); | 937 cache_paths.push_back(cache_root_path.Append(kFileCacheTmpDownloadsDir)); |
| 1127 cache_paths.push_back(cache_root_path.Append(kFileCacheTmpDocumentsDir)); | 938 cache_paths.push_back(cache_root_path.Append(kFileCacheTmpDocumentsDir)); |
| 1128 return cache_paths; | 939 return cache_paths; |
| 1129 } | 940 } |
| 1130 | 941 |
| 1131 // static | 942 // static |
| 1132 bool FileCache::CreateCacheDirectories( | 943 bool FileCache::CreateCacheDirectories( |
| 1133 const std::vector<base::FilePath>& paths_to_create) { | 944 const std::vector<base::FilePath>& paths_to_create) { |
| 1134 bool success = true; | 945 bool success = true; |
| 1135 | 946 |
| 1136 for (size_t i = 0; i < paths_to_create.size(); ++i) { | 947 for (size_t i = 0; i < paths_to_create.size(); ++i) { |
| 1137 if (file_util::DirectoryExists(paths_to_create[i])) | 948 if (file_util::DirectoryExists(paths_to_create[i])) |
| 1138 continue; | 949 continue; |
| 1139 | 950 |
| 1140 if (!file_util::CreateDirectory(paths_to_create[i])) { | 951 if (!file_util::CreateDirectory(paths_to_create[i])) { |
| 1141 // Error creating this directory, record error and proceed with next one. | 952 // Error creating this directory, record error and proceed with next one. |
| 1142 success = false; | 953 success = false; |
| 1143 PLOG(ERROR) << "Error creating directory " << paths_to_create[i].value(); | 954 PLOG(ERROR) << "Error creating directory " << paths_to_create[i].value(); |
| 1144 } else { | 955 } else { |
| 1145 DVLOG(1) << "Created directory " << paths_to_create[i].value(); | 956 DVLOG(1) << "Created directory " << paths_to_create[i].value(); |
| 1146 } | 957 } |
| 1147 } | 958 } |
| 1148 return success; | 959 return success; |
| 1149 } | 960 } |
| 1150 | 961 |
| 1151 // static | |
| 1152 FileCache::CacheSubDirectoryType FileCache::GetSubDirectoryType( | |
| 1153 const FileCacheEntry& cache_entry) { | |
| 1154 return cache_entry.is_persistent() ? CACHE_TYPE_PERSISTENT : CACHE_TYPE_TMP; | |
| 1155 } | |
| 1156 | |
| 1157 } // namespace internal | 962 } // namespace internal |
| 1158 } // namespace drive | 963 } // namespace drive |
| OLD | NEW |