blob: d072f47b7dd7b3370b098b3dd7f12faa2ee255ba [file] [log] [blame]
[email protected]3653146a2012-05-29 13:41:471// 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
[email protected]15de8142012-10-11 06:00:545#include "chrome/browser/chromeos/drive/drive_cache.h"
[email protected]3653146a2012-05-29 13:41:476
7#include <vector>
8
[email protected]a321b9632012-06-14 03:29:179#include "base/file_util.h"
[email protected]3653146a2012-05-29 13:41:4710#include "base/logging.h"
11#include "base/stringprintf.h"
12#include "base/string_util.h"
[email protected]a321b9632012-06-14 03:29:1713#include "base/sys_info.h"
[email protected]bdd947c2012-11-06 04:35:3414#include "base/task_runner_util.h"
[email protected]15de8142012-10-11 06:00:5415#include "chrome/browser/chromeos/drive/drive.pb.h"
16#include "chrome/browser/chromeos/drive/drive_cache_metadata.h"
17#include "chrome/browser/chromeos/drive/drive_cache_observer.h"
18#include "chrome/browser/chromeos/drive/drive_file_system_util.h"
[email protected]d68ede02012-11-07 14:30:5319#include "chrome/browser/google_apis/task_util.h"
[email protected]01ba15f72012-06-09 00:41:0520#include "chrome/browser/profiles/profile.h"
21#include "chrome/common/chrome_constants.h"
22#include "chrome/common/chrome_paths_internal.h"
[email protected]7986b8d2012-06-14 15:05:1423#include "content/public/browser/browser_thread.h"
24
25using content::BrowserThread;
[email protected]3653146a2012-05-29 13:41:4726
[email protected]d9d04df2012-10-12 07:06:3527namespace drive {
[email protected]3653146a2012-05-29 13:41:4728namespace {
29
[email protected]650b2d52013-02-10 03:41:4530const base::FilePath::CharType kDriveCacheVersionDir[] =
31 FILE_PATH_LITERAL("v1");
32const base::FilePath::CharType kDriveCacheMetaDir[] = FILE_PATH_LITERAL("meta");
[email protected]650b2d52013-02-10 03:41:4533const base::FilePath::CharType kDriveCacheOutgoingDir[] =
[email protected]32a7fc852012-06-08 17:25:5034 FILE_PATH_LITERAL("outgoing");
[email protected]650b2d52013-02-10 03:41:4535const base::FilePath::CharType kDriveCachePersistentDir[] =
[email protected]32a7fc852012-06-08 17:25:5036 FILE_PATH_LITERAL("persistent");
[email protected]650b2d52013-02-10 03:41:4537const base::FilePath::CharType kDriveCacheTmpDir[] = FILE_PATH_LITERAL("tmp");
38const base::FilePath::CharType kDriveCacheTmpDownloadsDir[] =
[email protected]32a7fc852012-06-08 17:25:5039 FILE_PATH_LITERAL("tmp/downloads");
[email protected]650b2d52013-02-10 03:41:4540const base::FilePath::CharType kDriveCacheTmpDocumentsDir[] =
[email protected]32a7fc852012-06-08 17:25:5041 FILE_PATH_LITERAL("tmp/documents");
42
[email protected]79c3752d2012-07-17 12:10:0843// Create cache directory paths and set permissions.
[email protected]650b2d52013-02-10 03:41:4544bool InitCachePaths(const std::vector<base::FilePath>& cache_paths) {
[email protected]fb371812012-08-22 16:05:2345 if (cache_paths.size() < DriveCache::NUM_CACHE_TYPES) {
[email protected]79c3752d2012-07-17 12:10:0846 NOTREACHED();
47 LOG(ERROR) << "Size of cache_paths is invalid.";
[email protected]322e0032012-10-07 01:55:5348 return false;
[email protected]79c3752d2012-07-17 12:10:0849 }
50
[email protected]fb371812012-08-22 16:05:2351 if (!DriveCache::CreateCacheDirectories(cache_paths))
[email protected]322e0032012-10-07 01:55:5352 return false;
[email protected]79c3752d2012-07-17 12:10:0853
54 // Change permissions of cache persistent directory to u+rwx,og+x (711) in
55 // order to allow archive files in that directory to be mounted by cros-disks.
56 file_util::SetPosixFilePermissions(
[email protected]fb371812012-08-22 16:05:2357 cache_paths[DriveCache::CACHE_TYPE_PERSISTENT],
[email protected]79c3752d2012-07-17 12:10:0858 file_util::FILE_PERMISSION_USER_MASK |
59 file_util::FILE_PERMISSION_EXECUTE_BY_GROUP |
60 file_util::FILE_PERMISSION_EXECUTE_BY_OTHERS);
[email protected]322e0032012-10-07 01:55:5361
62 return true;
[email protected]79c3752d2012-07-17 12:10:0863}
64
[email protected]a321b9632012-06-14 03:29:1765// Remove all files under the given directory, non-recursively.
[email protected]d7754f52012-08-01 08:45:3366// Do not remove recursively as we don't want to touch <gcache>/tmp/downloads,
[email protected]a321b9632012-06-14 03:29:1767// which is used for user initiated downloads like "Save As"
[email protected]650b2d52013-02-10 03:41:4568void RemoveAllFiles(const base::FilePath& directory) {
[email protected]a321b9632012-06-14 03:29:1769 using file_util::FileEnumerator;
70
71 FileEnumerator enumerator(directory, false /* recursive */,
72 FileEnumerator::FILES);
[email protected]650b2d52013-02-10 03:41:4573 for (base::FilePath file_path = enumerator.Next(); !file_path.empty();
[email protected]a321b9632012-06-14 03:29:1774 file_path = enumerator.Next()) {
75 DVLOG(1) << "Removing " << file_path.value();
76 if (!file_util::Delete(file_path, false /* recursive */))
77 LOG(WARNING) << "Failed to delete " << file_path.value();
78 }
79}
80
[email protected]c80ca12f2012-11-09 10:56:0381// Deletes the symlink.
[email protected]650b2d52013-02-10 03:41:4582void DeleteSymlink(const base::FilePath& symlink_path) {
[email protected]a321b9632012-06-14 03:29:1783 // We try to save one file operation by not checking if link exists before
84 // deleting it, so unlink may return error if link doesn't exist, but it
85 // doesn't really matter to us.
[email protected]750af1d2012-07-13 14:32:4386 file_util::Delete(symlink_path, false);
[email protected]c80ca12f2012-11-09 10:56:0387}
[email protected]a321b9632012-06-14 03:29:1788
[email protected]c80ca12f2012-11-09 10:56:0389// Creates a symlink.
[email protected]650b2d52013-02-10 03:41:4590bool CreateSymlink(const base::FilePath& cache_file_path,
91 const base::FilePath& symlink_path) {
[email protected]c80ca12f2012-11-09 10:56:0392 // Remove symlink because creating a link will not overwrite an existing one.
93 DeleteSymlink(symlink_path);
[email protected]a321b9632012-06-14 03:29:1794
[email protected]c80ca12f2012-11-09 10:56:0395 // Create new symlink to |cache_file_path|.
96 if (!file_util::CreateSymbolicLink(cache_file_path, symlink_path)) {
[email protected]750af1d2012-07-13 14:32:4397 LOG(ERROR) << "Failed to create a symlink from " << symlink_path.value()
[email protected]c80ca12f2012-11-09 10:56:0398 << " to " << cache_file_path.value();
99 return false;
[email protected]a321b9632012-06-14 03:29:17100 }
[email protected]c80ca12f2012-11-09 10:56:03101 return true;
102}
[email protected]a321b9632012-06-14 03:29:17103
[email protected]c80ca12f2012-11-09 10:56:03104// Moves the file.
[email protected]650b2d52013-02-10 03:41:45105bool MoveFile(const base::FilePath& source_path,
106 const base::FilePath& dest_path) {
[email protected]c80ca12f2012-11-09 10:56:03107 if (!file_util::Move(source_path, dest_path)) {
108 LOG(ERROR) << "Failed to move " << source_path.value()
109 << " to " << dest_path.value();
110 return false;
111 }
112 DVLOG(1) << "Moved " << source_path.value() << " to " << dest_path.value();
113 return true;
114}
115
116// Copies the file.
[email protected]650b2d52013-02-10 03:41:45117bool CopyFile(const base::FilePath& source_path,
118 const base::FilePath& dest_path) {
[email protected]c80ca12f2012-11-09 10:56:03119 if (!file_util::CopyFile(source_path, dest_path)) {
120 LOG(ERROR) << "Failed to copy " << source_path.value()
121 << " to " << dest_path.value();
122 return false;
123 }
124 DVLOG(1) << "Copied " << source_path.value() << " to " << dest_path.value();
125 return true;
[email protected]a321b9632012-06-14 03:29:17126}
127
128// Deletes all files that match |path_to_delete_pattern| except for
129// |path_to_keep| on blocking pool.
130// If |path_to_keep| is empty, all files in |path_to_delete_pattern| are
131// deleted.
[email protected]650b2d52013-02-10 03:41:45132void DeleteFilesSelectively(const base::FilePath& path_to_delete_pattern,
133 const base::FilePath& path_to_keep) {
[email protected]a321b9632012-06-14 03:29:17134 // Enumerate all files in directory of |path_to_delete_pattern| that match
135 // base name of |path_to_delete_pattern|.
136 // If a file is not |path_to_keep|, delete it.
137 bool success = true;
[email protected]84c3f162012-08-12 01:57:23138 file_util::FileEnumerator enumerator(path_to_delete_pattern.DirName(),
[email protected]a321b9632012-06-14 03:29:17139 false, // not recursive
[email protected]84c3f162012-08-12 01:57:23140 file_util::FileEnumerator::FILES |
141 file_util::FileEnumerator::SHOW_SYM_LINKS,
[email protected]a321b9632012-06-14 03:29:17142 path_to_delete_pattern.BaseName().value());
[email protected]650b2d52013-02-10 03:41:45143 for (base::FilePath current = enumerator.Next(); !current.empty();
[email protected]a321b9632012-06-14 03:29:17144 current = enumerator.Next()) {
145 // If |path_to_keep| is not empty and same as current, don't delete it.
146 if (!path_to_keep.empty() && current == path_to_keep)
147 continue;
148
[email protected]0b8d4cee2012-07-02 20:46:26149 success = file_util::Delete(current, false);
[email protected]a321b9632012-06-14 03:29:17150 if (!success)
151 DVLOG(1) << "Error deleting " << current.value();
152 else
153 DVLOG(1) << "Deleted " << current.value();
154 }
155}
156
[email protected]7986b8d2012-06-14 15:05:14157// Runs callback with pointers dereferenced.
[email protected]9564c1502012-11-28 12:12:16158// Used to implement GetFile, MarkAsMounted.
[email protected]bdd947c2012-11-06 04:35:34159void RunGetFileFromCacheCallback(
160 const GetFileFromCacheCallback& callback,
[email protected]78a158b2013-04-23 06:57:49161 scoped_ptr<std::pair<FileError, base::FilePath> > result) {
[email protected]c960d222012-06-15 10:03:50162 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]9564c1502012-11-28 12:12:16163 DCHECK(!callback.is_null());
[email protected]bdd947c2012-11-06 04:35:34164 DCHECK(result.get());
[email protected]c960d222012-06-15 10:03:50165
[email protected]9564c1502012-11-28 12:12:16166 callback.Run(result->first, result->second);
[email protected]c960d222012-06-15 10:03:50167}
168
[email protected]8764a392012-06-20 06:43:08169// Runs callback with pointers dereferenced.
[email protected]77fb1a62012-11-01 13:42:32170// Used to implement GetCacheEntry().
171void RunGetCacheEntryCallback(const GetCacheEntryCallback& callback,
[email protected]bdd947c2012-11-06 04:35:34172 DriveCacheEntry* cache_entry,
173 bool success) {
[email protected]4324fdc2012-06-29 05:32:48174 DCHECK(cache_entry);
[email protected]bdd947c2012-11-06 04:35:34175 DCHECK(!callback.is_null());
176 callback.Run(success, *cache_entry);
[email protected]322e0032012-10-07 01:55:53177}
178
[email protected]a321b9632012-06-14 03:29:17179} // namespace
[email protected]32a7fc852012-06-08 17:25:50180
[email protected]650b2d52013-02-10 03:41:45181DriveCache::DriveCache(const base::FilePath& cache_root_path,
[email protected]f6fd98a2012-12-14 00:04:02182 base::SequencedTaskRunner* blocking_task_runner,
183 FreeDiskSpaceGetterInterface* free_disk_space_getter)
[email protected]01ba15f72012-06-09 00:41:05184 : cache_root_path_(cache_root_path),
[email protected]6b70c7b2012-06-14 03:10:43185 cache_paths_(GetCachePaths(cache_root_path_)),
[email protected]ddbf2052012-07-13 15:07:02186 blocking_task_runner_(blocking_task_runner),
[email protected]f6fd98a2012-12-14 00:04:02187 free_disk_space_getter_(free_disk_space_getter),
[email protected]dc2e8f7b2012-08-30 20:22:44188 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
[email protected]17196ee2012-12-13 06:23:51189 DCHECK(blocking_task_runner_);
[email protected]73f9c742012-06-15 07:37:13190 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]3653146a2012-05-29 13:41:47191}
192
[email protected]fb371812012-08-22 16:05:23193DriveCache::~DriveCache() {
[email protected]17196ee2012-12-13 06:23:51194 // Must be on the sequenced worker pool, as |metadata_| must be deleted on
195 // the sequenced worker pool.
[email protected]73f9c742012-06-15 07:37:13196 AssertOnSequencedWorkerPool();
[email protected]3653146a2012-05-29 13:41:47197}
198
[email protected]650b2d52013-02-10 03:41:45199base::FilePath DriveCache::GetCacheDirectoryPath(
[email protected]32a7fc852012-06-08 17:25:50200 CacheSubDirectoryType sub_dir_type) const {
201 DCHECK_LE(0, sub_dir_type);
202 DCHECK_GT(NUM_CACHE_TYPES, sub_dir_type);
203 return cache_paths_[sub_dir_type];
204}
205
[email protected]650b2d52013-02-10 03:41:45206base::FilePath DriveCache::GetCacheFilePath(
207 const std::string& resource_id,
208 const std::string& md5,
209 CacheSubDirectoryType sub_dir_type,
210 CachedFileOrigin file_origin) const {
[email protected]32a7fc852012-06-08 17:25:50211 DCHECK(sub_dir_type != CACHE_TYPE_META);
212
213 // Runs on any thread.
214 // Filename is formatted as resource_id.md5, i.e. resource_id is the base
215 // name and md5 is the extension.
216 std::string base_name = util::EscapeCacheFileName(resource_id);
217 if (file_origin == CACHED_FILE_LOCALLY_MODIFIED) {
218 DCHECK(sub_dir_type == CACHE_TYPE_PERSISTENT);
[email protected]650b2d52013-02-10 03:41:45219 base_name += base::FilePath::kExtensionSeparator;
[email protected]b83e5202012-06-27 07:50:24220 base_name += util::kLocallyModifiedFileExtension;
[email protected]32a7fc852012-06-08 17:25:50221 } else if (!md5.empty()) {
[email protected]650b2d52013-02-10 03:41:45222 base_name += base::FilePath::kExtensionSeparator;
[email protected]32a7fc852012-06-08 17:25:50223 base_name += util::EscapeCacheFileName(md5);
224 }
225 // For mounted archives the filename is formatted as resource_id.md5.mounted,
226 // i.e. resource_id.md5 is the base name and ".mounted" is the extension
227 if (file_origin == CACHED_FILE_MOUNTED) {
[email protected]a321b9632012-06-14 03:29:17228 DCHECK(sub_dir_type == CACHE_TYPE_PERSISTENT);
[email protected]650b2d52013-02-10 03:41:45229 base_name += base::FilePath::kExtensionSeparator;
[email protected]ca5f6da2012-06-18 12:54:59230 base_name += util::kMountedArchiveFileExtension;
[email protected]32a7fc852012-06-08 17:25:50231 }
232 return GetCacheDirectoryPath(sub_dir_type).Append(base_name);
233}
234
[email protected]fb371812012-08-22 16:05:23235void DriveCache::AssertOnSequencedWorkerPool() {
[email protected]ddbf2052012-07-13 15:07:02236 DCHECK(!blocking_task_runner_ ||
237 blocking_task_runner_->RunsTasksOnCurrentThread());
[email protected]fcc92a52012-06-08 22:54:16238}
239
[email protected]650b2d52013-02-10 03:41:45240bool DriveCache::IsUnderDriveCacheDirectory(const base::FilePath& path) const {
[email protected]01ba15f72012-06-09 00:41:05241 return cache_root_path_ == path || cache_root_path_.IsParent(path);
242}
243
[email protected]a09275502012-10-10 04:48:01244void DriveCache::AddObserver(DriveCacheObserver* observer) {
[email protected]73f9c742012-06-15 07:37:13245 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
246 observers_.AddObserver(observer);
247}
248
[email protected]a09275502012-10-10 04:48:01249void DriveCache::RemoveObserver(DriveCacheObserver* observer) {
[email protected]73f9c742012-06-15 07:37:13250 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
251 observers_.RemoveObserver(observer);
252}
253
[email protected]77fb1a62012-11-01 13:42:32254void DriveCache::GetCacheEntry(const std::string& resource_id,
255 const std::string& md5,
256 const GetCacheEntryCallback& callback) {
[email protected]4324fdc2012-06-29 05:32:48257 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]bdd947c2012-11-06 04:35:34258 DCHECK(!callback.is_null());
[email protected]4324fdc2012-06-29 05:32:48259
[email protected]28a64092012-08-21 10:01:12260 DriveCacheEntry* cache_entry = new DriveCacheEntry;
[email protected]bdd947c2012-11-06 04:35:34261 base::PostTaskAndReplyWithResult(
262 blocking_task_runner_,
[email protected]4324fdc2012-06-29 05:32:48263 FROM_HERE,
[email protected]bdd947c2012-11-06 04:35:34264 base::Bind(&DriveCache::GetCacheEntryOnBlockingPool,
[email protected]3f5e2902012-11-06 08:21:15265 base::Unretained(this), resource_id, md5, cache_entry),
[email protected]4324fdc2012-06-29 05:32:48266 base::Bind(&RunGetCacheEntryCallback,
[email protected]3f5e2902012-11-06 08:21:15267 callback, base::Owned(cache_entry)));
[email protected]4324fdc2012-06-29 05:32:48268}
269
[email protected]d68ede02012-11-07 14:30:53270void DriveCache::Iterate(const CacheIterateCallback& iteration_callback,
271 const base::Closure& completion_callback) {
[email protected]8764a392012-06-20 06:43:08272 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]d68ede02012-11-07 14:30:53273 DCHECK(!iteration_callback.is_null());
274 DCHECK(!completion_callback.is_null());
[email protected]8764a392012-06-20 06:43:08275
[email protected]ddbf2052012-07-13 15:07:02276 blocking_task_runner_->PostTaskAndReply(
[email protected]8764a392012-06-20 06:43:08277 FROM_HERE,
[email protected]d68ede02012-11-07 14:30:53278 base::Bind(&DriveCache::IterateOnBlockingPool,
279 base::Unretained(this),
280 google_apis::CreateRelayCallback(iteration_callback)),
281 completion_callback);
[email protected]cd236432012-07-27 18:03:30282}
283
[email protected]f423c0b2012-11-22 09:51:10284void DriveCache::FreeDiskSpaceIfNeededFor(
285 int64 num_bytes,
286 const InitializeCacheCallback& callback) {
287 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
288 DCHECK(!callback.is_null());
[email protected]a321b9632012-06-14 03:29:17289
[email protected]f423c0b2012-11-22 09:51:10290 base::PostTaskAndReplyWithResult(
291 blocking_task_runner_,
292 FROM_HERE,
293 base::Bind(&DriveCache::FreeDiskSpaceOnBlockingPoolIfNeededFor,
294 base::Unretained(this),
295 num_bytes),
296 callback);
[email protected]a321b9632012-06-14 03:29:17297}
298
[email protected]77fb1a62012-11-01 13:42:32299void DriveCache::GetFile(const std::string& resource_id,
300 const std::string& md5,
301 const GetFileFromCacheCallback& callback) {
[email protected]c960d222012-06-15 10:03:50302 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]bdd947c2012-11-06 04:35:34303 DCHECK(!callback.is_null());
[email protected]a321b9632012-06-14 03:29:17304
[email protected]bdd947c2012-11-06 04:35:34305 base::PostTaskAndReplyWithResult(
306 blocking_task_runner_,
[email protected]c960d222012-06-15 10:03:50307 FROM_HERE,
[email protected]77fb1a62012-11-01 13:42:32308 base::Bind(&DriveCache::GetFileOnBlockingPool,
[email protected]bdd947c2012-11-06 04:35:34309 base::Unretained(this), resource_id, md5),
310 base::Bind(&RunGetFileFromCacheCallback, callback));
[email protected]a321b9632012-06-14 03:29:17311}
312
[email protected]77fb1a62012-11-01 13:42:32313void DriveCache::Store(const std::string& resource_id,
314 const std::string& md5,
[email protected]650b2d52013-02-10 03:41:45315 const base::FilePath& source_path,
[email protected]77fb1a62012-11-01 13:42:32316 FileOperationType file_operation_type,
[email protected]2a2c4152012-11-26 11:34:50317 const FileOperationCallback& callback) {
[email protected]73f9c742012-06-15 07:37:13318 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]2a2c4152012-11-26 11:34:50319 DCHECK(!callback.is_null());
[email protected]73f9c742012-06-15 07:37:13320
[email protected]bdd947c2012-11-06 04:35:34321 base::PostTaskAndReplyWithResult(
322 blocking_task_runner_,
[email protected]73f9c742012-06-15 07:37:13323 FROM_HERE,
[email protected]77fb1a62012-11-01 13:42:32324 base::Bind(&DriveCache::StoreOnBlockingPool,
[email protected]73f9c742012-06-15 07:37:13325 base::Unretained(this),
[email protected]3f5e2902012-11-06 08:21:15326 resource_id, md5, source_path, file_operation_type),
[email protected]2a2c4152012-11-26 11:34:50327 callback);
[email protected]73f9c742012-06-15 07:37:13328}
329
[email protected]77fb1a62012-11-01 13:42:32330void DriveCache::Pin(const std::string& resource_id,
331 const std::string& md5,
[email protected]2a2c4152012-11-26 11:34:50332 const FileOperationCallback& callback) {
[email protected]73f9c742012-06-15 07:37:13333 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]2a2c4152012-11-26 11:34:50334 DCHECK(!callback.is_null());
[email protected]73f9c742012-06-15 07:37:13335
[email protected]bdd947c2012-11-06 04:35:34336 base::PostTaskAndReplyWithResult(
337 blocking_task_runner_,
[email protected]73f9c742012-06-15 07:37:13338 FROM_HERE,
[email protected]77fb1a62012-11-01 13:42:32339 base::Bind(&DriveCache::PinOnBlockingPool,
[email protected]3f5e2902012-11-06 08:21:15340 base::Unretained(this), resource_id, md5),
[email protected]fb371812012-08-22 16:05:23341 base::Bind(&DriveCache::OnPinned,
[email protected]3f5e2902012-11-06 08:21:15342 weak_ptr_factory_.GetWeakPtr(), resource_id, md5, callback));
[email protected]73f9c742012-06-15 07:37:13343}
344
[email protected]77fb1a62012-11-01 13:42:32345void DriveCache::Unpin(const std::string& resource_id,
346 const std::string& md5,
[email protected]2a2c4152012-11-26 11:34:50347 const FileOperationCallback& callback) {
[email protected]73f9c742012-06-15 07:37:13348 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]2a2c4152012-11-26 11:34:50349 DCHECK(!callback.is_null());
350
[email protected]bdd947c2012-11-06 04:35:34351 base::PostTaskAndReplyWithResult(
352 blocking_task_runner_,
[email protected]73f9c742012-06-15 07:37:13353 FROM_HERE,
[email protected]77fb1a62012-11-01 13:42:32354 base::Bind(&DriveCache::UnpinOnBlockingPool,
[email protected]3f5e2902012-11-06 08:21:15355 base::Unretained(this), resource_id, md5),
[email protected]fb371812012-08-22 16:05:23356 base::Bind(&DriveCache::OnUnpinned,
[email protected]3f5e2902012-11-06 08:21:15357 weak_ptr_factory_.GetWeakPtr(), resource_id, md5, callback));
[email protected]73f9c742012-06-15 07:37:13358}
359
[email protected]35c1f9b2013-02-07 07:39:42360void DriveCache::MarkAsMounted(const std::string& resource_id,
361 const std::string& md5,
[email protected]9564c1502012-11-28 12:12:16362 const GetFileFromCacheCallback& callback) {
[email protected]73f9c742012-06-15 07:37:13363 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]9564c1502012-11-28 12:12:16364 DCHECK(!callback.is_null());
[email protected]73f9c742012-06-15 07:37:13365
[email protected]bdd947c2012-11-06 04:35:34366 base::PostTaskAndReplyWithResult(
367 blocking_task_runner_,
[email protected]73f9c742012-06-15 07:37:13368 FROM_HERE,
[email protected]9564c1502012-11-28 12:12:16369 base::Bind(&DriveCache::MarkAsMountedOnBlockingPool,
[email protected]35c1f9b2013-02-07 07:39:42370 base::Unretained(this), resource_id, md5),
[email protected]bdd947c2012-11-06 04:35:34371 base::Bind(RunGetFileFromCacheCallback, callback));
[email protected]73f9c742012-06-15 07:37:13372}
373
[email protected]650b2d52013-02-10 03:41:45374void DriveCache::MarkAsUnmounted(const base::FilePath& file_path,
[email protected]9564c1502012-11-28 12:12:16375 const FileOperationCallback& callback) {
376 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
377 DCHECK(!callback.is_null());
378
379 base::PostTaskAndReplyWithResult(
380 blocking_task_runner_,
381 FROM_HERE,
382 base::Bind(&DriveCache::MarkAsUnmountedOnBlockingPool,
383 base::Unretained(this), file_path),
384 callback);
385}
386
[email protected]77fb1a62012-11-01 13:42:32387void DriveCache::MarkDirty(const std::string& resource_id,
388 const std::string& md5,
[email protected]bc809e42012-11-28 04:46:29389 const FileOperationCallback& callback) {
[email protected]c960d222012-06-15 10:03:50390 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]bdd947c2012-11-06 04:35:34391 DCHECK(!callback.is_null());
[email protected]73f9c742012-06-15 07:37:13392
[email protected]bdd947c2012-11-06 04:35:34393 base::PostTaskAndReplyWithResult(
394 blocking_task_runner_,
[email protected]c960d222012-06-15 10:03:50395 FROM_HERE,
[email protected]77fb1a62012-11-01 13:42:32396 base::Bind(&DriveCache::MarkDirtyOnBlockingPool,
[email protected]bdd947c2012-11-06 04:35:34397 base::Unretained(this), resource_id, md5),
[email protected]bc809e42012-11-28 04:46:29398 callback);
[email protected]73f9c742012-06-15 07:37:13399}
400
[email protected]77fb1a62012-11-01 13:42:32401void DriveCache::CommitDirty(const std::string& resource_id,
402 const std::string& md5,
[email protected]2a2c4152012-11-26 11:34:50403 const FileOperationCallback& callback) {
[email protected]73f9c742012-06-15 07:37:13404 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]2a2c4152012-11-26 11:34:50405 DCHECK(!callback.is_null());
[email protected]73f9c742012-06-15 07:37:13406
[email protected]bdd947c2012-11-06 04:35:34407 base::PostTaskAndReplyWithResult(
408 blocking_task_runner_,
[email protected]73f9c742012-06-15 07:37:13409 FROM_HERE,
[email protected]77fb1a62012-11-01 13:42:32410 base::Bind(&DriveCache::CommitDirtyOnBlockingPool,
[email protected]3f5e2902012-11-06 08:21:15411 base::Unretained(this), resource_id, md5),
[email protected]fb371812012-08-22 16:05:23412 base::Bind(&DriveCache::OnCommitDirty,
[email protected]2a2c4152012-11-26 11:34:50413 weak_ptr_factory_.GetWeakPtr(), resource_id, callback));
[email protected]73f9c742012-06-15 07:37:13414}
415
[email protected]77fb1a62012-11-01 13:42:32416void DriveCache::ClearDirty(const std::string& resource_id,
417 const std::string& md5,
[email protected]2a2c4152012-11-26 11:34:50418 const FileOperationCallback& callback) {
[email protected]73f9c742012-06-15 07:37:13419 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]2a2c4152012-11-26 11:34:50420 DCHECK(!callback.is_null());
[email protected]73f9c742012-06-15 07:37:13421
[email protected]bdd947c2012-11-06 04:35:34422 base::PostTaskAndReplyWithResult(
423 blocking_task_runner_,
[email protected]73f9c742012-06-15 07:37:13424 FROM_HERE,
[email protected]77fb1a62012-11-01 13:42:32425 base::Bind(&DriveCache::ClearDirtyOnBlockingPool,
[email protected]3f5e2902012-11-06 08:21:15426 base::Unretained(this), resource_id, md5),
[email protected]2a2c4152012-11-26 11:34:50427 callback);
[email protected]73f9c742012-06-15 07:37:13428}
429
[email protected]77fb1a62012-11-01 13:42:32430void DriveCache::Remove(const std::string& resource_id,
[email protected]2a2c4152012-11-26 11:34:50431 const FileOperationCallback& callback) {
[email protected]73f9c742012-06-15 07:37:13432 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]2a2c4152012-11-26 11:34:50433 DCHECK(!callback.is_null());
[email protected]73f9c742012-06-15 07:37:13434
[email protected]bdd947c2012-11-06 04:35:34435 base::PostTaskAndReplyWithResult(
436 blocking_task_runner_,
[email protected]73f9c742012-06-15 07:37:13437 FROM_HERE,
[email protected]77fb1a62012-11-01 13:42:32438 base::Bind(&DriveCache::RemoveOnBlockingPool,
[email protected]3f5e2902012-11-06 08:21:15439 base::Unretained(this), resource_id),
[email protected]2a2c4152012-11-26 11:34:50440 callback);
[email protected]73f9c742012-06-15 07:37:13441}
442
[email protected]bdd947c2012-11-06 04:35:34443void DriveCache::ClearAll(const InitializeCacheCallback& callback) {
[email protected]f861b392012-08-03 20:41:12444 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]bdd947c2012-11-06 04:35:34445 DCHECK(!callback.is_null());
[email protected]f861b392012-08-03 20:41:12446
[email protected]bdd947c2012-11-06 04:35:34447 base::PostTaskAndReplyWithResult(
448 blocking_task_runner_,
[email protected]f861b392012-08-03 20:41:12449 FROM_HERE,
[email protected]bdd947c2012-11-06 04:35:34450 base::Bind(&DriveCache::ClearAllOnBlockingPool, base::Unretained(this)),
451 callback);
[email protected]f861b392012-08-03 20:41:12452}
453
[email protected]77fb1a62012-11-01 13:42:32454void DriveCache::RequestInitialize(const InitializeCacheCallback& callback) {
[email protected]73f9c742012-06-15 07:37:13455 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]322e0032012-10-07 01:55:53456 DCHECK(!callback.is_null());
[email protected]73f9c742012-06-15 07:37:13457
[email protected]bdd947c2012-11-06 04:35:34458 base::PostTaskAndReplyWithResult(
459 blocking_task_runner_,
[email protected]73f9c742012-06-15 07:37:13460 FROM_HERE,
[email protected]bdd947c2012-11-06 04:35:34461 base::Bind(&DriveCache::InitializeOnBlockingPool, base::Unretained(this)),
462 callback);
[email protected]73f9c742012-06-15 07:37:13463}
464
[email protected]77fb1a62012-11-01 13:42:32465void DriveCache::RequestInitializeForTesting() {
[email protected]d310bfc2012-08-10 09:41:28466 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
467
468 blocking_task_runner_->PostTask(
469 FROM_HERE,
[email protected]77fb1a62012-11-01 13:42:32470 base::Bind(&DriveCache::InitializeOnBlockingPoolForTesting,
471 base::Unretained(this)));
[email protected]d310bfc2012-08-10 09:41:28472}
473
[email protected]77fb1a62012-11-01 13:42:32474void DriveCache::Destroy() {
[email protected]73f9c742012-06-15 07:37:13475 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
476
477 // Invalidate the weak pointer.
[email protected]e53ac8f2012-08-02 07:05:00478 weak_ptr_factory_.InvalidateWeakPtrs();
[email protected]73f9c742012-06-15 07:37:13479
480 // Destroy myself on the blocking pool.
[email protected]17196ee2012-12-13 06:23:51481 // Note that base::DeletePointer<> cannot be used as the destructor of this
482 // class is private.
[email protected]ddbf2052012-07-13 15:07:02483 blocking_task_runner_->PostTask(
[email protected]73f9c742012-06-15 07:37:13484 FROM_HERE,
[email protected]3f5e2902012-11-06 08:21:15485 base::Bind(&DriveCache::DestroyOnBlockingPool, base::Unretained(this)));
[email protected]73f9c742012-06-15 07:37:13486}
487
[email protected]bdd947c2012-11-06 04:35:34488bool DriveCache::InitializeOnBlockingPool() {
[email protected]ca5f6da2012-06-18 12:54:59489 AssertOnSequencedWorkerPool();
490
[email protected]bdd947c2012-11-06 04:35:34491 if (!InitCachePaths(cache_paths_))
492 return false;
[email protected]322e0032012-10-07 01:55:53493
[email protected]fb371812012-08-22 16:05:23494 metadata_ = DriveCacheMetadata::CreateDriveCacheMetadata(
[email protected]f5532c42012-11-21 10:39:56495 blocking_task_runner_);
[email protected]bdd947c2012-11-06 04:35:34496 return metadata_->Initialize(cache_paths_);
[email protected]ca5f6da2012-06-18 12:54:59497}
498
[email protected]77fb1a62012-11-01 13:42:32499void DriveCache::InitializeOnBlockingPoolForTesting() {
[email protected]d310bfc2012-08-10 09:41:28500 AssertOnSequencedWorkerPool();
501
502 InitCachePaths(cache_paths_);
[email protected]fb371812012-08-22 16:05:23503 metadata_ = DriveCacheMetadata::CreateDriveCacheMetadataForTesting(
[email protected]f5532c42012-11-21 10:39:56504 blocking_task_runner_);
[email protected]d310bfc2012-08-10 09:41:28505 metadata_->Initialize(cache_paths_);
506}
507
[email protected]77fb1a62012-11-01 13:42:32508void DriveCache::DestroyOnBlockingPool() {
[email protected]73f9c742012-06-15 07:37:13509 AssertOnSequencedWorkerPool();
510 delete this;
511}
512
[email protected]717e43c2012-11-22 07:47:39513bool DriveCache::GetCacheEntryOnBlockingPool(const std::string& resource_id,
514 const std::string& md5,
515 DriveCacheEntry* entry) {
516 DCHECK(entry);
517 AssertOnSequencedWorkerPool();
518 return metadata_->GetCacheEntry(resource_id, md5, entry);
519}
520
[email protected]d68ede02012-11-07 14:30:53521void DriveCache::IterateOnBlockingPool(
522 const CacheIterateCallback& iteration_callback) {
[email protected]8764a392012-06-20 06:43:08523 AssertOnSequencedWorkerPool();
[email protected]d68ede02012-11-07 14:30:53524 DCHECK(!iteration_callback.is_null());
[email protected]8764a392012-06-20 06:43:08525
[email protected]d68ede02012-11-07 14:30:53526 metadata_->Iterate(iteration_callback);
[email protected]cd236432012-07-27 18:03:30527}
528
[email protected]f423c0b2012-11-22 09:51:10529bool DriveCache::FreeDiskSpaceOnBlockingPoolIfNeededFor(int64 num_bytes) {
530 AssertOnSequencedWorkerPool();
531
532 // Do nothing and return if we have enough space.
533 if (HasEnoughSpaceFor(num_bytes, cache_root_path_))
534 return true;
535
536 // Otherwise, try to free up the disk space.
537 DVLOG(1) << "Freeing up disk space for " << num_bytes;
538 // First remove temporary files from the metadata.
539 metadata_->RemoveTemporaryFiles();
540 // Then remove all files under "tmp" directory.
541 RemoveAllFiles(GetCacheDirectoryPath(CACHE_TYPE_TMP));
542
543 // Check the disk space again.
544 return HasEnoughSpaceFor(num_bytes, cache_root_path_);
545}
546
[email protected]bdd947c2012-11-06 04:35:34547scoped_ptr<DriveCache::GetFileResult> DriveCache::GetFileOnBlockingPool(
548 const std::string& resource_id,
549 const std::string& md5) {
[email protected]c960d222012-06-15 10:03:50550 AssertOnSequencedWorkerPool();
[email protected]bdd947c2012-11-06 04:35:34551
552 scoped_ptr<GetFileResult> result(new GetFileResult);
[email protected]c960d222012-06-15 10:03:50553
[email protected]28a64092012-08-21 10:01:12554 DriveCacheEntry cache_entry;
[email protected]bdd947c2012-11-06 04:35:34555 if (!GetCacheEntryOnBlockingPool(resource_id, md5, &cache_entry) ||
556 !cache_entry.is_present()) {
[email protected]78a158b2013-04-23 06:57:49557 result->first = FILE_ERROR_NOT_FOUND;
[email protected]bdd947c2012-11-06 04:35:34558 return result.Pass();
[email protected]c960d222012-06-15 10:03:50559 }
[email protected]bdd947c2012-11-06 04:35:34560
561 CachedFileOrigin file_origin;
562 if (cache_entry.is_mounted()) {
563 file_origin = CACHED_FILE_MOUNTED;
564 } else if (cache_entry.is_dirty()) {
565 file_origin = CACHED_FILE_LOCALLY_MODIFIED;
566 } else {
567 file_origin = CACHED_FILE_FROM_SERVER;
568 }
[email protected]78a158b2013-04-23 06:57:49569 result->first = FILE_ERROR_OK;
[email protected]bdd947c2012-11-06 04:35:34570 result->second = GetCacheFilePath(resource_id,
571 md5,
572 GetSubDirectoryType(cache_entry),
573 file_origin);
574 return result.Pass();
[email protected]c960d222012-06-15 10:03:50575}
576
[email protected]78a158b2013-04-23 06:57:49577FileError DriveCache::StoreOnBlockingPool(
[email protected]bdd947c2012-11-06 04:35:34578 const std::string& resource_id,
579 const std::string& md5,
[email protected]650b2d52013-02-10 03:41:45580 const base::FilePath& source_path,
[email protected]bdd947c2012-11-06 04:35:34581 FileOperationType file_operation_type) {
[email protected]a321b9632012-06-14 03:29:17582 AssertOnSequencedWorkerPool();
[email protected]a321b9632012-06-14 03:29:17583
[email protected]fb1b37b2013-04-09 04:37:49584 int64 file_size = 0;
[email protected]f0c67002012-08-15 04:10:38585 if (file_operation_type == FILE_OPERATION_COPY) {
[email protected]f0c67002012-08-15 04:10:38586 if (!file_util::GetFileSize(source_path, &file_size)) {
587 LOG(WARNING) << "Couldn't get file size for: " << source_path.value();
[email protected]78a158b2013-04-23 06:57:49588 return FILE_ERROR_FAILED;
[email protected]f0c67002012-08-15 04:10:38589 }
[email protected]f0c67002012-08-15 04:10:38590 }
[email protected]fb1b37b2013-04-09 04:37:49591 if (!FreeDiskSpaceOnBlockingPoolIfNeededFor(file_size))
[email protected]78a158b2013-04-23 06:57:49592 return FILE_ERROR_NO_SPACE;
[email protected]f0c67002012-08-15 04:10:38593
[email protected]650b2d52013-02-10 03:41:45594 base::FilePath symlink_path;
[email protected]a321b9632012-06-14 03:29:17595 CacheSubDirectoryType sub_dir_type = CACHE_TYPE_TMP;
596
[email protected]c80ca12f2012-11-09 10:56:03597 // If file was previously pinned, store it in persistent dir.
[email protected]28a64092012-08-21 10:01:12598 DriveCacheEntry cache_entry;
[email protected]77fb1a62012-11-01 13:42:32599 if (GetCacheEntryOnBlockingPool(resource_id, md5, &cache_entry)) {
600 // File exists in cache.
[email protected]a321b9632012-06-14 03:29:17601 // If file is dirty or mounted, return error.
[email protected]02821102012-07-12 20:19:17602 if (cache_entry.is_dirty() || cache_entry.is_mounted()) {
[email protected]a321b9632012-06-14 03:29:17603 LOG(WARNING) << "Can't store a file to replace a "
[email protected]02821102012-07-12 20:19:17604 << (cache_entry.is_dirty() ? "dirty" : "mounted")
[email protected]a321b9632012-06-14 03:29:17605 << " file: res_id=" << resource_id
606 << ", md5=" << md5;
[email protected]78a158b2013-04-23 06:57:49607 return FILE_ERROR_IN_USE;
[email protected]a321b9632012-06-14 03:29:17608 }
609
[email protected]c80ca12f2012-11-09 10:56:03610 if (cache_entry.is_pinned())
[email protected]a321b9632012-06-14 03:29:17611 sub_dir_type = CACHE_TYPE_PERSISTENT;
[email protected]a321b9632012-06-14 03:29:17612 }
613
[email protected]650b2d52013-02-10 03:41:45614 base::FilePath dest_path = GetCacheFilePath(resource_id, md5, sub_dir_type,
[email protected]c80ca12f2012-11-09 10:56:03615 CACHED_FILE_FROM_SERVER);
616 bool success = false;
617 switch (file_operation_type) {
618 case FILE_OPERATION_MOVE:
619 success = MoveFile(source_path, dest_path);
620 break;
621 case FILE_OPERATION_COPY:
622 success = CopyFile(source_path, dest_path);
623 break;
624 default:
625 NOTREACHED();
[email protected]a321b9632012-06-14 03:29:17626 }
627
[email protected]f60c670b2012-09-13 06:19:25628 // Determine search pattern for stale filenames corresponding to resource_id,
[email protected]a321b9632012-06-14 03:29:17629 // either "<resource_id>*" or "<resource_id>.*".
[email protected]650b2d52013-02-10 03:41:45630 base::FilePath stale_filenames_pattern;
[email protected]a321b9632012-06-14 03:29:17631 if (md5.empty()) {
632 // No md5 means no extension, append '*' after base name, i.e.
633 // "<resource_id>*".
634 // Cannot call |dest_path|.ReplaceExtension when there's no md5 extension:
635 // if base name of |dest_path| (i.e. escaped resource_id) contains the
636 // extension separator '.', ReplaceExtension will remove it and everything
637 // after it. The result will be nothing like the escaped resource_id.
[email protected]650b2d52013-02-10 03:41:45638 stale_filenames_pattern =
639 base::FilePath(dest_path.value() + util::kWildCard);
[email protected]a321b9632012-06-14 03:29:17640 } else {
641 // Replace md5 extension with '*' i.e. "<resource_id>.*".
642 // Note that ReplaceExtension automatically prefixes the extension with the
643 // extension separator '.'.
[email protected]ca5f6da2012-06-18 12:54:59644 stale_filenames_pattern = dest_path.ReplaceExtension(util::kWildCard);
[email protected]a321b9632012-06-14 03:29:17645 }
646
647 // Delete files that match |stale_filenames_pattern| except for |dest_path|.
648 DeleteFilesSelectively(stale_filenames_pattern, dest_path);
649
[email protected]c80ca12f2012-11-09 10:56:03650 if (success) {
651 // Now that file operations have completed, update metadata.
[email protected]b22f87f2012-07-12 10:53:17652 cache_entry.set_md5(md5);
[email protected]02821102012-07-12 20:19:17653 cache_entry.set_is_present(true);
654 cache_entry.set_is_persistent(sub_dir_type == CACHE_TYPE_PERSISTENT);
[email protected]b22f87f2012-07-12 10:53:17655 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry);
[email protected]a321b9632012-06-14 03:29:17656 }
[email protected]bdd947c2012-11-06 04:35:34657
[email protected]78a158b2013-04-23 06:57:49658 return success ? FILE_ERROR_OK : FILE_ERROR_FAILED;
[email protected]a321b9632012-06-14 03:29:17659}
660
[email protected]78a158b2013-04-23 06:57:49661FileError DriveCache::PinOnBlockingPool(const std::string& resource_id,
662 const std::string& md5) {
[email protected]a321b9632012-06-14 03:29:17663 AssertOnSequencedWorkerPool();
[email protected]a321b9632012-06-14 03:29:17664
[email protected]ae248f02013-03-06 12:55:41665 bool is_persistent = true;
[email protected]28a64092012-08-21 10:01:12666 DriveCacheEntry cache_entry;
[email protected]77fb1a62012-11-01 13:42:32667 if (!GetCacheEntryOnBlockingPool(resource_id, md5, &cache_entry)) {
[email protected]ae248f02013-03-06 12:55:41668 // The file will be first downloaded in 'tmp', then moved to 'persistent'.
669 is_persistent = false;
[email protected]109eb5c2012-07-12 03:20:05670 } else { // File exists in cache, determines destination path.
[email protected]a321b9632012-06-14 03:29:17671 // Determine source and destination paths.
672
[email protected]c80ca12f2012-11-09 10:56:03673 // If file is dirty or mounted, don't move it.
[email protected]ae248f02013-03-06 12:55:41674 if (!cache_entry.is_dirty() && !cache_entry.is_mounted()) {
[email protected]a321b9632012-06-14 03:29:17675 // If file was pinned before but actual file blob doesn't exist in cache:
[email protected]c80ca12f2012-11-09 10:56:03676 // - don't need to move the file.
[email protected]02821102012-07-12 20:19:17677 if (!cache_entry.is_present()) {
[email protected]c80ca12f2012-11-09 10:56:03678 DCHECK(cache_entry.is_pinned());
[email protected]78a158b2013-04-23 06:57:49679 return FILE_ERROR_OK;
[email protected]a321b9632012-06-14 03:29:17680 }
[email protected]c80ca12f2012-11-09 10:56:03681 // File exists, move it to persistent dir.
682 // Gets the current path of the file in cache.
[email protected]650b2d52013-02-10 03:41:45683 base::FilePath source_path = GetCacheFilePath(resource_id,
[email protected]c80ca12f2012-11-09 10:56:03684 md5,
685 GetSubDirectoryType(cache_entry),
686 CACHED_FILE_FROM_SERVER);
[email protected]ae248f02013-03-06 12:55:41687 base::FilePath dest_path = GetCacheFilePath(resource_id,
688 md5,
689 CACHE_TYPE_PERSISTENT,
690 CACHED_FILE_FROM_SERVER);
[email protected]c80ca12f2012-11-09 10:56:03691 if (!MoveFile(source_path, dest_path))
[email protected]78a158b2013-04-23 06:57:49692 return FILE_ERROR_FAILED;
[email protected]a321b9632012-06-14 03:29:17693 }
694 }
695
[email protected]c80ca12f2012-11-09 10:56:03696 // Now that file operations have completed, update metadata.
697 cache_entry.set_md5(md5);
698 cache_entry.set_is_pinned(true);
[email protected]ae248f02013-03-06 12:55:41699 cache_entry.set_is_persistent(is_persistent);
[email protected]c80ca12f2012-11-09 10:56:03700 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry);
[email protected]78a158b2013-04-23 06:57:49701 return FILE_ERROR_OK;
[email protected]a321b9632012-06-14 03:29:17702}
703
[email protected]78a158b2013-04-23 06:57:49704FileError DriveCache::UnpinOnBlockingPool(const std::string& resource_id,
705 const std::string& md5) {
[email protected]a321b9632012-06-14 03:29:17706 AssertOnSequencedWorkerPool();
[email protected]a321b9632012-06-14 03:29:17707
[email protected]a321b9632012-06-14 03:29:17708 // Unpinning a file means its entry must exist in cache.
[email protected]28a64092012-08-21 10:01:12709 DriveCacheEntry cache_entry;
[email protected]77fb1a62012-11-01 13:42:32710 if (!GetCacheEntryOnBlockingPool(resource_id, md5, &cache_entry)) {
[email protected]a321b9632012-06-14 03:29:17711 LOG(WARNING) << "Can't unpin a file that wasn't pinned or cached: res_id="
712 << resource_id
713 << ", md5=" << md5;
[email protected]78a158b2013-04-23 06:57:49714 return FILE_ERROR_NOT_FOUND;
[email protected]a321b9632012-06-14 03:29:17715 }
716
[email protected]a321b9632012-06-14 03:29:17717 CacheSubDirectoryType sub_dir_type = CACHE_TYPE_TMP;
718
[email protected]c80ca12f2012-11-09 10:56:03719 // If file is dirty or mounted, don't move it.
[email protected]02821102012-07-12 20:19:17720 if (cache_entry.is_dirty() || cache_entry.is_mounted()) {
[email protected]a321b9632012-06-14 03:29:17721 sub_dir_type = CACHE_TYPE_PERSISTENT;
[email protected]02821102012-07-12 20:19:17722 DCHECK(cache_entry.is_persistent());
[email protected]a321b9632012-06-14 03:29:17723 } else {
[email protected]a321b9632012-06-14 03:29:17724 // If file was pinned but actual file blob still doesn't exist in cache,
[email protected]c80ca12f2012-11-09 10:56:03725 // don't need to move the file.
[email protected]02821102012-07-12 20:19:17726 if (cache_entry.is_present()) {
[email protected]c80ca12f2012-11-09 10:56:03727 // Gets the current path of the file in cache.
[email protected]650b2d52013-02-10 03:41:45728 base::FilePath source_path = GetCacheFilePath(resource_id,
[email protected]c80ca12f2012-11-09 10:56:03729 md5,
730 GetSubDirectoryType(cache_entry),
731 CACHED_FILE_FROM_SERVER);
732 // File exists, move it to tmp dir.
[email protected]650b2d52013-02-10 03:41:45733 base::FilePath dest_path = GetCacheFilePath(resource_id,
[email protected]c80ca12f2012-11-09 10:56:03734 md5,
735 CACHE_TYPE_TMP,
736 CACHED_FILE_FROM_SERVER);
737 if (!MoveFile(source_path, dest_path))
[email protected]78a158b2013-04-23 06:57:49738 return FILE_ERROR_FAILED;
[email protected]3423871a2012-07-12 00:41:27739 }
[email protected]a321b9632012-06-14 03:29:17740 }
[email protected]bdd947c2012-11-06 04:35:34741
[email protected]c80ca12f2012-11-09 10:56:03742 // Now that file operations have completed, update metadata.
743 if (cache_entry.is_present()) {
744 cache_entry.set_md5(md5);
745 cache_entry.set_is_pinned(false);
746 cache_entry.set_is_persistent(sub_dir_type == CACHE_TYPE_PERSISTENT);
747 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry);
748 } else {
749 // Remove the existing entry if we are unpinning a non-present file.
750 metadata_->RemoveCacheEntry(resource_id);
751 }
[email protected]78a158b2013-04-23 06:57:49752 return FILE_ERROR_OK;
[email protected]a321b9632012-06-14 03:29:17753}
754
[email protected]9564c1502012-11-28 12:12:16755scoped_ptr<DriveCache::GetFileResult> DriveCache::MarkAsMountedOnBlockingPool(
[email protected]35c1f9b2013-02-07 07:39:42756 const std::string& resource_id,
757 const std::string& md5) {
[email protected]a321b9632012-06-14 03:29:17758 AssertOnSequencedWorkerPool();
[email protected]bdd947c2012-11-06 04:35:34759
760 scoped_ptr<GetFileResult> result(new GetFileResult);
[email protected]a321b9632012-06-14 03:29:17761
[email protected]a321b9632012-06-14 03:29:17762 // Get cache entry associated with the resource_id and md5
[email protected]28a64092012-08-21 10:01:12763 DriveCacheEntry cache_entry;
[email protected]77fb1a62012-11-01 13:42:32764 if (!GetCacheEntryOnBlockingPool(resource_id, md5, &cache_entry)) {
[email protected]78a158b2013-04-23 06:57:49765 result->first = FILE_ERROR_NOT_FOUND;
[email protected]bdd947c2012-11-06 04:35:34766 return result.Pass();
[email protected]a321b9632012-06-14 03:29:17767 }
[email protected]bdd947c2012-11-06 04:35:34768
[email protected]9564c1502012-11-28 12:12:16769 if (cache_entry.is_mounted()) {
[email protected]78a158b2013-04-23 06:57:49770 result->first = FILE_ERROR_INVALID_OPERATION;
[email protected]bdd947c2012-11-06 04:35:34771 return result.Pass();
[email protected]a321b9632012-06-14 03:29:17772 }
773
774 // Get the subdir type and path for the unmounted state.
775 CacheSubDirectoryType unmounted_subdir =
[email protected]02821102012-07-12 20:19:17776 cache_entry.is_pinned() ? CACHE_TYPE_PERSISTENT : CACHE_TYPE_TMP;
[email protected]650b2d52013-02-10 03:41:45777 base::FilePath unmounted_path = GetCacheFilePath(
[email protected]a321b9632012-06-14 03:29:17778 resource_id, md5, unmounted_subdir, CACHED_FILE_FROM_SERVER);
779
780 // Get the subdir type and path for the mounted state.
781 CacheSubDirectoryType mounted_subdir = CACHE_TYPE_PERSISTENT;
[email protected]650b2d52013-02-10 03:41:45782 base::FilePath mounted_path = GetCacheFilePath(
[email protected]a321b9632012-06-14 03:29:17783 resource_id, md5, mounted_subdir, CACHED_FILE_MOUNTED);
784
[email protected]9564c1502012-11-28 12:12:16785 // Move cache file.
786 bool success = MoveFile(unmounted_path, mounted_path);
[email protected]c80ca12f2012-11-09 10:56:03787
788 if (success) {
789 // Now that cache operation is complete, update metadata.
[email protected]48477fe2012-07-12 17:45:08790 cache_entry.set_md5(md5);
[email protected]9564c1502012-11-28 12:12:16791 cache_entry.set_is_mounted(true);
792 cache_entry.set_is_persistent(true);
[email protected]48477fe2012-07-12 17:45:08793 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry);
[email protected]a321b9632012-06-14 03:29:17794 }
[email protected]78a158b2013-04-23 06:57:49795 result->first = success ? FILE_ERROR_OK : FILE_ERROR_FAILED;
[email protected]9564c1502012-11-28 12:12:16796 result->second = mounted_path;
[email protected]bdd947c2012-11-06 04:35:34797 return result.Pass();
[email protected]a321b9632012-06-14 03:29:17798}
799
[email protected]78a158b2013-04-23 06:57:49800FileError DriveCache::MarkAsUnmountedOnBlockingPool(
[email protected]650b2d52013-02-10 03:41:45801 const base::FilePath& file_path) {
[email protected]9564c1502012-11-28 12:12:16802 AssertOnSequencedWorkerPool();
[email protected]3a680f32013-03-01 04:07:27803 DCHECK(IsUnderDriveCacheDirectory(file_path));
[email protected]9564c1502012-11-28 12:12:16804
805 // Parse file path to obtain resource_id, md5 and extra_extension.
806 std::string resource_id;
807 std::string md5;
808 std::string extra_extension;
809 util::ParseCacheFilePath(file_path, &resource_id, &md5, &extra_extension);
810 // The extra_extension shall be ".mounted" iff we're unmounting.
[email protected]3a680f32013-03-01 04:07:27811 DCHECK_EQ(util::kMountedArchiveFileExtension, extra_extension);
[email protected]9564c1502012-11-28 12:12:16812
813 // Get cache entry associated with the resource_id and md5
814 DriveCacheEntry cache_entry;
815 if (!GetCacheEntryOnBlockingPool(resource_id, md5, &cache_entry))
[email protected]78a158b2013-04-23 06:57:49816 return FILE_ERROR_NOT_FOUND;
[email protected]9564c1502012-11-28 12:12:16817
818 if (!cache_entry.is_mounted())
[email protected]78a158b2013-04-23 06:57:49819 return FILE_ERROR_INVALID_OPERATION;
[email protected]9564c1502012-11-28 12:12:16820
821 // Get the subdir type and path for the unmounted state.
822 CacheSubDirectoryType unmounted_subdir =
823 cache_entry.is_pinned() ? CACHE_TYPE_PERSISTENT : CACHE_TYPE_TMP;
[email protected]650b2d52013-02-10 03:41:45824 base::FilePath unmounted_path = GetCacheFilePath(
[email protected]9564c1502012-11-28 12:12:16825 resource_id, md5, unmounted_subdir, CACHED_FILE_FROM_SERVER);
826
827 // Get the subdir type and path for the mounted state.
828 CacheSubDirectoryType mounted_subdir = CACHE_TYPE_PERSISTENT;
[email protected]650b2d52013-02-10 03:41:45829 base::FilePath mounted_path = GetCacheFilePath(
[email protected]9564c1502012-11-28 12:12:16830 resource_id, md5, mounted_subdir, CACHED_FILE_MOUNTED);
831
832 // Move cache file.
833 if (!MoveFile(mounted_path, unmounted_path))
[email protected]78a158b2013-04-23 06:57:49834 return FILE_ERROR_FAILED;
[email protected]9564c1502012-11-28 12:12:16835
836 // Now that cache operation is complete, update metadata.
837 cache_entry.set_md5(md5);
838 cache_entry.set_is_mounted(false);
839 cache_entry.set_is_persistent(unmounted_subdir == CACHE_TYPE_PERSISTENT);
840 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry);
[email protected]78a158b2013-04-23 06:57:49841 return FILE_ERROR_OK;
[email protected]9564c1502012-11-28 12:12:16842}
843
[email protected]78a158b2013-04-23 06:57:49844FileError DriveCache::MarkDirtyOnBlockingPool(
[email protected]bdd947c2012-11-06 04:35:34845 const std::string& resource_id,
846 const std::string& md5) {
[email protected]c960d222012-06-15 10:03:50847 AssertOnSequencedWorkerPool();
[email protected]bdd947c2012-11-06 04:35:34848
[email protected]c960d222012-06-15 10:03:50849 // If file has already been marked dirty in previous instance of chrome, we
850 // would have lost the md5 info during cache initialization, because the file
851 // would have been renamed to .local extension.
852 // So, search for entry in cache without comparing md5.
[email protected]c960d222012-06-15 10:03:50853
854 // Marking a file dirty means its entry and actual file blob must exist in
855 // cache.
[email protected]28a64092012-08-21 10:01:12856 DriveCacheEntry cache_entry;
[email protected]77fb1a62012-11-01 13:42:32857 if (!GetCacheEntryOnBlockingPool(resource_id, std::string(), &cache_entry) ||
[email protected]02821102012-07-12 20:19:17858 !cache_entry.is_present()) {
[email protected]c960d222012-06-15 10:03:50859 LOG(WARNING) << "Can't mark dirty a file that wasn't cached: res_id="
860 << resource_id
861 << ", md5=" << md5;
[email protected]78a158b2013-04-23 06:57:49862 return FILE_ERROR_NOT_FOUND;
[email protected]c960d222012-06-15 10:03:50863 }
864
865 // If a file is already dirty (i.e. MarkDirtyInCache was called before),
866 // delete outgoing symlink if it exists.
867 // TODO(benchan): We should only delete outgoing symlink if file is currently
868 // not being uploaded. However, for now, cache doesn't know if uploading of a
869 // file is in progress. Per zel, the upload process should be canceled before
870 // MarkDirtyInCache is called again.
[email protected]02821102012-07-12 20:19:17871 if (cache_entry.is_dirty()) {
[email protected]c960d222012-06-15 10:03:50872 // The file must be in persistent dir.
[email protected]02821102012-07-12 20:19:17873 DCHECK(cache_entry.is_persistent());
[email protected]c960d222012-06-15 10:03:50874
875 // Determine symlink path in outgoing dir, so as to remove it.
[email protected]650b2d52013-02-10 03:41:45876 base::FilePath symlink_path = GetCacheFilePath(resource_id,
[email protected]c80ca12f2012-11-09 10:56:03877 std::string(),
878 CACHE_TYPE_OUTGOING,
879 CACHED_FILE_FROM_SERVER);
880 DeleteSymlink(symlink_path);
[email protected]c960d222012-06-15 10:03:50881
[email protected]78a158b2013-04-23 06:57:49882 return FILE_ERROR_OK;
[email protected]c960d222012-06-15 10:03:50883 }
884
885 // Move file to persistent dir with new .local extension.
886
887 // Get the current path of the file in cache.
[email protected]650b2d52013-02-10 03:41:45888 base::FilePath source_path = GetCacheFilePath(resource_id,
[email protected]c80ca12f2012-11-09 10:56:03889 md5,
890 GetSubDirectoryType(cache_entry),
891 CACHED_FILE_FROM_SERVER);
[email protected]c960d222012-06-15 10:03:50892 // Determine destination path.
[email protected]3dc88ee2012-07-11 21:04:11893 const CacheSubDirectoryType sub_dir_type = CACHE_TYPE_PERSISTENT;
[email protected]650b2d52013-02-10 03:41:45894 base::FilePath cache_file_path = GetCacheFilePath(resource_id,
[email protected]bdd947c2012-11-06 04:35:34895 md5,
896 sub_dir_type,
897 CACHED_FILE_LOCALLY_MODIFIED);
[email protected]c960d222012-06-15 10:03:50898
[email protected]ae248f02013-03-06 12:55:41899 if (!MoveFile(source_path, cache_file_path))
[email protected]78a158b2013-04-23 06:57:49900 return FILE_ERROR_FAILED;
[email protected]c80ca12f2012-11-09 10:56:03901
[email protected]ae248f02013-03-06 12:55:41902 // Now that file operations have completed, update metadata.
903 cache_entry.set_md5(md5);
904 cache_entry.set_is_dirty(true);
905 cache_entry.set_is_persistent(sub_dir_type == CACHE_TYPE_PERSISTENT);
906 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry);
[email protected]78a158b2013-04-23 06:57:49907 return FILE_ERROR_OK;
[email protected]c960d222012-06-15 10:03:50908}
909
[email protected]78a158b2013-04-23 06:57:49910FileError DriveCache::CommitDirtyOnBlockingPool(
[email protected]77fb1a62012-11-01 13:42:32911 const std::string& resource_id,
[email protected]3f5e2902012-11-06 08:21:15912 const std::string& md5) {
[email protected]a321b9632012-06-14 03:29:17913 AssertOnSequencedWorkerPool();
[email protected]a321b9632012-06-14 03:29:17914
915 // If file has already been marked dirty in previous instance of chrome, we
916 // would have lost the md5 info during cache initialization, because the file
917 // would have been renamed to .local extension.
918 // So, search for entry in cache without comparing md5.
[email protected]a321b9632012-06-14 03:29:17919
920 // Committing a file dirty means its entry and actual file blob must exist in
921 // cache.
[email protected]28a64092012-08-21 10:01:12922 DriveCacheEntry cache_entry;
[email protected]77fb1a62012-11-01 13:42:32923 if (!GetCacheEntryOnBlockingPool(resource_id, std::string(), &cache_entry) ||
[email protected]02821102012-07-12 20:19:17924 !cache_entry.is_present()) {
[email protected]a321b9632012-06-14 03:29:17925 LOG(WARNING) << "Can't commit dirty a file that wasn't cached: res_id="
926 << resource_id
927 << ", md5=" << md5;
[email protected]78a158b2013-04-23 06:57:49928 return FILE_ERROR_NOT_FOUND;
[email protected]a321b9632012-06-14 03:29:17929 }
930
931 // If a file is not dirty (it should have been marked dirty via
932 // MarkDirtyInCache), committing it dirty is an invalid operation.
[email protected]02821102012-07-12 20:19:17933 if (!cache_entry.is_dirty()) {
[email protected]a321b9632012-06-14 03:29:17934 LOG(WARNING) << "Can't commit a non-dirty file: res_id="
935 << resource_id
936 << ", md5=" << md5;
[email protected]78a158b2013-04-23 06:57:49937 return FILE_ERROR_INVALID_OPERATION;
[email protected]a321b9632012-06-14 03:29:17938 }
939
940 // Dirty files must be in persistent dir.
[email protected]02821102012-07-12 20:19:17941 DCHECK(cache_entry.is_persistent());
[email protected]a321b9632012-06-14 03:29:17942
943 // Create symlink in outgoing dir.
[email protected]650b2d52013-02-10 03:41:45944 base::FilePath symlink_path = GetCacheFilePath(resource_id,
[email protected]a321b9632012-06-14 03:29:17945 std::string(),
946 CACHE_TYPE_OUTGOING,
947 CACHED_FILE_FROM_SERVER);
948
949 // Get target path of symlink i.e. current path of the file in cache.
[email protected]650b2d52013-02-10 03:41:45950 base::FilePath target_path = GetCacheFilePath(resource_id,
[email protected]a321b9632012-06-14 03:29:17951 md5,
[email protected]b22f87f2012-07-12 10:53:17952 GetSubDirectoryType(cache_entry),
[email protected]a321b9632012-06-14 03:29:17953 CACHED_FILE_LOCALLY_MODIFIED);
954
[email protected]c80ca12f2012-11-09 10:56:03955 return CreateSymlink(target_path, symlink_path) ?
[email protected]78a158b2013-04-23 06:57:49956 FILE_ERROR_OK : FILE_ERROR_FAILED;
[email protected]a321b9632012-06-14 03:29:17957}
958
[email protected]78a158b2013-04-23 06:57:49959FileError DriveCache::ClearDirtyOnBlockingPool(
[email protected]bdd947c2012-11-06 04:35:34960 const std::string& resource_id,
[email protected]3f5e2902012-11-06 08:21:15961 const std::string& md5) {
[email protected]a321b9632012-06-14 03:29:17962 AssertOnSequencedWorkerPool();
[email protected]a321b9632012-06-14 03:29:17963
964 // |md5| is the new .<md5> extension to rename the file to.
965 // So, search for entry in cache without comparing md5.
[email protected]28a64092012-08-21 10:01:12966 DriveCacheEntry cache_entry;
[email protected]a321b9632012-06-14 03:29:17967
968 // Clearing a dirty file means its entry and actual file blob must exist in
969 // cache.
[email protected]77fb1a62012-11-01 13:42:32970 if (!GetCacheEntryOnBlockingPool(resource_id, std::string(), &cache_entry) ||
[email protected]02821102012-07-12 20:19:17971 !cache_entry.is_present()) {
[email protected]a321b9632012-06-14 03:29:17972 LOG(WARNING) << "Can't clear dirty state of a file that wasn't cached: "
973 << "res_id=" << resource_id
974 << ", md5=" << md5;
[email protected]78a158b2013-04-23 06:57:49975 return FILE_ERROR_NOT_FOUND;
[email protected]a321b9632012-06-14 03:29:17976 }
977
978 // If a file is not dirty (it should have been marked dirty via
979 // MarkDirtyInCache), clearing its dirty state is an invalid operation.
[email protected]02821102012-07-12 20:19:17980 if (!cache_entry.is_dirty()) {
[email protected]a321b9632012-06-14 03:29:17981 LOG(WARNING) << "Can't clear dirty state of a non-dirty file: res_id="
982 << resource_id
983 << ", md5=" << md5;
[email protected]78a158b2013-04-23 06:57:49984 return FILE_ERROR_INVALID_OPERATION;
[email protected]a321b9632012-06-14 03:29:17985 }
986
987 // File must be dirty and hence in persistent dir.
[email protected]02821102012-07-12 20:19:17988 DCHECK(cache_entry.is_persistent());
[email protected]a321b9632012-06-14 03:29:17989
990 // Get the current path of the file in cache.
[email protected]ae248f02013-03-06 12:55:41991 base::FilePath source_path =
992 GetCacheFilePath(resource_id,
993 md5,
994 GetSubDirectoryType(cache_entry),
995 CACHED_FILE_LOCALLY_MODIFIED);
[email protected]a321b9632012-06-14 03:29:17996
997 // Determine destination path.
998 // If file is pinned, move it to persistent dir with .md5 extension;
999 // otherwise, move it to tmp dir with .md5 extension.
[email protected]3dc88ee2012-07-11 21:04:111000 const CacheSubDirectoryType sub_dir_type =
[email protected]02821102012-07-12 20:19:171001 cache_entry.is_pinned() ? CACHE_TYPE_PERSISTENT : CACHE_TYPE_TMP;
[email protected]650b2d52013-02-10 03:41:451002 base::FilePath dest_path = GetCacheFilePath(resource_id,
[email protected]ae248f02013-03-06 12:55:411003 md5,
1004 sub_dir_type,
1005 CACHED_FILE_FROM_SERVER);
[email protected]a321b9632012-06-14 03:29:171006
[email protected]ae248f02013-03-06 12:55:411007 if (!MoveFile(source_path, dest_path))
[email protected]78a158b2013-04-23 06:57:491008 return FILE_ERROR_FAILED;
[email protected]a321b9632012-06-14 03:29:171009
[email protected]ae248f02013-03-06 12:55:411010 // Delete symlink in outgoing dir.
1011 base::FilePath symlink_path = GetCacheFilePath(resource_id,
1012 std::string(),
1013 CACHE_TYPE_OUTGOING,
1014 CACHED_FILE_FROM_SERVER);
1015 DeleteSymlink(symlink_path);
[email protected]a321b9632012-06-14 03:29:171016
[email protected]ae248f02013-03-06 12:55:411017 // Now that file operations have completed, update metadata.
1018 cache_entry.set_md5(md5);
1019 cache_entry.set_is_dirty(false);
1020 cache_entry.set_is_persistent(sub_dir_type == CACHE_TYPE_PERSISTENT);
1021 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry);
[email protected]78a158b2013-04-23 06:57:491022 return FILE_ERROR_OK;
[email protected]a321b9632012-06-14 03:29:171023}
1024
[email protected]78a158b2013-04-23 06:57:491025FileError DriveCache::RemoveOnBlockingPool(
[email protected]bdd947c2012-11-06 04:35:341026 const std::string& resource_id) {
[email protected]a321b9632012-06-14 03:29:171027 AssertOnSequencedWorkerPool();
[email protected]a321b9632012-06-14 03:29:171028
[email protected]3423871a2012-07-12 00:41:271029 // MD5 is not passed into RemoveCacheEntry because we would delete all
1030 // cache files corresponding to <resource_id> regardless of the md5.
[email protected]a321b9632012-06-14 03:29:171031 // So, search for entry in cache without taking md5 into account.
[email protected]28a64092012-08-21 10:01:121032 DriveCacheEntry cache_entry;
[email protected]a321b9632012-06-14 03:29:171033
1034 // If entry doesn't exist or is dirty or mounted in cache, nothing to do.
[email protected]b22f87f2012-07-12 10:53:171035 const bool entry_found =
[email protected]77fb1a62012-11-01 13:42:321036 GetCacheEntryOnBlockingPool(resource_id, std::string(), &cache_entry);
[email protected]02821102012-07-12 20:19:171037 if (!entry_found || cache_entry.is_dirty() || cache_entry.is_mounted()) {
[email protected]a321b9632012-06-14 03:29:171038 DVLOG(1) << "Entry is "
[email protected]b22f87f2012-07-12 10:53:171039 << (entry_found ?
[email protected]02821102012-07-12 20:19:171040 (cache_entry.is_dirty() ? "dirty" : "mounted") :
[email protected]a321b9632012-06-14 03:29:171041 "non-existent")
1042 << " in cache, not removing";
[email protected]78a158b2013-04-23 06:57:491043 return FILE_ERROR_OK;
[email protected]a321b9632012-06-14 03:29:171044 }
1045
1046 // Determine paths to delete all cache versions of |resource_id| in
1047 // persistent, tmp and pinned directories.
[email protected]650b2d52013-02-10 03:41:451048 std::vector<base::FilePath> paths_to_delete;
[email protected]a321b9632012-06-14 03:29:171049
1050 // For files in persistent and tmp dirs, delete files that match
1051 // "<resource_id>.*".
1052 paths_to_delete.push_back(GetCacheFilePath(resource_id,
[email protected]ca5f6da2012-06-18 12:54:591053 util::kWildCard,
[email protected]a321b9632012-06-14 03:29:171054 CACHE_TYPE_PERSISTENT,
1055 CACHED_FILE_FROM_SERVER));
1056 paths_to_delete.push_back(GetCacheFilePath(resource_id,
[email protected]ca5f6da2012-06-18 12:54:591057 util::kWildCard,
[email protected]a321b9632012-06-14 03:29:171058 CACHE_TYPE_TMP,
1059 CACHED_FILE_FROM_SERVER));
1060
[email protected]a321b9632012-06-14 03:29:171061 // Don't delete locally modified (i.e. dirty and possibly outgoing) files.
1062 // Since we're not deleting outgoing symlinks, we don't need to append
1063 // outgoing path to |paths_to_delete|.
[email protected]650b2d52013-02-10 03:41:451064 base::FilePath path_to_keep = GetCacheFilePath(resource_id,
[email protected]a321b9632012-06-14 03:29:171065 std::string(),
1066 CACHE_TYPE_PERSISTENT,
1067 CACHED_FILE_LOCALLY_MODIFIED);
1068
1069 for (size_t i = 0; i < paths_to_delete.size(); ++i) {
1070 DeleteFilesSelectively(paths_to_delete[i], path_to_keep);
1071 }
1072
[email protected]c80ca12f2012-11-09 10:56:031073 // Now that all file operations have completed, remove from metadata.
[email protected]3423871a2012-07-12 00:41:271074 metadata_->RemoveCacheEntry(resource_id);
[email protected]a321b9632012-06-14 03:29:171075
[email protected]78a158b2013-04-23 06:57:491076 return FILE_ERROR_OK;
[email protected]a321b9632012-06-14 03:29:171077}
1078
[email protected]bdd947c2012-11-06 04:35:341079bool DriveCache::ClearAllOnBlockingPool() {
[email protected]f861b392012-08-03 20:41:121080 AssertOnSequencedWorkerPool();
[email protected]f861b392012-08-03 20:41:121081
[email protected]bdd947c2012-11-06 04:35:341082 if (!file_util::Delete(cache_root_path_, true)) {
[email protected]322e0032012-10-07 01:55:531083 LOG(WARNING) << "Failed to delete the cache directory";
[email protected]bdd947c2012-11-06 04:35:341084 return false;
[email protected]322e0032012-10-07 01:55:531085 }
[email protected]f861b392012-08-03 20:41:121086
[email protected]bdd947c2012-11-06 04:35:341087 if (!InitializeOnBlockingPool()) {
[email protected]322e0032012-10-07 01:55:531088 LOG(WARNING) << "Failed to initialize the cache";
[email protected]bdd947c2012-11-06 04:35:341089 return false;
[email protected]322e0032012-10-07 01:55:531090 }
[email protected]bdd947c2012-11-06 04:35:341091 return true;
[email protected]f861b392012-08-03 20:41:121092}
1093
[email protected]bdd947c2012-11-06 04:35:341094void DriveCache::OnPinned(const std::string& resource_id,
[email protected]73f9c742012-06-15 07:37:131095 const std::string& md5,
[email protected]2a2c4152012-11-26 11:34:501096 const FileOperationCallback& callback,
[email protected]78a158b2013-04-23 06:57:491097 FileError error) {
[email protected]73f9c742012-06-15 07:37:131098 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]2a2c4152012-11-26 11:34:501099 DCHECK(!callback.is_null());
[email protected]73f9c742012-06-15 07:37:131100
[email protected]2a2c4152012-11-26 11:34:501101 callback.Run(error);
[email protected]73f9c742012-06-15 07:37:131102
[email protected]78a158b2013-04-23 06:57:491103 if (error == FILE_ERROR_OK)
[email protected]a09275502012-10-10 04:48:011104 FOR_EACH_OBSERVER(DriveCacheObserver,
1105 observers_,
1106 OnCachePinned(resource_id, md5));
[email protected]3653146a2012-05-29 13:41:471107}
1108
[email protected]bdd947c2012-11-06 04:35:341109void DriveCache::OnUnpinned(const std::string& resource_id,
[email protected]73f9c742012-06-15 07:37:131110 const std::string& md5,
[email protected]2a2c4152012-11-26 11:34:501111 const FileOperationCallback& callback,
[email protected]78a158b2013-04-23 06:57:491112 FileError error) {
[email protected]73f9c742012-06-15 07:37:131113 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]2a2c4152012-11-26 11:34:501114 DCHECK(!callback.is_null());
[email protected]a321b9632012-06-14 03:29:171115
[email protected]2a2c4152012-11-26 11:34:501116 callback.Run(error);
[email protected]a321b9632012-06-14 03:29:171117
[email protected]78a158b2013-04-23 06:57:491118 if (error == FILE_ERROR_OK)
[email protected]a09275502012-10-10 04:48:011119 FOR_EACH_OBSERVER(DriveCacheObserver,
1120 observers_,
1121 OnCacheUnpinned(resource_id, md5));
[email protected]a321b9632012-06-14 03:29:171122
[email protected]73f9c742012-06-15 07:37:131123 // Now the file is moved from "persistent" to "tmp" directory.
1124 // It's a chance to free up space if needed.
[email protected]ddbf2052012-07-13 15:07:021125 blocking_task_runner_->PostTask(
[email protected]73f9c742012-06-15 07:37:131126 FROM_HERE,
[email protected]77fb1a62012-11-01 13:42:321127 base::Bind(
1128 base::IgnoreResult(
1129 &DriveCache::FreeDiskSpaceOnBlockingPoolIfNeededFor),
1130 base::Unretained(this), 0));
[email protected]3653146a2012-05-29 13:41:471131}
1132
[email protected]bdd947c2012-11-06 04:35:341133void DriveCache::OnCommitDirty(const std::string& resource_id,
[email protected]2a2c4152012-11-26 11:34:501134 const FileOperationCallback& callback,
[email protected]78a158b2013-04-23 06:57:491135 FileError error) {
[email protected]d7664c22012-06-18 19:35:491136 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]2a2c4152012-11-26 11:34:501137 DCHECK(!callback.is_null());
[email protected]d7664c22012-06-18 19:35:491138
[email protected]2a2c4152012-11-26 11:34:501139 callback.Run(error);
[email protected]d7664c22012-06-18 19:35:491140
[email protected]78a158b2013-04-23 06:57:491141 if (error == FILE_ERROR_OK)
[email protected]a09275502012-10-10 04:48:011142 FOR_EACH_OBSERVER(DriveCacheObserver,
1143 observers_,
1144 OnCacheCommitted(resource_id));
[email protected]d7664c22012-06-18 19:35:491145}
1146
[email protected]650b2d52013-02-10 03:41:451147bool DriveCache::HasEnoughSpaceFor(int64 num_bytes,
1148 const base::FilePath& path) {
[email protected]f6fd98a2012-12-14 00:04:021149 int64 free_space = 0;
1150 if (free_disk_space_getter_)
1151 free_space = free_disk_space_getter_->AmountOfFreeDiskSpace();
1152 else
1153 free_space = base::SysInfo::AmountOfFreeDiskSpace(path);
1154
1155 // Subtract this as if this portion does not exist.
1156 free_space -= kMinFreeSpace;
1157 return (free_space >= num_bytes);
1158}
1159
[email protected]01ba15f72012-06-09 00:41:051160// static
[email protected]650b2d52013-02-10 03:41:451161base::FilePath DriveCache::GetCacheRootPath(Profile* profile) {
1162 base::FilePath cache_base_path;
[email protected]01ba15f72012-06-09 00:41:051163 chrome::GetUserCacheDirectory(profile->GetPath(), &cache_base_path);
[email protected]650b2d52013-02-10 03:41:451164 base::FilePath cache_root_path =
[email protected]fb371812012-08-22 16:05:231165 cache_base_path.Append(chrome::kDriveCacheDirname);
1166 return cache_root_path.Append(kDriveCacheVersionDir);
[email protected]01ba15f72012-06-09 00:41:051167}
1168
[email protected]30d9dda2012-06-30 05:56:281169// static
[email protected]650b2d52013-02-10 03:41:451170std::vector<base::FilePath> DriveCache::GetCachePaths(
1171 const base::FilePath& cache_root_path) {
1172 std::vector<base::FilePath> cache_paths;
[email protected]fb371812012-08-22 16:05:231173 // The order should match DriveCache::CacheSubDirectoryType enum.
1174 cache_paths.push_back(cache_root_path.Append(kDriveCacheMetaDir));
[email protected]fb371812012-08-22 16:05:231175 cache_paths.push_back(cache_root_path.Append(kDriveCacheOutgoingDir));
1176 cache_paths.push_back(cache_root_path.Append(kDriveCachePersistentDir));
1177 cache_paths.push_back(cache_root_path.Append(kDriveCacheTmpDir));
1178 cache_paths.push_back(cache_root_path.Append(kDriveCacheTmpDownloadsDir));
1179 cache_paths.push_back(cache_root_path.Append(kDriveCacheTmpDocumentsDir));
[email protected]30d9dda2012-06-30 05:56:281180 return cache_paths;
1181}
1182
1183// static
[email protected]fb371812012-08-22 16:05:231184bool DriveCache::CreateCacheDirectories(
[email protected]650b2d52013-02-10 03:41:451185 const std::vector<base::FilePath>& paths_to_create) {
[email protected]30d9dda2012-06-30 05:56:281186 bool success = true;
1187
1188 for (size_t i = 0; i < paths_to_create.size(); ++i) {
1189 if (file_util::DirectoryExists(paths_to_create[i]))
1190 continue;
1191
1192 if (!file_util::CreateDirectory(paths_to_create[i])) {
1193 // Error creating this directory, record error and proceed with next one.
1194 success = false;
1195 PLOG(ERROR) << "Error creating directory " << paths_to_create[i].value();
1196 } else {
1197 DVLOG(1) << "Created directory " << paths_to_create[i].value();
1198 }
1199 }
1200 return success;
1201}
1202
[email protected]fae353a2012-07-11 23:30:271203// static
[email protected]fb371812012-08-22 16:05:231204DriveCache::CacheSubDirectoryType DriveCache::GetSubDirectoryType(
[email protected]28a64092012-08-21 10:01:121205 const DriveCacheEntry& cache_entry) {
[email protected]02821102012-07-12 20:19:171206 return cache_entry.is_persistent() ? CACHE_TYPE_PERSISTENT : CACHE_TYPE_TMP;
[email protected]fae353a2012-07-11 23:30:271207}
1208
[email protected]d9d04df2012-10-12 07:06:351209} // namespace drive