blob: c0aff6f8cd23e8425344cc5a3c4e6f8df1ffa202 [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"
[email protected]3653146a2012-05-29 13:41:4711#include "base/string_util.h"
[email protected]c2b557732013-04-24 01:46:3412#include "base/stringprintf.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]c2b557732013-04-24 01:46:3415#include "chrome/browser/chromeos/drive/cache_metadata.h"
[email protected]bd547ad82013-04-26 04:52:2916#include "chrome/browser/chromeos/drive/cache_observer.h"
[email protected]15de8142012-10-11 06:00:5417#include "chrome/browser/chromeos/drive/drive.pb.h"
[email protected]4fa2fd5d2013-04-26 03:42:5218#include "chrome/browser/chromeos/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 }
[email protected]2333b2a12013-04-26 07:22:22232 return GetCacheDirectoryPath(sub_dir_type).Append(
233 base::FilePath::FromUTF8Unsafe(base_name));
[email protected]32a7fc852012-06-08 17:25:50234}
235
[email protected]fb371812012-08-22 16:05:23236void DriveCache::AssertOnSequencedWorkerPool() {
[email protected]ddbf2052012-07-13 15:07:02237 DCHECK(!blocking_task_runner_ ||
238 blocking_task_runner_->RunsTasksOnCurrentThread());
[email protected]fcc92a52012-06-08 22:54:16239}
240
[email protected]650b2d52013-02-10 03:41:45241bool DriveCache::IsUnderDriveCacheDirectory(const base::FilePath& path) const {
[email protected]01ba15f72012-06-09 00:41:05242 return cache_root_path_ == path || cache_root_path_.IsParent(path);
243}
244
[email protected]bd547ad82013-04-26 04:52:29245void DriveCache::AddObserver(CacheObserver* observer) {
[email protected]73f9c742012-06-15 07:37:13246 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
247 observers_.AddObserver(observer);
248}
249
[email protected]bd547ad82013-04-26 04:52:29250void DriveCache::RemoveObserver(CacheObserver* observer) {
[email protected]73f9c742012-06-15 07:37:13251 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
252 observers_.RemoveObserver(observer);
253}
254
[email protected]77fb1a62012-11-01 13:42:32255void DriveCache::GetCacheEntry(const std::string& resource_id,
256 const std::string& md5,
257 const GetCacheEntryCallback& callback) {
[email protected]4324fdc2012-06-29 05:32:48258 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]bdd947c2012-11-06 04:35:34259 DCHECK(!callback.is_null());
[email protected]4324fdc2012-06-29 05:32:48260
[email protected]28a64092012-08-21 10:01:12261 DriveCacheEntry* cache_entry = new DriveCacheEntry;
[email protected]bdd947c2012-11-06 04:35:34262 base::PostTaskAndReplyWithResult(
263 blocking_task_runner_,
[email protected]4324fdc2012-06-29 05:32:48264 FROM_HERE,
[email protected]bdd947c2012-11-06 04:35:34265 base::Bind(&DriveCache::GetCacheEntryOnBlockingPool,
[email protected]3f5e2902012-11-06 08:21:15266 base::Unretained(this), resource_id, md5, cache_entry),
[email protected]4324fdc2012-06-29 05:32:48267 base::Bind(&RunGetCacheEntryCallback,
[email protected]3f5e2902012-11-06 08:21:15268 callback, base::Owned(cache_entry)));
[email protected]4324fdc2012-06-29 05:32:48269}
270
[email protected]d68ede02012-11-07 14:30:53271void DriveCache::Iterate(const CacheIterateCallback& iteration_callback,
272 const base::Closure& completion_callback) {
[email protected]8764a392012-06-20 06:43:08273 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]d68ede02012-11-07 14:30:53274 DCHECK(!iteration_callback.is_null());
275 DCHECK(!completion_callback.is_null());
[email protected]8764a392012-06-20 06:43:08276
[email protected]ddbf2052012-07-13 15:07:02277 blocking_task_runner_->PostTaskAndReply(
[email protected]8764a392012-06-20 06:43:08278 FROM_HERE,
[email protected]d68ede02012-11-07 14:30:53279 base::Bind(&DriveCache::IterateOnBlockingPool,
280 base::Unretained(this),
281 google_apis::CreateRelayCallback(iteration_callback)),
282 completion_callback);
[email protected]cd236432012-07-27 18:03:30283}
284
[email protected]f423c0b2012-11-22 09:51:10285void DriveCache::FreeDiskSpaceIfNeededFor(
286 int64 num_bytes,
287 const InitializeCacheCallback& callback) {
288 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
289 DCHECK(!callback.is_null());
[email protected]a321b9632012-06-14 03:29:17290
[email protected]f423c0b2012-11-22 09:51:10291 base::PostTaskAndReplyWithResult(
292 blocking_task_runner_,
293 FROM_HERE,
294 base::Bind(&DriveCache::FreeDiskSpaceOnBlockingPoolIfNeededFor,
295 base::Unretained(this),
296 num_bytes),
297 callback);
[email protected]a321b9632012-06-14 03:29:17298}
299
[email protected]77fb1a62012-11-01 13:42:32300void DriveCache::GetFile(const std::string& resource_id,
301 const std::string& md5,
302 const GetFileFromCacheCallback& callback) {
[email protected]c960d222012-06-15 10:03:50303 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]bdd947c2012-11-06 04:35:34304 DCHECK(!callback.is_null());
[email protected]a321b9632012-06-14 03:29:17305
[email protected]bdd947c2012-11-06 04:35:34306 base::PostTaskAndReplyWithResult(
307 blocking_task_runner_,
[email protected]c960d222012-06-15 10:03:50308 FROM_HERE,
[email protected]77fb1a62012-11-01 13:42:32309 base::Bind(&DriveCache::GetFileOnBlockingPool,
[email protected]bdd947c2012-11-06 04:35:34310 base::Unretained(this), resource_id, md5),
311 base::Bind(&RunGetFileFromCacheCallback, callback));
[email protected]a321b9632012-06-14 03:29:17312}
313
[email protected]77fb1a62012-11-01 13:42:32314void DriveCache::Store(const std::string& resource_id,
315 const std::string& md5,
[email protected]650b2d52013-02-10 03:41:45316 const base::FilePath& source_path,
[email protected]77fb1a62012-11-01 13:42:32317 FileOperationType file_operation_type,
[email protected]2a2c4152012-11-26 11:34:50318 const FileOperationCallback& callback) {
[email protected]73f9c742012-06-15 07:37:13319 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]2a2c4152012-11-26 11:34:50320 DCHECK(!callback.is_null());
[email protected]73f9c742012-06-15 07:37:13321
[email protected]bdd947c2012-11-06 04:35:34322 base::PostTaskAndReplyWithResult(
323 blocking_task_runner_,
[email protected]73f9c742012-06-15 07:37:13324 FROM_HERE,
[email protected]77fb1a62012-11-01 13:42:32325 base::Bind(&DriveCache::StoreOnBlockingPool,
[email protected]73f9c742012-06-15 07:37:13326 base::Unretained(this),
[email protected]3f5e2902012-11-06 08:21:15327 resource_id, md5, source_path, file_operation_type),
[email protected]2a2c4152012-11-26 11:34:50328 callback);
[email protected]73f9c742012-06-15 07:37:13329}
330
[email protected]77fb1a62012-11-01 13:42:32331void DriveCache::Pin(const std::string& resource_id,
332 const std::string& md5,
[email protected]2a2c4152012-11-26 11:34:50333 const FileOperationCallback& callback) {
[email protected]73f9c742012-06-15 07:37:13334 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]2a2c4152012-11-26 11:34:50335 DCHECK(!callback.is_null());
[email protected]73f9c742012-06-15 07:37:13336
[email protected]bdd947c2012-11-06 04:35:34337 base::PostTaskAndReplyWithResult(
338 blocking_task_runner_,
[email protected]73f9c742012-06-15 07:37:13339 FROM_HERE,
[email protected]77fb1a62012-11-01 13:42:32340 base::Bind(&DriveCache::PinOnBlockingPool,
[email protected]3f5e2902012-11-06 08:21:15341 base::Unretained(this), resource_id, md5),
[email protected]fb371812012-08-22 16:05:23342 base::Bind(&DriveCache::OnPinned,
[email protected]3f5e2902012-11-06 08:21:15343 weak_ptr_factory_.GetWeakPtr(), resource_id, md5, callback));
[email protected]73f9c742012-06-15 07:37:13344}
345
[email protected]77fb1a62012-11-01 13:42:32346void DriveCache::Unpin(const std::string& resource_id,
347 const std::string& md5,
[email protected]2a2c4152012-11-26 11:34:50348 const FileOperationCallback& callback) {
[email protected]73f9c742012-06-15 07:37:13349 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]2a2c4152012-11-26 11:34:50350 DCHECK(!callback.is_null());
351
[email protected]bdd947c2012-11-06 04:35:34352 base::PostTaskAndReplyWithResult(
353 blocking_task_runner_,
[email protected]73f9c742012-06-15 07:37:13354 FROM_HERE,
[email protected]77fb1a62012-11-01 13:42:32355 base::Bind(&DriveCache::UnpinOnBlockingPool,
[email protected]3f5e2902012-11-06 08:21:15356 base::Unretained(this), resource_id, md5),
[email protected]fb371812012-08-22 16:05:23357 base::Bind(&DriveCache::OnUnpinned,
[email protected]3f5e2902012-11-06 08:21:15358 weak_ptr_factory_.GetWeakPtr(), resource_id, md5, callback));
[email protected]73f9c742012-06-15 07:37:13359}
360
[email protected]35c1f9b2013-02-07 07:39:42361void DriveCache::MarkAsMounted(const std::string& resource_id,
362 const std::string& md5,
[email protected]9564c1502012-11-28 12:12:16363 const GetFileFromCacheCallback& callback) {
[email protected]73f9c742012-06-15 07:37:13364 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]9564c1502012-11-28 12:12:16365 DCHECK(!callback.is_null());
[email protected]73f9c742012-06-15 07:37:13366
[email protected]bdd947c2012-11-06 04:35:34367 base::PostTaskAndReplyWithResult(
368 blocking_task_runner_,
[email protected]73f9c742012-06-15 07:37:13369 FROM_HERE,
[email protected]9564c1502012-11-28 12:12:16370 base::Bind(&DriveCache::MarkAsMountedOnBlockingPool,
[email protected]35c1f9b2013-02-07 07:39:42371 base::Unretained(this), resource_id, md5),
[email protected]bdd947c2012-11-06 04:35:34372 base::Bind(RunGetFileFromCacheCallback, callback));
[email protected]73f9c742012-06-15 07:37:13373}
374
[email protected]650b2d52013-02-10 03:41:45375void DriveCache::MarkAsUnmounted(const base::FilePath& file_path,
[email protected]9564c1502012-11-28 12:12:16376 const FileOperationCallback& callback) {
377 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
378 DCHECK(!callback.is_null());
379
380 base::PostTaskAndReplyWithResult(
381 blocking_task_runner_,
382 FROM_HERE,
383 base::Bind(&DriveCache::MarkAsUnmountedOnBlockingPool,
384 base::Unretained(this), file_path),
385 callback);
386}
387
[email protected]77fb1a62012-11-01 13:42:32388void DriveCache::MarkDirty(const std::string& resource_id,
389 const std::string& md5,
[email protected]bc809e42012-11-28 04:46:29390 const FileOperationCallback& callback) {
[email protected]c960d222012-06-15 10:03:50391 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]bdd947c2012-11-06 04:35:34392 DCHECK(!callback.is_null());
[email protected]73f9c742012-06-15 07:37:13393
[email protected]bdd947c2012-11-06 04:35:34394 base::PostTaskAndReplyWithResult(
395 blocking_task_runner_,
[email protected]c960d222012-06-15 10:03:50396 FROM_HERE,
[email protected]77fb1a62012-11-01 13:42:32397 base::Bind(&DriveCache::MarkDirtyOnBlockingPool,
[email protected]bdd947c2012-11-06 04:35:34398 base::Unretained(this), resource_id, md5),
[email protected]bc809e42012-11-28 04:46:29399 callback);
[email protected]73f9c742012-06-15 07:37:13400}
401
[email protected]77fb1a62012-11-01 13:42:32402void DriveCache::CommitDirty(const std::string& resource_id,
403 const std::string& md5,
[email protected]2a2c4152012-11-26 11:34:50404 const FileOperationCallback& callback) {
[email protected]73f9c742012-06-15 07:37:13405 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]2a2c4152012-11-26 11:34:50406 DCHECK(!callback.is_null());
[email protected]73f9c742012-06-15 07:37:13407
[email protected]bdd947c2012-11-06 04:35:34408 base::PostTaskAndReplyWithResult(
409 blocking_task_runner_,
[email protected]73f9c742012-06-15 07:37:13410 FROM_HERE,
[email protected]77fb1a62012-11-01 13:42:32411 base::Bind(&DriveCache::CommitDirtyOnBlockingPool,
[email protected]3f5e2902012-11-06 08:21:15412 base::Unretained(this), resource_id, md5),
[email protected]fb371812012-08-22 16:05:23413 base::Bind(&DriveCache::OnCommitDirty,
[email protected]2a2c4152012-11-26 11:34:50414 weak_ptr_factory_.GetWeakPtr(), resource_id, callback));
[email protected]73f9c742012-06-15 07:37:13415}
416
[email protected]77fb1a62012-11-01 13:42:32417void DriveCache::ClearDirty(const std::string& resource_id,
418 const std::string& md5,
[email protected]2a2c4152012-11-26 11:34:50419 const FileOperationCallback& callback) {
[email protected]73f9c742012-06-15 07:37:13420 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]2a2c4152012-11-26 11:34:50421 DCHECK(!callback.is_null());
[email protected]73f9c742012-06-15 07:37:13422
[email protected]bdd947c2012-11-06 04:35:34423 base::PostTaskAndReplyWithResult(
424 blocking_task_runner_,
[email protected]73f9c742012-06-15 07:37:13425 FROM_HERE,
[email protected]77fb1a62012-11-01 13:42:32426 base::Bind(&DriveCache::ClearDirtyOnBlockingPool,
[email protected]3f5e2902012-11-06 08:21:15427 base::Unretained(this), resource_id, md5),
[email protected]2a2c4152012-11-26 11:34:50428 callback);
[email protected]73f9c742012-06-15 07:37:13429}
430
[email protected]77fb1a62012-11-01 13:42:32431void DriveCache::Remove(const std::string& resource_id,
[email protected]2a2c4152012-11-26 11:34:50432 const FileOperationCallback& callback) {
[email protected]73f9c742012-06-15 07:37:13433 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]2a2c4152012-11-26 11:34:50434 DCHECK(!callback.is_null());
[email protected]73f9c742012-06-15 07:37:13435
[email protected]bdd947c2012-11-06 04:35:34436 base::PostTaskAndReplyWithResult(
437 blocking_task_runner_,
[email protected]73f9c742012-06-15 07:37:13438 FROM_HERE,
[email protected]77fb1a62012-11-01 13:42:32439 base::Bind(&DriveCache::RemoveOnBlockingPool,
[email protected]3f5e2902012-11-06 08:21:15440 base::Unretained(this), resource_id),
[email protected]2a2c4152012-11-26 11:34:50441 callback);
[email protected]73f9c742012-06-15 07:37:13442}
443
[email protected]bdd947c2012-11-06 04:35:34444void DriveCache::ClearAll(const InitializeCacheCallback& callback) {
[email protected]f861b392012-08-03 20:41:12445 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]bdd947c2012-11-06 04:35:34446 DCHECK(!callback.is_null());
[email protected]f861b392012-08-03 20:41:12447
[email protected]bdd947c2012-11-06 04:35:34448 base::PostTaskAndReplyWithResult(
449 blocking_task_runner_,
[email protected]f861b392012-08-03 20:41:12450 FROM_HERE,
[email protected]bdd947c2012-11-06 04:35:34451 base::Bind(&DriveCache::ClearAllOnBlockingPool, base::Unretained(this)),
452 callback);
[email protected]f861b392012-08-03 20:41:12453}
454
[email protected]77fb1a62012-11-01 13:42:32455void DriveCache::RequestInitialize(const InitializeCacheCallback& callback) {
[email protected]73f9c742012-06-15 07:37:13456 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]322e0032012-10-07 01:55:53457 DCHECK(!callback.is_null());
[email protected]73f9c742012-06-15 07:37:13458
[email protected]bdd947c2012-11-06 04:35:34459 base::PostTaskAndReplyWithResult(
460 blocking_task_runner_,
[email protected]73f9c742012-06-15 07:37:13461 FROM_HERE,
[email protected]bdd947c2012-11-06 04:35:34462 base::Bind(&DriveCache::InitializeOnBlockingPool, base::Unretained(this)),
463 callback);
[email protected]73f9c742012-06-15 07:37:13464}
465
[email protected]77fb1a62012-11-01 13:42:32466void DriveCache::RequestInitializeForTesting() {
[email protected]d310bfc2012-08-10 09:41:28467 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
468
469 blocking_task_runner_->PostTask(
470 FROM_HERE,
[email protected]77fb1a62012-11-01 13:42:32471 base::Bind(&DriveCache::InitializeOnBlockingPoolForTesting,
472 base::Unretained(this)));
[email protected]d310bfc2012-08-10 09:41:28473}
474
[email protected]77fb1a62012-11-01 13:42:32475void DriveCache::Destroy() {
[email protected]73f9c742012-06-15 07:37:13476 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
477
478 // Invalidate the weak pointer.
[email protected]e53ac8f2012-08-02 07:05:00479 weak_ptr_factory_.InvalidateWeakPtrs();
[email protected]73f9c742012-06-15 07:37:13480
481 // Destroy myself on the blocking pool.
[email protected]17196ee2012-12-13 06:23:51482 // Note that base::DeletePointer<> cannot be used as the destructor of this
483 // class is private.
[email protected]ddbf2052012-07-13 15:07:02484 blocking_task_runner_->PostTask(
[email protected]73f9c742012-06-15 07:37:13485 FROM_HERE,
[email protected]3f5e2902012-11-06 08:21:15486 base::Bind(&DriveCache::DestroyOnBlockingPool, base::Unretained(this)));
[email protected]73f9c742012-06-15 07:37:13487}
488
[email protected]bdd947c2012-11-06 04:35:34489bool DriveCache::InitializeOnBlockingPool() {
[email protected]ca5f6da2012-06-18 12:54:59490 AssertOnSequencedWorkerPool();
491
[email protected]bdd947c2012-11-06 04:35:34492 if (!InitCachePaths(cache_paths_))
493 return false;
[email protected]322e0032012-10-07 01:55:53494
[email protected]c2b557732013-04-24 01:46:34495 metadata_ = CacheMetadata::CreateCacheMetadata(
[email protected]f5532c42012-11-21 10:39:56496 blocking_task_runner_);
[email protected]bdd947c2012-11-06 04:35:34497 return metadata_->Initialize(cache_paths_);
[email protected]ca5f6da2012-06-18 12:54:59498}
499
[email protected]77fb1a62012-11-01 13:42:32500void DriveCache::InitializeOnBlockingPoolForTesting() {
[email protected]d310bfc2012-08-10 09:41:28501 AssertOnSequencedWorkerPool();
502
503 InitCachePaths(cache_paths_);
[email protected]c2b557732013-04-24 01:46:34504 metadata_ = CacheMetadata::CreateCacheMetadataForTesting(
[email protected]f5532c42012-11-21 10:39:56505 blocking_task_runner_);
[email protected]d310bfc2012-08-10 09:41:28506 metadata_->Initialize(cache_paths_);
507}
508
[email protected]77fb1a62012-11-01 13:42:32509void DriveCache::DestroyOnBlockingPool() {
[email protected]73f9c742012-06-15 07:37:13510 AssertOnSequencedWorkerPool();
511 delete this;
512}
513
[email protected]717e43c2012-11-22 07:47:39514bool DriveCache::GetCacheEntryOnBlockingPool(const std::string& resource_id,
515 const std::string& md5,
516 DriveCacheEntry* entry) {
517 DCHECK(entry);
518 AssertOnSequencedWorkerPool();
519 return metadata_->GetCacheEntry(resource_id, md5, entry);
520}
521
[email protected]d68ede02012-11-07 14:30:53522void DriveCache::IterateOnBlockingPool(
523 const CacheIterateCallback& iteration_callback) {
[email protected]8764a392012-06-20 06:43:08524 AssertOnSequencedWorkerPool();
[email protected]d68ede02012-11-07 14:30:53525 DCHECK(!iteration_callback.is_null());
[email protected]8764a392012-06-20 06:43:08526
[email protected]d68ede02012-11-07 14:30:53527 metadata_->Iterate(iteration_callback);
[email protected]cd236432012-07-27 18:03:30528}
529
[email protected]f423c0b2012-11-22 09:51:10530bool DriveCache::FreeDiskSpaceOnBlockingPoolIfNeededFor(int64 num_bytes) {
531 AssertOnSequencedWorkerPool();
532
533 // Do nothing and return if we have enough space.
534 if (HasEnoughSpaceFor(num_bytes, cache_root_path_))
535 return true;
536
537 // Otherwise, try to free up the disk space.
538 DVLOG(1) << "Freeing up disk space for " << num_bytes;
539 // First remove temporary files from the metadata.
540 metadata_->RemoveTemporaryFiles();
541 // Then remove all files under "tmp" directory.
542 RemoveAllFiles(GetCacheDirectoryPath(CACHE_TYPE_TMP));
543
544 // Check the disk space again.
545 return HasEnoughSpaceFor(num_bytes, cache_root_path_);
546}
547
[email protected]bdd947c2012-11-06 04:35:34548scoped_ptr<DriveCache::GetFileResult> DriveCache::GetFileOnBlockingPool(
549 const std::string& resource_id,
550 const std::string& md5) {
[email protected]c960d222012-06-15 10:03:50551 AssertOnSequencedWorkerPool();
[email protected]bdd947c2012-11-06 04:35:34552
553 scoped_ptr<GetFileResult> result(new GetFileResult);
[email protected]c960d222012-06-15 10:03:50554
[email protected]28a64092012-08-21 10:01:12555 DriveCacheEntry cache_entry;
[email protected]bdd947c2012-11-06 04:35:34556 if (!GetCacheEntryOnBlockingPool(resource_id, md5, &cache_entry) ||
557 !cache_entry.is_present()) {
[email protected]78a158b2013-04-23 06:57:49558 result->first = FILE_ERROR_NOT_FOUND;
[email protected]bdd947c2012-11-06 04:35:34559 return result.Pass();
[email protected]c960d222012-06-15 10:03:50560 }
[email protected]bdd947c2012-11-06 04:35:34561
562 CachedFileOrigin file_origin;
563 if (cache_entry.is_mounted()) {
564 file_origin = CACHED_FILE_MOUNTED;
565 } else if (cache_entry.is_dirty()) {
566 file_origin = CACHED_FILE_LOCALLY_MODIFIED;
567 } else {
568 file_origin = CACHED_FILE_FROM_SERVER;
569 }
[email protected]78a158b2013-04-23 06:57:49570 result->first = FILE_ERROR_OK;
[email protected]bdd947c2012-11-06 04:35:34571 result->second = GetCacheFilePath(resource_id,
572 md5,
573 GetSubDirectoryType(cache_entry),
574 file_origin);
575 return result.Pass();
[email protected]c960d222012-06-15 10:03:50576}
577
[email protected]78a158b2013-04-23 06:57:49578FileError DriveCache::StoreOnBlockingPool(
[email protected]bdd947c2012-11-06 04:35:34579 const std::string& resource_id,
580 const std::string& md5,
[email protected]650b2d52013-02-10 03:41:45581 const base::FilePath& source_path,
[email protected]bdd947c2012-11-06 04:35:34582 FileOperationType file_operation_type) {
[email protected]a321b9632012-06-14 03:29:17583 AssertOnSequencedWorkerPool();
[email protected]a321b9632012-06-14 03:29:17584
[email protected]fb1b37b2013-04-09 04:37:49585 int64 file_size = 0;
[email protected]f0c67002012-08-15 04:10:38586 if (file_operation_type == FILE_OPERATION_COPY) {
[email protected]f0c67002012-08-15 04:10:38587 if (!file_util::GetFileSize(source_path, &file_size)) {
588 LOG(WARNING) << "Couldn't get file size for: " << source_path.value();
[email protected]78a158b2013-04-23 06:57:49589 return FILE_ERROR_FAILED;
[email protected]f0c67002012-08-15 04:10:38590 }
[email protected]f0c67002012-08-15 04:10:38591 }
[email protected]fb1b37b2013-04-09 04:37:49592 if (!FreeDiskSpaceOnBlockingPoolIfNeededFor(file_size))
[email protected]78a158b2013-04-23 06:57:49593 return FILE_ERROR_NO_SPACE;
[email protected]f0c67002012-08-15 04:10:38594
[email protected]650b2d52013-02-10 03:41:45595 base::FilePath symlink_path;
[email protected]a321b9632012-06-14 03:29:17596 CacheSubDirectoryType sub_dir_type = CACHE_TYPE_TMP;
597
[email protected]c80ca12f2012-11-09 10:56:03598 // If file was previously pinned, store it in persistent dir.
[email protected]28a64092012-08-21 10:01:12599 DriveCacheEntry cache_entry;
[email protected]77fb1a62012-11-01 13:42:32600 if (GetCacheEntryOnBlockingPool(resource_id, md5, &cache_entry)) {
601 // File exists in cache.
[email protected]a321b9632012-06-14 03:29:17602 // If file is dirty or mounted, return error.
[email protected]02821102012-07-12 20:19:17603 if (cache_entry.is_dirty() || cache_entry.is_mounted()) {
[email protected]a321b9632012-06-14 03:29:17604 LOG(WARNING) << "Can't store a file to replace a "
[email protected]02821102012-07-12 20:19:17605 << (cache_entry.is_dirty() ? "dirty" : "mounted")
[email protected]a321b9632012-06-14 03:29:17606 << " file: res_id=" << resource_id
607 << ", md5=" << md5;
[email protected]78a158b2013-04-23 06:57:49608 return FILE_ERROR_IN_USE;
[email protected]a321b9632012-06-14 03:29:17609 }
610
[email protected]c80ca12f2012-11-09 10:56:03611 if (cache_entry.is_pinned())
[email protected]a321b9632012-06-14 03:29:17612 sub_dir_type = CACHE_TYPE_PERSISTENT;
[email protected]a321b9632012-06-14 03:29:17613 }
614
[email protected]650b2d52013-02-10 03:41:45615 base::FilePath dest_path = GetCacheFilePath(resource_id, md5, sub_dir_type,
[email protected]c80ca12f2012-11-09 10:56:03616 CACHED_FILE_FROM_SERVER);
617 bool success = false;
618 switch (file_operation_type) {
619 case FILE_OPERATION_MOVE:
620 success = MoveFile(source_path, dest_path);
621 break;
622 case FILE_OPERATION_COPY:
623 success = CopyFile(source_path, dest_path);
624 break;
625 default:
626 NOTREACHED();
[email protected]a321b9632012-06-14 03:29:17627 }
628
[email protected]f60c670b2012-09-13 06:19:25629 // Determine search pattern for stale filenames corresponding to resource_id,
[email protected]a321b9632012-06-14 03:29:17630 // either "<resource_id>*" or "<resource_id>.*".
[email protected]650b2d52013-02-10 03:41:45631 base::FilePath stale_filenames_pattern;
[email protected]a321b9632012-06-14 03:29:17632 if (md5.empty()) {
633 // No md5 means no extension, append '*' after base name, i.e.
634 // "<resource_id>*".
635 // Cannot call |dest_path|.ReplaceExtension when there's no md5 extension:
636 // if base name of |dest_path| (i.e. escaped resource_id) contains the
637 // extension separator '.', ReplaceExtension will remove it and everything
638 // after it. The result will be nothing like the escaped resource_id.
[email protected]650b2d52013-02-10 03:41:45639 stale_filenames_pattern =
640 base::FilePath(dest_path.value() + util::kWildCard);
[email protected]a321b9632012-06-14 03:29:17641 } else {
642 // Replace md5 extension with '*' i.e. "<resource_id>.*".
643 // Note that ReplaceExtension automatically prefixes the extension with the
644 // extension separator '.'.
[email protected]ca5f6da2012-06-18 12:54:59645 stale_filenames_pattern = dest_path.ReplaceExtension(util::kWildCard);
[email protected]a321b9632012-06-14 03:29:17646 }
647
648 // Delete files that match |stale_filenames_pattern| except for |dest_path|.
649 DeleteFilesSelectively(stale_filenames_pattern, dest_path);
650
[email protected]c80ca12f2012-11-09 10:56:03651 if (success) {
652 // Now that file operations have completed, update metadata.
[email protected]b22f87f2012-07-12 10:53:17653 cache_entry.set_md5(md5);
[email protected]02821102012-07-12 20:19:17654 cache_entry.set_is_present(true);
655 cache_entry.set_is_persistent(sub_dir_type == CACHE_TYPE_PERSISTENT);
[email protected]b22f87f2012-07-12 10:53:17656 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry);
[email protected]a321b9632012-06-14 03:29:17657 }
[email protected]bdd947c2012-11-06 04:35:34658
[email protected]78a158b2013-04-23 06:57:49659 return success ? FILE_ERROR_OK : FILE_ERROR_FAILED;
[email protected]a321b9632012-06-14 03:29:17660}
661
[email protected]78a158b2013-04-23 06:57:49662FileError DriveCache::PinOnBlockingPool(const std::string& resource_id,
663 const std::string& md5) {
[email protected]a321b9632012-06-14 03:29:17664 AssertOnSequencedWorkerPool();
[email protected]a321b9632012-06-14 03:29:17665
[email protected]ae248f02013-03-06 12:55:41666 bool is_persistent = true;
[email protected]28a64092012-08-21 10:01:12667 DriveCacheEntry cache_entry;
[email protected]77fb1a62012-11-01 13:42:32668 if (!GetCacheEntryOnBlockingPool(resource_id, md5, &cache_entry)) {
[email protected]ae248f02013-03-06 12:55:41669 // The file will be first downloaded in 'tmp', then moved to 'persistent'.
670 is_persistent = false;
[email protected]109eb5c2012-07-12 03:20:05671 } else { // File exists in cache, determines destination path.
[email protected]a321b9632012-06-14 03:29:17672 // Determine source and destination paths.
673
[email protected]c80ca12f2012-11-09 10:56:03674 // If file is dirty or mounted, don't move it.
[email protected]ae248f02013-03-06 12:55:41675 if (!cache_entry.is_dirty() && !cache_entry.is_mounted()) {
[email protected]a321b9632012-06-14 03:29:17676 // If file was pinned before but actual file blob doesn't exist in cache:
[email protected]c80ca12f2012-11-09 10:56:03677 // - don't need to move the file.
[email protected]02821102012-07-12 20:19:17678 if (!cache_entry.is_present()) {
[email protected]c80ca12f2012-11-09 10:56:03679 DCHECK(cache_entry.is_pinned());
[email protected]78a158b2013-04-23 06:57:49680 return FILE_ERROR_OK;
[email protected]a321b9632012-06-14 03:29:17681 }
[email protected]c80ca12f2012-11-09 10:56:03682 // File exists, move it to persistent dir.
683 // Gets the current path of the file in cache.
[email protected]650b2d52013-02-10 03:41:45684 base::FilePath source_path = GetCacheFilePath(resource_id,
[email protected]c80ca12f2012-11-09 10:56:03685 md5,
686 GetSubDirectoryType(cache_entry),
687 CACHED_FILE_FROM_SERVER);
[email protected]ae248f02013-03-06 12:55:41688 base::FilePath dest_path = GetCacheFilePath(resource_id,
689 md5,
690 CACHE_TYPE_PERSISTENT,
691 CACHED_FILE_FROM_SERVER);
[email protected]c80ca12f2012-11-09 10:56:03692 if (!MoveFile(source_path, dest_path))
[email protected]78a158b2013-04-23 06:57:49693 return FILE_ERROR_FAILED;
[email protected]a321b9632012-06-14 03:29:17694 }
695 }
696
[email protected]c80ca12f2012-11-09 10:56:03697 // Now that file operations have completed, update metadata.
698 cache_entry.set_md5(md5);
699 cache_entry.set_is_pinned(true);
[email protected]ae248f02013-03-06 12:55:41700 cache_entry.set_is_persistent(is_persistent);
[email protected]c80ca12f2012-11-09 10:56:03701 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry);
[email protected]78a158b2013-04-23 06:57:49702 return FILE_ERROR_OK;
[email protected]a321b9632012-06-14 03:29:17703}
704
[email protected]78a158b2013-04-23 06:57:49705FileError DriveCache::UnpinOnBlockingPool(const std::string& resource_id,
706 const std::string& md5) {
[email protected]a321b9632012-06-14 03:29:17707 AssertOnSequencedWorkerPool();
[email protected]a321b9632012-06-14 03:29:17708
[email protected]a321b9632012-06-14 03:29:17709 // Unpinning a file means its entry must exist in cache.
[email protected]28a64092012-08-21 10:01:12710 DriveCacheEntry cache_entry;
[email protected]77fb1a62012-11-01 13:42:32711 if (!GetCacheEntryOnBlockingPool(resource_id, md5, &cache_entry)) {
[email protected]a321b9632012-06-14 03:29:17712 LOG(WARNING) << "Can't unpin a file that wasn't pinned or cached: res_id="
713 << resource_id
714 << ", md5=" << md5;
[email protected]78a158b2013-04-23 06:57:49715 return FILE_ERROR_NOT_FOUND;
[email protected]a321b9632012-06-14 03:29:17716 }
717
[email protected]a321b9632012-06-14 03:29:17718 CacheSubDirectoryType sub_dir_type = CACHE_TYPE_TMP;
719
[email protected]c80ca12f2012-11-09 10:56:03720 // If file is dirty or mounted, don't move it.
[email protected]02821102012-07-12 20:19:17721 if (cache_entry.is_dirty() || cache_entry.is_mounted()) {
[email protected]a321b9632012-06-14 03:29:17722 sub_dir_type = CACHE_TYPE_PERSISTENT;
[email protected]02821102012-07-12 20:19:17723 DCHECK(cache_entry.is_persistent());
[email protected]a321b9632012-06-14 03:29:17724 } else {
[email protected]a321b9632012-06-14 03:29:17725 // If file was pinned but actual file blob still doesn't exist in cache,
[email protected]c80ca12f2012-11-09 10:56:03726 // don't need to move the file.
[email protected]02821102012-07-12 20:19:17727 if (cache_entry.is_present()) {
[email protected]c80ca12f2012-11-09 10:56:03728 // Gets the current path of the file in cache.
[email protected]650b2d52013-02-10 03:41:45729 base::FilePath source_path = GetCacheFilePath(resource_id,
[email protected]c80ca12f2012-11-09 10:56:03730 md5,
731 GetSubDirectoryType(cache_entry),
732 CACHED_FILE_FROM_SERVER);
733 // File exists, move it to tmp dir.
[email protected]650b2d52013-02-10 03:41:45734 base::FilePath dest_path = GetCacheFilePath(resource_id,
[email protected]c80ca12f2012-11-09 10:56:03735 md5,
736 CACHE_TYPE_TMP,
737 CACHED_FILE_FROM_SERVER);
738 if (!MoveFile(source_path, dest_path))
[email protected]78a158b2013-04-23 06:57:49739 return FILE_ERROR_FAILED;
[email protected]3423871a2012-07-12 00:41:27740 }
[email protected]a321b9632012-06-14 03:29:17741 }
[email protected]bdd947c2012-11-06 04:35:34742
[email protected]c80ca12f2012-11-09 10:56:03743 // Now that file operations have completed, update metadata.
744 if (cache_entry.is_present()) {
745 cache_entry.set_md5(md5);
746 cache_entry.set_is_pinned(false);
747 cache_entry.set_is_persistent(sub_dir_type == CACHE_TYPE_PERSISTENT);
748 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry);
749 } else {
750 // Remove the existing entry if we are unpinning a non-present file.
751 metadata_->RemoveCacheEntry(resource_id);
752 }
[email protected]78a158b2013-04-23 06:57:49753 return FILE_ERROR_OK;
[email protected]a321b9632012-06-14 03:29:17754}
755
[email protected]9564c1502012-11-28 12:12:16756scoped_ptr<DriveCache::GetFileResult> DriveCache::MarkAsMountedOnBlockingPool(
[email protected]35c1f9b2013-02-07 07:39:42757 const std::string& resource_id,
758 const std::string& md5) {
[email protected]a321b9632012-06-14 03:29:17759 AssertOnSequencedWorkerPool();
[email protected]bdd947c2012-11-06 04:35:34760
761 scoped_ptr<GetFileResult> result(new GetFileResult);
[email protected]a321b9632012-06-14 03:29:17762
[email protected]a321b9632012-06-14 03:29:17763 // Get cache entry associated with the resource_id and md5
[email protected]28a64092012-08-21 10:01:12764 DriveCacheEntry cache_entry;
[email protected]77fb1a62012-11-01 13:42:32765 if (!GetCacheEntryOnBlockingPool(resource_id, md5, &cache_entry)) {
[email protected]78a158b2013-04-23 06:57:49766 result->first = FILE_ERROR_NOT_FOUND;
[email protected]bdd947c2012-11-06 04:35:34767 return result.Pass();
[email protected]a321b9632012-06-14 03:29:17768 }
[email protected]bdd947c2012-11-06 04:35:34769
[email protected]9564c1502012-11-28 12:12:16770 if (cache_entry.is_mounted()) {
[email protected]78a158b2013-04-23 06:57:49771 result->first = FILE_ERROR_INVALID_OPERATION;
[email protected]bdd947c2012-11-06 04:35:34772 return result.Pass();
[email protected]a321b9632012-06-14 03:29:17773 }
774
775 // Get the subdir type and path for the unmounted state.
776 CacheSubDirectoryType unmounted_subdir =
[email protected]02821102012-07-12 20:19:17777 cache_entry.is_pinned() ? CACHE_TYPE_PERSISTENT : CACHE_TYPE_TMP;
[email protected]650b2d52013-02-10 03:41:45778 base::FilePath unmounted_path = GetCacheFilePath(
[email protected]a321b9632012-06-14 03:29:17779 resource_id, md5, unmounted_subdir, CACHED_FILE_FROM_SERVER);
780
781 // Get the subdir type and path for the mounted state.
782 CacheSubDirectoryType mounted_subdir = CACHE_TYPE_PERSISTENT;
[email protected]650b2d52013-02-10 03:41:45783 base::FilePath mounted_path = GetCacheFilePath(
[email protected]a321b9632012-06-14 03:29:17784 resource_id, md5, mounted_subdir, CACHED_FILE_MOUNTED);
785
[email protected]9564c1502012-11-28 12:12:16786 // Move cache file.
787 bool success = MoveFile(unmounted_path, mounted_path);
[email protected]c80ca12f2012-11-09 10:56:03788
789 if (success) {
790 // Now that cache operation is complete, update metadata.
[email protected]48477fe2012-07-12 17:45:08791 cache_entry.set_md5(md5);
[email protected]9564c1502012-11-28 12:12:16792 cache_entry.set_is_mounted(true);
793 cache_entry.set_is_persistent(true);
[email protected]48477fe2012-07-12 17:45:08794 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry);
[email protected]a321b9632012-06-14 03:29:17795 }
[email protected]78a158b2013-04-23 06:57:49796 result->first = success ? FILE_ERROR_OK : FILE_ERROR_FAILED;
[email protected]9564c1502012-11-28 12:12:16797 result->second = mounted_path;
[email protected]bdd947c2012-11-06 04:35:34798 return result.Pass();
[email protected]a321b9632012-06-14 03:29:17799}
800
[email protected]78a158b2013-04-23 06:57:49801FileError DriveCache::MarkAsUnmountedOnBlockingPool(
[email protected]650b2d52013-02-10 03:41:45802 const base::FilePath& file_path) {
[email protected]9564c1502012-11-28 12:12:16803 AssertOnSequencedWorkerPool();
[email protected]3a680f32013-03-01 04:07:27804 DCHECK(IsUnderDriveCacheDirectory(file_path));
[email protected]9564c1502012-11-28 12:12:16805
806 // Parse file path to obtain resource_id, md5 and extra_extension.
807 std::string resource_id;
808 std::string md5;
809 std::string extra_extension;
810 util::ParseCacheFilePath(file_path, &resource_id, &md5, &extra_extension);
811 // The extra_extension shall be ".mounted" iff we're unmounting.
[email protected]3a680f32013-03-01 04:07:27812 DCHECK_EQ(util::kMountedArchiveFileExtension, extra_extension);
[email protected]9564c1502012-11-28 12:12:16813
814 // Get cache entry associated with the resource_id and md5
815 DriveCacheEntry cache_entry;
816 if (!GetCacheEntryOnBlockingPool(resource_id, md5, &cache_entry))
[email protected]78a158b2013-04-23 06:57:49817 return FILE_ERROR_NOT_FOUND;
[email protected]9564c1502012-11-28 12:12:16818
819 if (!cache_entry.is_mounted())
[email protected]78a158b2013-04-23 06:57:49820 return FILE_ERROR_INVALID_OPERATION;
[email protected]9564c1502012-11-28 12:12:16821
822 // Get the subdir type and path for the unmounted state.
823 CacheSubDirectoryType unmounted_subdir =
824 cache_entry.is_pinned() ? CACHE_TYPE_PERSISTENT : CACHE_TYPE_TMP;
[email protected]650b2d52013-02-10 03:41:45825 base::FilePath unmounted_path = GetCacheFilePath(
[email protected]9564c1502012-11-28 12:12:16826 resource_id, md5, unmounted_subdir, CACHED_FILE_FROM_SERVER);
827
828 // Get the subdir type and path for the mounted state.
829 CacheSubDirectoryType mounted_subdir = CACHE_TYPE_PERSISTENT;
[email protected]650b2d52013-02-10 03:41:45830 base::FilePath mounted_path = GetCacheFilePath(
[email protected]9564c1502012-11-28 12:12:16831 resource_id, md5, mounted_subdir, CACHED_FILE_MOUNTED);
832
833 // Move cache file.
834 if (!MoveFile(mounted_path, unmounted_path))
[email protected]78a158b2013-04-23 06:57:49835 return FILE_ERROR_FAILED;
[email protected]9564c1502012-11-28 12:12:16836
837 // Now that cache operation is complete, update metadata.
838 cache_entry.set_md5(md5);
839 cache_entry.set_is_mounted(false);
840 cache_entry.set_is_persistent(unmounted_subdir == CACHE_TYPE_PERSISTENT);
841 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry);
[email protected]78a158b2013-04-23 06:57:49842 return FILE_ERROR_OK;
[email protected]9564c1502012-11-28 12:12:16843}
844
[email protected]78a158b2013-04-23 06:57:49845FileError DriveCache::MarkDirtyOnBlockingPool(
[email protected]bdd947c2012-11-06 04:35:34846 const std::string& resource_id,
847 const std::string& md5) {
[email protected]c960d222012-06-15 10:03:50848 AssertOnSequencedWorkerPool();
[email protected]bdd947c2012-11-06 04:35:34849
[email protected]c960d222012-06-15 10:03:50850 // If file has already been marked dirty in previous instance of chrome, we
851 // would have lost the md5 info during cache initialization, because the file
852 // would have been renamed to .local extension.
853 // So, search for entry in cache without comparing md5.
[email protected]c960d222012-06-15 10:03:50854
855 // Marking a file dirty means its entry and actual file blob must exist in
856 // cache.
[email protected]28a64092012-08-21 10:01:12857 DriveCacheEntry cache_entry;
[email protected]77fb1a62012-11-01 13:42:32858 if (!GetCacheEntryOnBlockingPool(resource_id, std::string(), &cache_entry) ||
[email protected]02821102012-07-12 20:19:17859 !cache_entry.is_present()) {
[email protected]c960d222012-06-15 10:03:50860 LOG(WARNING) << "Can't mark dirty a file that wasn't cached: res_id="
861 << resource_id
862 << ", md5=" << md5;
[email protected]78a158b2013-04-23 06:57:49863 return FILE_ERROR_NOT_FOUND;
[email protected]c960d222012-06-15 10:03:50864 }
865
866 // If a file is already dirty (i.e. MarkDirtyInCache was called before),
867 // delete outgoing symlink if it exists.
868 // TODO(benchan): We should only delete outgoing symlink if file is currently
869 // not being uploaded. However, for now, cache doesn't know if uploading of a
870 // file is in progress. Per zel, the upload process should be canceled before
871 // MarkDirtyInCache is called again.
[email protected]02821102012-07-12 20:19:17872 if (cache_entry.is_dirty()) {
[email protected]c960d222012-06-15 10:03:50873 // The file must be in persistent dir.
[email protected]02821102012-07-12 20:19:17874 DCHECK(cache_entry.is_persistent());
[email protected]c960d222012-06-15 10:03:50875
876 // Determine symlink path in outgoing dir, so as to remove it.
[email protected]650b2d52013-02-10 03:41:45877 base::FilePath symlink_path = GetCacheFilePath(resource_id,
[email protected]c80ca12f2012-11-09 10:56:03878 std::string(),
879 CACHE_TYPE_OUTGOING,
880 CACHED_FILE_FROM_SERVER);
881 DeleteSymlink(symlink_path);
[email protected]c960d222012-06-15 10:03:50882
[email protected]78a158b2013-04-23 06:57:49883 return FILE_ERROR_OK;
[email protected]c960d222012-06-15 10:03:50884 }
885
886 // Move file to persistent dir with new .local extension.
887
888 // Get the current path of the file in cache.
[email protected]650b2d52013-02-10 03:41:45889 base::FilePath source_path = GetCacheFilePath(resource_id,
[email protected]c80ca12f2012-11-09 10:56:03890 md5,
891 GetSubDirectoryType(cache_entry),
892 CACHED_FILE_FROM_SERVER);
[email protected]c960d222012-06-15 10:03:50893 // Determine destination path.
[email protected]3dc88ee2012-07-11 21:04:11894 const CacheSubDirectoryType sub_dir_type = CACHE_TYPE_PERSISTENT;
[email protected]650b2d52013-02-10 03:41:45895 base::FilePath cache_file_path = GetCacheFilePath(resource_id,
[email protected]bdd947c2012-11-06 04:35:34896 md5,
897 sub_dir_type,
898 CACHED_FILE_LOCALLY_MODIFIED);
[email protected]c960d222012-06-15 10:03:50899
[email protected]ae248f02013-03-06 12:55:41900 if (!MoveFile(source_path, cache_file_path))
[email protected]78a158b2013-04-23 06:57:49901 return FILE_ERROR_FAILED;
[email protected]c80ca12f2012-11-09 10:56:03902
[email protected]ae248f02013-03-06 12:55:41903 // Now that file operations have completed, update metadata.
904 cache_entry.set_md5(md5);
905 cache_entry.set_is_dirty(true);
906 cache_entry.set_is_persistent(sub_dir_type == CACHE_TYPE_PERSISTENT);
907 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry);
[email protected]78a158b2013-04-23 06:57:49908 return FILE_ERROR_OK;
[email protected]c960d222012-06-15 10:03:50909}
910
[email protected]78a158b2013-04-23 06:57:49911FileError DriveCache::CommitDirtyOnBlockingPool(
[email protected]77fb1a62012-11-01 13:42:32912 const std::string& resource_id,
[email protected]3f5e2902012-11-06 08:21:15913 const std::string& md5) {
[email protected]a321b9632012-06-14 03:29:17914 AssertOnSequencedWorkerPool();
[email protected]a321b9632012-06-14 03:29:17915
916 // If file has already been marked dirty in previous instance of chrome, we
917 // would have lost the md5 info during cache initialization, because the file
918 // would have been renamed to .local extension.
919 // So, search for entry in cache without comparing md5.
[email protected]a321b9632012-06-14 03:29:17920
921 // Committing a file dirty means its entry and actual file blob must exist in
922 // cache.
[email protected]28a64092012-08-21 10:01:12923 DriveCacheEntry cache_entry;
[email protected]77fb1a62012-11-01 13:42:32924 if (!GetCacheEntryOnBlockingPool(resource_id, std::string(), &cache_entry) ||
[email protected]02821102012-07-12 20:19:17925 !cache_entry.is_present()) {
[email protected]a321b9632012-06-14 03:29:17926 LOG(WARNING) << "Can't commit dirty a file that wasn't cached: res_id="
927 << resource_id
928 << ", md5=" << md5;
[email protected]78a158b2013-04-23 06:57:49929 return FILE_ERROR_NOT_FOUND;
[email protected]a321b9632012-06-14 03:29:17930 }
931
932 // If a file is not dirty (it should have been marked dirty via
933 // MarkDirtyInCache), committing it dirty is an invalid operation.
[email protected]02821102012-07-12 20:19:17934 if (!cache_entry.is_dirty()) {
[email protected]a321b9632012-06-14 03:29:17935 LOG(WARNING) << "Can't commit a non-dirty file: res_id="
936 << resource_id
937 << ", md5=" << md5;
[email protected]78a158b2013-04-23 06:57:49938 return FILE_ERROR_INVALID_OPERATION;
[email protected]a321b9632012-06-14 03:29:17939 }
940
941 // Dirty files must be in persistent dir.
[email protected]02821102012-07-12 20:19:17942 DCHECK(cache_entry.is_persistent());
[email protected]a321b9632012-06-14 03:29:17943
944 // Create symlink in outgoing dir.
[email protected]650b2d52013-02-10 03:41:45945 base::FilePath symlink_path = GetCacheFilePath(resource_id,
[email protected]a321b9632012-06-14 03:29:17946 std::string(),
947 CACHE_TYPE_OUTGOING,
948 CACHED_FILE_FROM_SERVER);
949
950 // Get target path of symlink i.e. current path of the file in cache.
[email protected]650b2d52013-02-10 03:41:45951 base::FilePath target_path = GetCacheFilePath(resource_id,
[email protected]a321b9632012-06-14 03:29:17952 md5,
[email protected]b22f87f2012-07-12 10:53:17953 GetSubDirectoryType(cache_entry),
[email protected]a321b9632012-06-14 03:29:17954 CACHED_FILE_LOCALLY_MODIFIED);
955
[email protected]c80ca12f2012-11-09 10:56:03956 return CreateSymlink(target_path, symlink_path) ?
[email protected]78a158b2013-04-23 06:57:49957 FILE_ERROR_OK : FILE_ERROR_FAILED;
[email protected]a321b9632012-06-14 03:29:17958}
959
[email protected]78a158b2013-04-23 06:57:49960FileError DriveCache::ClearDirtyOnBlockingPool(
[email protected]bdd947c2012-11-06 04:35:34961 const std::string& resource_id,
[email protected]3f5e2902012-11-06 08:21:15962 const std::string& md5) {
[email protected]a321b9632012-06-14 03:29:17963 AssertOnSequencedWorkerPool();
[email protected]a321b9632012-06-14 03:29:17964
965 // |md5| is the new .<md5> extension to rename the file to.
966 // So, search for entry in cache without comparing md5.
[email protected]28a64092012-08-21 10:01:12967 DriveCacheEntry cache_entry;
[email protected]a321b9632012-06-14 03:29:17968
969 // Clearing a dirty file means its entry and actual file blob must exist in
970 // cache.
[email protected]77fb1a62012-11-01 13:42:32971 if (!GetCacheEntryOnBlockingPool(resource_id, std::string(), &cache_entry) ||
[email protected]02821102012-07-12 20:19:17972 !cache_entry.is_present()) {
[email protected]a321b9632012-06-14 03:29:17973 LOG(WARNING) << "Can't clear dirty state of a file that wasn't cached: "
974 << "res_id=" << resource_id
975 << ", md5=" << md5;
[email protected]78a158b2013-04-23 06:57:49976 return FILE_ERROR_NOT_FOUND;
[email protected]a321b9632012-06-14 03:29:17977 }
978
979 // If a file is not dirty (it should have been marked dirty via
980 // MarkDirtyInCache), clearing its dirty state is an invalid operation.
[email protected]02821102012-07-12 20:19:17981 if (!cache_entry.is_dirty()) {
[email protected]a321b9632012-06-14 03:29:17982 LOG(WARNING) << "Can't clear dirty state of a non-dirty file: res_id="
983 << resource_id
984 << ", md5=" << md5;
[email protected]78a158b2013-04-23 06:57:49985 return FILE_ERROR_INVALID_OPERATION;
[email protected]a321b9632012-06-14 03:29:17986 }
987
988 // File must be dirty and hence in persistent dir.
[email protected]02821102012-07-12 20:19:17989 DCHECK(cache_entry.is_persistent());
[email protected]a321b9632012-06-14 03:29:17990
991 // Get the current path of the file in cache.
[email protected]ae248f02013-03-06 12:55:41992 base::FilePath source_path =
993 GetCacheFilePath(resource_id,
994 md5,
995 GetSubDirectoryType(cache_entry),
996 CACHED_FILE_LOCALLY_MODIFIED);
[email protected]a321b9632012-06-14 03:29:17997
998 // Determine destination path.
999 // If file is pinned, move it to persistent dir with .md5 extension;
1000 // otherwise, move it to tmp dir with .md5 extension.
[email protected]3dc88ee2012-07-11 21:04:111001 const CacheSubDirectoryType sub_dir_type =
[email protected]02821102012-07-12 20:19:171002 cache_entry.is_pinned() ? CACHE_TYPE_PERSISTENT : CACHE_TYPE_TMP;
[email protected]650b2d52013-02-10 03:41:451003 base::FilePath dest_path = GetCacheFilePath(resource_id,
[email protected]ae248f02013-03-06 12:55:411004 md5,
1005 sub_dir_type,
1006 CACHED_FILE_FROM_SERVER);
[email protected]a321b9632012-06-14 03:29:171007
[email protected]ae248f02013-03-06 12:55:411008 if (!MoveFile(source_path, dest_path))
[email protected]78a158b2013-04-23 06:57:491009 return FILE_ERROR_FAILED;
[email protected]a321b9632012-06-14 03:29:171010
[email protected]ae248f02013-03-06 12:55:411011 // Delete symlink in outgoing dir.
1012 base::FilePath symlink_path = GetCacheFilePath(resource_id,
1013 std::string(),
1014 CACHE_TYPE_OUTGOING,
1015 CACHED_FILE_FROM_SERVER);
1016 DeleteSymlink(symlink_path);
[email protected]a321b9632012-06-14 03:29:171017
[email protected]ae248f02013-03-06 12:55:411018 // Now that file operations have completed, update metadata.
1019 cache_entry.set_md5(md5);
1020 cache_entry.set_is_dirty(false);
1021 cache_entry.set_is_persistent(sub_dir_type == CACHE_TYPE_PERSISTENT);
1022 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry);
[email protected]78a158b2013-04-23 06:57:491023 return FILE_ERROR_OK;
[email protected]a321b9632012-06-14 03:29:171024}
1025
[email protected]78a158b2013-04-23 06:57:491026FileError DriveCache::RemoveOnBlockingPool(
[email protected]bdd947c2012-11-06 04:35:341027 const std::string& resource_id) {
[email protected]a321b9632012-06-14 03:29:171028 AssertOnSequencedWorkerPool();
[email protected]a321b9632012-06-14 03:29:171029
[email protected]3423871a2012-07-12 00:41:271030 // MD5 is not passed into RemoveCacheEntry because we would delete all
1031 // cache files corresponding to <resource_id> regardless of the md5.
[email protected]a321b9632012-06-14 03:29:171032 // So, search for entry in cache without taking md5 into account.
[email protected]28a64092012-08-21 10:01:121033 DriveCacheEntry cache_entry;
[email protected]a321b9632012-06-14 03:29:171034
1035 // If entry doesn't exist or is dirty or mounted in cache, nothing to do.
[email protected]b22f87f2012-07-12 10:53:171036 const bool entry_found =
[email protected]77fb1a62012-11-01 13:42:321037 GetCacheEntryOnBlockingPool(resource_id, std::string(), &cache_entry);
[email protected]02821102012-07-12 20:19:171038 if (!entry_found || cache_entry.is_dirty() || cache_entry.is_mounted()) {
[email protected]a321b9632012-06-14 03:29:171039 DVLOG(1) << "Entry is "
[email protected]b22f87f2012-07-12 10:53:171040 << (entry_found ?
[email protected]02821102012-07-12 20:19:171041 (cache_entry.is_dirty() ? "dirty" : "mounted") :
[email protected]a321b9632012-06-14 03:29:171042 "non-existent")
1043 << " in cache, not removing";
[email protected]78a158b2013-04-23 06:57:491044 return FILE_ERROR_OK;
[email protected]a321b9632012-06-14 03:29:171045 }
1046
1047 // Determine paths to delete all cache versions of |resource_id| in
1048 // persistent, tmp and pinned directories.
[email protected]650b2d52013-02-10 03:41:451049 std::vector<base::FilePath> paths_to_delete;
[email protected]a321b9632012-06-14 03:29:171050
1051 // For files in persistent and tmp dirs, delete files that match
1052 // "<resource_id>.*".
1053 paths_to_delete.push_back(GetCacheFilePath(resource_id,
[email protected]ca5f6da2012-06-18 12:54:591054 util::kWildCard,
[email protected]a321b9632012-06-14 03:29:171055 CACHE_TYPE_PERSISTENT,
1056 CACHED_FILE_FROM_SERVER));
1057 paths_to_delete.push_back(GetCacheFilePath(resource_id,
[email protected]ca5f6da2012-06-18 12:54:591058 util::kWildCard,
[email protected]a321b9632012-06-14 03:29:171059 CACHE_TYPE_TMP,
1060 CACHED_FILE_FROM_SERVER));
1061
[email protected]a321b9632012-06-14 03:29:171062 // Don't delete locally modified (i.e. dirty and possibly outgoing) files.
1063 // Since we're not deleting outgoing symlinks, we don't need to append
1064 // outgoing path to |paths_to_delete|.
[email protected]650b2d52013-02-10 03:41:451065 base::FilePath path_to_keep = GetCacheFilePath(resource_id,
[email protected]a321b9632012-06-14 03:29:171066 std::string(),
1067 CACHE_TYPE_PERSISTENT,
1068 CACHED_FILE_LOCALLY_MODIFIED);
1069
1070 for (size_t i = 0; i < paths_to_delete.size(); ++i) {
1071 DeleteFilesSelectively(paths_to_delete[i], path_to_keep);
1072 }
1073
[email protected]c80ca12f2012-11-09 10:56:031074 // Now that all file operations have completed, remove from metadata.
[email protected]3423871a2012-07-12 00:41:271075 metadata_->RemoveCacheEntry(resource_id);
[email protected]a321b9632012-06-14 03:29:171076
[email protected]78a158b2013-04-23 06:57:491077 return FILE_ERROR_OK;
[email protected]a321b9632012-06-14 03:29:171078}
1079
[email protected]bdd947c2012-11-06 04:35:341080bool DriveCache::ClearAllOnBlockingPool() {
[email protected]f861b392012-08-03 20:41:121081 AssertOnSequencedWorkerPool();
[email protected]f861b392012-08-03 20:41:121082
[email protected]bdd947c2012-11-06 04:35:341083 if (!file_util::Delete(cache_root_path_, true)) {
[email protected]322e0032012-10-07 01:55:531084 LOG(WARNING) << "Failed to delete the cache directory";
[email protected]bdd947c2012-11-06 04:35:341085 return false;
[email protected]322e0032012-10-07 01:55:531086 }
[email protected]f861b392012-08-03 20:41:121087
[email protected]bdd947c2012-11-06 04:35:341088 if (!InitializeOnBlockingPool()) {
[email protected]322e0032012-10-07 01:55:531089 LOG(WARNING) << "Failed to initialize the cache";
[email protected]bdd947c2012-11-06 04:35:341090 return false;
[email protected]322e0032012-10-07 01:55:531091 }
[email protected]bdd947c2012-11-06 04:35:341092 return true;
[email protected]f861b392012-08-03 20:41:121093}
1094
[email protected]bdd947c2012-11-06 04:35:341095void DriveCache::OnPinned(const std::string& resource_id,
[email protected]73f9c742012-06-15 07:37:131096 const std::string& md5,
[email protected]2a2c4152012-11-26 11:34:501097 const FileOperationCallback& callback,
[email protected]78a158b2013-04-23 06:57:491098 FileError error) {
[email protected]73f9c742012-06-15 07:37:131099 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]2a2c4152012-11-26 11:34:501100 DCHECK(!callback.is_null());
[email protected]73f9c742012-06-15 07:37:131101
[email protected]2a2c4152012-11-26 11:34:501102 callback.Run(error);
[email protected]73f9c742012-06-15 07:37:131103
[email protected]78a158b2013-04-23 06:57:491104 if (error == FILE_ERROR_OK)
[email protected]bd547ad82013-04-26 04:52:291105 FOR_EACH_OBSERVER(CacheObserver,
[email protected]a09275502012-10-10 04:48:011106 observers_,
1107 OnCachePinned(resource_id, md5));
[email protected]3653146a2012-05-29 13:41:471108}
1109
[email protected]bdd947c2012-11-06 04:35:341110void DriveCache::OnUnpinned(const std::string& resource_id,
[email protected]73f9c742012-06-15 07:37:131111 const std::string& md5,
[email protected]2a2c4152012-11-26 11:34:501112 const FileOperationCallback& callback,
[email protected]78a158b2013-04-23 06:57:491113 FileError error) {
[email protected]73f9c742012-06-15 07:37:131114 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]2a2c4152012-11-26 11:34:501115 DCHECK(!callback.is_null());
[email protected]a321b9632012-06-14 03:29:171116
[email protected]2a2c4152012-11-26 11:34:501117 callback.Run(error);
[email protected]a321b9632012-06-14 03:29:171118
[email protected]78a158b2013-04-23 06:57:491119 if (error == FILE_ERROR_OK)
[email protected]bd547ad82013-04-26 04:52:291120 FOR_EACH_OBSERVER(CacheObserver,
[email protected]a09275502012-10-10 04:48:011121 observers_,
1122 OnCacheUnpinned(resource_id, md5));
[email protected]a321b9632012-06-14 03:29:171123
[email protected]73f9c742012-06-15 07:37:131124 // Now the file is moved from "persistent" to "tmp" directory.
1125 // It's a chance to free up space if needed.
[email protected]ddbf2052012-07-13 15:07:021126 blocking_task_runner_->PostTask(
[email protected]73f9c742012-06-15 07:37:131127 FROM_HERE,
[email protected]77fb1a62012-11-01 13:42:321128 base::Bind(
1129 base::IgnoreResult(
1130 &DriveCache::FreeDiskSpaceOnBlockingPoolIfNeededFor),
1131 base::Unretained(this), 0));
[email protected]3653146a2012-05-29 13:41:471132}
1133
[email protected]bdd947c2012-11-06 04:35:341134void DriveCache::OnCommitDirty(const std::string& resource_id,
[email protected]2a2c4152012-11-26 11:34:501135 const FileOperationCallback& callback,
[email protected]78a158b2013-04-23 06:57:491136 FileError error) {
[email protected]d7664c22012-06-18 19:35:491137 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]2a2c4152012-11-26 11:34:501138 DCHECK(!callback.is_null());
[email protected]d7664c22012-06-18 19:35:491139
[email protected]2a2c4152012-11-26 11:34:501140 callback.Run(error);
[email protected]d7664c22012-06-18 19:35:491141
[email protected]78a158b2013-04-23 06:57:491142 if (error == FILE_ERROR_OK)
[email protected]bd547ad82013-04-26 04:52:291143 FOR_EACH_OBSERVER(CacheObserver,
[email protected]a09275502012-10-10 04:48:011144 observers_,
1145 OnCacheCommitted(resource_id));
[email protected]d7664c22012-06-18 19:35:491146}
1147
[email protected]650b2d52013-02-10 03:41:451148bool DriveCache::HasEnoughSpaceFor(int64 num_bytes,
1149 const base::FilePath& path) {
[email protected]f6fd98a2012-12-14 00:04:021150 int64 free_space = 0;
1151 if (free_disk_space_getter_)
1152 free_space = free_disk_space_getter_->AmountOfFreeDiskSpace();
1153 else
1154 free_space = base::SysInfo::AmountOfFreeDiskSpace(path);
1155
1156 // Subtract this as if this portion does not exist.
1157 free_space -= kMinFreeSpace;
1158 return (free_space >= num_bytes);
1159}
1160
[email protected]01ba15f72012-06-09 00:41:051161// static
[email protected]650b2d52013-02-10 03:41:451162base::FilePath DriveCache::GetCacheRootPath(Profile* profile) {
1163 base::FilePath cache_base_path;
[email protected]01ba15f72012-06-09 00:41:051164 chrome::GetUserCacheDirectory(profile->GetPath(), &cache_base_path);
[email protected]650b2d52013-02-10 03:41:451165 base::FilePath cache_root_path =
[email protected]fb371812012-08-22 16:05:231166 cache_base_path.Append(chrome::kDriveCacheDirname);
1167 return cache_root_path.Append(kDriveCacheVersionDir);
[email protected]01ba15f72012-06-09 00:41:051168}
1169
[email protected]30d9dda2012-06-30 05:56:281170// static
[email protected]650b2d52013-02-10 03:41:451171std::vector<base::FilePath> DriveCache::GetCachePaths(
1172 const base::FilePath& cache_root_path) {
1173 std::vector<base::FilePath> cache_paths;
[email protected]fb371812012-08-22 16:05:231174 // The order should match DriveCache::CacheSubDirectoryType enum.
1175 cache_paths.push_back(cache_root_path.Append(kDriveCacheMetaDir));
[email protected]fb371812012-08-22 16:05:231176 cache_paths.push_back(cache_root_path.Append(kDriveCacheOutgoingDir));
1177 cache_paths.push_back(cache_root_path.Append(kDriveCachePersistentDir));
1178 cache_paths.push_back(cache_root_path.Append(kDriveCacheTmpDir));
1179 cache_paths.push_back(cache_root_path.Append(kDriveCacheTmpDownloadsDir));
1180 cache_paths.push_back(cache_root_path.Append(kDriveCacheTmpDocumentsDir));
[email protected]30d9dda2012-06-30 05:56:281181 return cache_paths;
1182}
1183
1184// static
[email protected]fb371812012-08-22 16:05:231185bool DriveCache::CreateCacheDirectories(
[email protected]650b2d52013-02-10 03:41:451186 const std::vector<base::FilePath>& paths_to_create) {
[email protected]30d9dda2012-06-30 05:56:281187 bool success = true;
1188
1189 for (size_t i = 0; i < paths_to_create.size(); ++i) {
1190 if (file_util::DirectoryExists(paths_to_create[i]))
1191 continue;
1192
1193 if (!file_util::CreateDirectory(paths_to_create[i])) {
1194 // Error creating this directory, record error and proceed with next one.
1195 success = false;
1196 PLOG(ERROR) << "Error creating directory " << paths_to_create[i].value();
1197 } else {
1198 DVLOG(1) << "Created directory " << paths_to_create[i].value();
1199 }
1200 }
1201 return success;
1202}
1203
[email protected]fae353a2012-07-11 23:30:271204// static
[email protected]fb371812012-08-22 16:05:231205DriveCache::CacheSubDirectoryType DriveCache::GetSubDirectoryType(
[email protected]28a64092012-08-21 10:01:121206 const DriveCacheEntry& cache_entry) {
[email protected]02821102012-07-12 20:19:171207 return cache_entry.is_persistent() ? CACHE_TYPE_PERSISTENT : CACHE_TYPE_TMP;
[email protected]fae353a2012-07-11 23:30:271208}
1209
[email protected]d9d04df2012-10-12 07:06:351210} // namespace drive