blob: 769059d145ef78e50799fb878c148b0c34ee04c6 [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]fb371812012-08-22 16:05:235#include "chrome/browser/chromeos/gdata/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/chromeos/chromeos_version.h"
10#include "base/file_util.h"
[email protected]3653146a2012-05-29 13:41:4711#include "base/logging.h"
[email protected]774727282012-08-06 09:14:4412#include "base/path_service.h"
[email protected]3653146a2012-05-29 13:41:4713#include "base/stringprintf.h"
14#include "base/string_util.h"
[email protected]a321b9632012-06-14 03:29:1715#include "base/sys_info.h"
[email protected]28a64092012-08-21 10:01:1216#include "chrome/browser/chromeos/gdata/drive.pb.h"
[email protected]fb371812012-08-22 16:05:2317#include "chrome/browser/chromeos/gdata/drive_cache_metadata.h"
[email protected]32a7fc852012-06-08 17:25:5018#include "chrome/browser/chromeos/gdata/gdata_util.h"
[email protected]01ba15f72012-06-09 00:41:0519#include "chrome/browser/profiles/profile.h"
20#include "chrome/common/chrome_constants.h"
21#include "chrome/common/chrome_paths_internal.h"
[email protected]7986b8d2012-06-14 15:05:1422#include "content/public/browser/browser_thread.h"
23
24using content::BrowserThread;
[email protected]3653146a2012-05-29 13:41:4725
26namespace gdata {
27namespace {
28
[email protected]fb371812012-08-22 16:05:2329const FilePath::CharType kDriveCacheVersionDir[] = FILE_PATH_LITERAL("v1");
30const FilePath::CharType kDriveCacheMetaDir[] = FILE_PATH_LITERAL("meta");
31const FilePath::CharType kDriveCachePinnedDir[] = FILE_PATH_LITERAL("pinned");
32const FilePath::CharType kDriveCacheOutgoingDir[] =
[email protected]32a7fc852012-06-08 17:25:5033 FILE_PATH_LITERAL("outgoing");
[email protected]fb371812012-08-22 16:05:2334const FilePath::CharType kDriveCachePersistentDir[] =
[email protected]32a7fc852012-06-08 17:25:5035 FILE_PATH_LITERAL("persistent");
[email protected]fb371812012-08-22 16:05:2336const FilePath::CharType kDriveCacheTmpDir[] = FILE_PATH_LITERAL("tmp");
37const FilePath::CharType kDriveCacheTmpDownloadsDir[] =
[email protected]32a7fc852012-06-08 17:25:5038 FILE_PATH_LITERAL("tmp/downloads");
[email protected]fb371812012-08-22 16:05:2339const FilePath::CharType kDriveCacheTmpDocumentsDir[] =
[email protected]32a7fc852012-06-08 17:25:5040 FILE_PATH_LITERAL("tmp/documents");
41
[email protected]a321b9632012-06-14 03:29:1742// Used to tweak GetAmountOfFreeDiskSpace() behavior for testing.
43FreeDiskSpaceGetterInterface* global_free_disk_getter_for_testing = NULL;
44
45// Gets the amount of free disk space. Use
46// |global_free_disk_getter_for_testing| if set.
47int64 GetAmountOfFreeDiskSpace() {
48 if (global_free_disk_getter_for_testing)
49 return global_free_disk_getter_for_testing->AmountOfFreeDiskSpace();
50
[email protected]774727282012-08-06 09:14:4451 FilePath path;
52 if (!PathService::Get(base::DIR_HOME, &path)) {
53 LOG(ERROR) << "Home directory not found";
54 return -1;
55 }
56 return base::SysInfo::AmountOfFreeDiskSpace(path);
[email protected]a321b9632012-06-14 03:29:1757}
58
59// Returns true if we have sufficient space to store the given number of
60// bytes, while keeping kMinFreeSpace bytes on the disk.
61bool HasEnoughSpaceFor(int64 num_bytes) {
62 int64 free_space = GetAmountOfFreeDiskSpace();
[email protected]d7754f52012-08-01 08:45:3363 // Subtract this as if this portion does not exist.
[email protected]a321b9632012-06-14 03:29:1764 free_space -= kMinFreeSpace;
65 return (free_space >= num_bytes);
66}
67
[email protected]79c3752d2012-07-17 12:10:0868// Create cache directory paths and set permissions.
69void InitCachePaths(const std::vector<FilePath>& cache_paths) {
[email protected]fb371812012-08-22 16:05:2370 if (cache_paths.size() < DriveCache::NUM_CACHE_TYPES) {
[email protected]79c3752d2012-07-17 12:10:0871 NOTREACHED();
72 LOG(ERROR) << "Size of cache_paths is invalid.";
73 return;
74 }
75
[email protected]fb371812012-08-22 16:05:2376 if (!DriveCache::CreateCacheDirectories(cache_paths))
[email protected]79c3752d2012-07-17 12:10:0877 return;
78
79 // Change permissions of cache persistent directory to u+rwx,og+x (711) in
80 // order to allow archive files in that directory to be mounted by cros-disks.
81 file_util::SetPosixFilePermissions(
[email protected]fb371812012-08-22 16:05:2382 cache_paths[DriveCache::CACHE_TYPE_PERSISTENT],
[email protected]79c3752d2012-07-17 12:10:0883 file_util::FILE_PERMISSION_USER_MASK |
84 file_util::FILE_PERMISSION_EXECUTE_BY_GROUP |
85 file_util::FILE_PERMISSION_EXECUTE_BY_OTHERS);
86}
87
[email protected]a321b9632012-06-14 03:29:1788// Remove all files under the given directory, non-recursively.
[email protected]d7754f52012-08-01 08:45:3389// Do not remove recursively as we don't want to touch <gcache>/tmp/downloads,
[email protected]a321b9632012-06-14 03:29:1790// which is used for user initiated downloads like "Save As"
91void RemoveAllFiles(const FilePath& directory) {
92 using file_util::FileEnumerator;
93
94 FileEnumerator enumerator(directory, false /* recursive */,
95 FileEnumerator::FILES);
96 for (FilePath file_path = enumerator.Next(); !file_path.empty();
97 file_path = enumerator.Next()) {
98 DVLOG(1) << "Removing " << file_path.value();
99 if (!file_util::Delete(file_path, false /* recursive */))
100 LOG(WARNING) << "Failed to delete " << file_path.value();
101 }
102}
103
[email protected]a321b9632012-06-14 03:29:17104// Modifies cache state of file on blocking pool, which involves:
105// - moving or copying file (per |file_operation_type|) from |source_path| to
106// |dest_path| if they're different
107// - deleting symlink if |symlink_path| is not empty
108// - creating symlink if |symlink_path| is not empty and |create_symlink| is
109// true.
[email protected]11f60db2012-08-23 16:28:15110DriveFileError ModifyCacheState(
[email protected]a321b9632012-06-14 03:29:17111 const FilePath& source_path,
112 const FilePath& dest_path,
[email protected]fb371812012-08-22 16:05:23113 DriveCache::FileOperationType file_operation_type,
[email protected]a321b9632012-06-14 03:29:17114 const FilePath& symlink_path,
115 bool create_symlink) {
116 // Move or copy |source_path| to |dest_path| if they are different.
117 if (source_path != dest_path) {
118 bool success = false;
[email protected]fb371812012-08-22 16:05:23119 if (file_operation_type == DriveCache::FILE_OPERATION_MOVE)
[email protected]a321b9632012-06-14 03:29:17120 success = file_util::Move(source_path, dest_path);
[email protected]fb371812012-08-22 16:05:23121 else if (file_operation_type == DriveCache::FILE_OPERATION_COPY)
[email protected]a321b9632012-06-14 03:29:17122 success = file_util::CopyFile(source_path, dest_path);
123 if (!success) {
[email protected]750af1d2012-07-13 14:32:43124 LOG(ERROR) << "Failed to "
[email protected]fb371812012-08-22 16:05:23125 << (file_operation_type == DriveCache::FILE_OPERATION_MOVE ?
[email protected]750af1d2012-07-13 14:32:43126 "move " : "copy ")
127 << source_path.value()
128 << " to " << dest_path.value();
[email protected]11f60db2012-08-23 16:28:15129 return DRIVE_FILE_ERROR_FAILED;
[email protected]a321b9632012-06-14 03:29:17130 } else {
[email protected]fb371812012-08-22 16:05:23131 DVLOG(1) << (file_operation_type == DriveCache::FILE_OPERATION_MOVE ?
[email protected]a321b9632012-06-14 03:29:17132 "Moved " : "Copied ")
133 << source_path.value()
134 << " to " << dest_path.value();
135 }
136 } else {
137 DVLOG(1) << "No need to move file: source = destination";
138 }
139
140 if (symlink_path.empty())
[email protected]11f60db2012-08-23 16:28:15141 return DRIVE_FILE_OK;
[email protected]a321b9632012-06-14 03:29:17142
143 // Remove symlink regardless of |create_symlink| because creating a link will
144 // not overwrite an existing one.
[email protected]a321b9632012-06-14 03:29:17145 // We try to save one file operation by not checking if link exists before
146 // deleting it, so unlink may return error if link doesn't exist, but it
147 // doesn't really matter to us.
[email protected]750af1d2012-07-13 14:32:43148 file_util::Delete(symlink_path, false);
[email protected]a321b9632012-06-14 03:29:17149
150 if (!create_symlink)
[email protected]11f60db2012-08-23 16:28:15151 return DRIVE_FILE_OK;
[email protected]a321b9632012-06-14 03:29:17152
153 // Create new symlink to |dest_path|.
154 if (!file_util::CreateSymbolicLink(dest_path, symlink_path)) {
[email protected]750af1d2012-07-13 14:32:43155 LOG(ERROR) << "Failed to create a symlink from " << symlink_path.value()
156 << " to " << dest_path.value();
[email protected]11f60db2012-08-23 16:28:15157 return DRIVE_FILE_ERROR_FAILED;
[email protected]a321b9632012-06-14 03:29:17158 }
159
[email protected]11f60db2012-08-23 16:28:15160 return DRIVE_FILE_OK;
[email protected]a321b9632012-06-14 03:29:17161}
162
163// Deletes all files that match |path_to_delete_pattern| except for
164// |path_to_keep| on blocking pool.
165// If |path_to_keep| is empty, all files in |path_to_delete_pattern| are
166// deleted.
167void DeleteFilesSelectively(const FilePath& path_to_delete_pattern,
168 const FilePath& path_to_keep) {
169 // Enumerate all files in directory of |path_to_delete_pattern| that match
170 // base name of |path_to_delete_pattern|.
171 // If a file is not |path_to_keep|, delete it.
172 bool success = true;
[email protected]84c3f162012-08-12 01:57:23173 file_util::FileEnumerator enumerator(path_to_delete_pattern.DirName(),
[email protected]a321b9632012-06-14 03:29:17174 false, // not recursive
[email protected]84c3f162012-08-12 01:57:23175 file_util::FileEnumerator::FILES |
176 file_util::FileEnumerator::SHOW_SYM_LINKS,
[email protected]a321b9632012-06-14 03:29:17177 path_to_delete_pattern.BaseName().value());
178 for (FilePath current = enumerator.Next(); !current.empty();
179 current = enumerator.Next()) {
180 // If |path_to_keep| is not empty and same as current, don't delete it.
181 if (!path_to_keep.empty() && current == path_to_keep)
182 continue;
183
[email protected]0b8d4cee2012-07-02 20:46:26184 success = file_util::Delete(current, false);
[email protected]a321b9632012-06-14 03:29:17185 if (!success)
186 DVLOG(1) << "Error deleting " << current.value();
187 else
188 DVLOG(1) << "Deleted " << current.value();
189 }
190}
191
[email protected]b83e5202012-06-27 07:50:24192// Appends |resource_id| ID to |to_fetch| if the file is pinned but not
193// fetched (not present locally), or to |to_upload| if the file is dirty
194// but not uploaded.
195void CollectBacklog(std::vector<std::string>* to_fetch,
196 std::vector<std::string>* to_upload,
197 const std::string& resource_id,
[email protected]28a64092012-08-21 10:01:12198 const DriveCacheEntry& cache_entry) {
[email protected]b83e5202012-06-27 07:50:24199 DCHECK(to_fetch);
200 DCHECK(to_upload);
[email protected]8764a392012-06-20 06:43:08201
[email protected]02821102012-07-12 20:19:17202 if (cache_entry.is_pinned() && !cache_entry.is_present())
[email protected]b83e5202012-06-27 07:50:24203 to_fetch->push_back(resource_id);
204
[email protected]02821102012-07-12 20:19:17205 if (cache_entry.is_dirty())
[email protected]b83e5202012-06-27 07:50:24206 to_upload->push_back(resource_id);
[email protected]8764a392012-06-20 06:43:08207}
208
[email protected]85b62192012-06-29 19:56:38209// Appends |resource_id| ID to |resource_ids| if the file is pinned and
210// present (cached locally).
211void CollectExistingPinnedFile(std::vector<std::string>* resource_ids,
212 const std::string& resource_id,
[email protected]28a64092012-08-21 10:01:12213 const DriveCacheEntry& cache_entry) {
[email protected]85b62192012-06-29 19:56:38214 DCHECK(resource_ids);
215
[email protected]02821102012-07-12 20:19:17216 if (cache_entry.is_pinned() && cache_entry.is_present())
[email protected]85b62192012-06-29 19:56:38217 resource_ids->push_back(resource_id);
218}
[email protected]8764a392012-06-20 06:43:08219
[email protected]cd236432012-07-27 18:03:30220// Appends |resource_id| ID to |resource_ids| unconditionally.
221void CollectAnyFile(std::vector<std::string>* resource_ids,
222 const std::string& resource_id,
[email protected]28a64092012-08-21 10:01:12223 const DriveCacheEntry& /* cache_entry */) {
[email protected]cd236432012-07-27 18:03:30224 DCHECK(resource_ids);
225
226 resource_ids->push_back(resource_id);
227}
228
[email protected]7986b8d2012-06-14 15:05:14229// Runs callback with pointers dereferenced.
[email protected]f861b392012-08-03 20:41:12230// Used to implement SetMountedStateOnUIThread and ClearAllOnUIThread.
231void RunChangeCacheStateCallback(const ChangeCacheStateCallback& callback,
[email protected]11f60db2012-08-23 16:28:15232 const DriveFileError* error,
[email protected]f861b392012-08-03 20:41:12233 const FilePath* cache_file_path) {
[email protected]7986b8d2012-06-14 15:05:14234 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
235 DCHECK(error);
236 DCHECK(cache_file_path);
237
238 if (!callback.is_null())
239 callback.Run(*error, *cache_file_path);
240}
241
[email protected]73f9c742012-06-15 07:37:13242// Runs callback with pointers dereferenced.
243// Used to implement *OnUIThread methods.
244void RunCacheOperationCallback(const CacheOperationCallback& callback,
[email protected]11f60db2012-08-23 16:28:15245 DriveFileError* error,
[email protected]73f9c742012-06-15 07:37:13246 const std::string& resource_id,
247 const std::string& md5) {
248 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
249 DCHECK(error);
250
251 if (!callback.is_null())
252 callback.Run(*error, resource_id, md5);
253}
254
[email protected]c960d222012-06-15 10:03:50255// Runs callback with pointers dereferenced.
256// Used to implement *OnUIThread methods.
257void RunGetFileFromCacheCallback(const GetFileFromCacheCallback& callback,
[email protected]11f60db2012-08-23 16:28:15258 DriveFileError* error,
[email protected]c960d222012-06-15 10:03:50259 const std::string& resource_id,
260 const std::string& md5,
261 FilePath* cache_file_path) {
262 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
263 DCHECK(error);
264 DCHECK(cache_file_path);
265
266 if (!callback.is_null())
267 callback.Run(*error, resource_id, md5, *cache_file_path);
268}
269
[email protected]8764a392012-06-20 06:43:08270// Runs callback with pointers dereferenced.
[email protected]4324fdc2012-06-29 05:32:48271// Used to implement GetResourceIdsOfBacklogOnUIThread().
[email protected]85b62192012-06-29 19:56:38272void RunGetResourceIdsOfBacklogCallback(
273 const GetResourceIdsOfBacklogCallback& callback,
274 std::vector<std::string>* to_fetch,
275 std::vector<std::string>* to_upload) {
[email protected]8764a392012-06-20 06:43:08276 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]b83e5202012-06-27 07:50:24277 DCHECK(to_fetch);
278 DCHECK(to_upload);
[email protected]8764a392012-06-20 06:43:08279
280 if (!callback.is_null())
[email protected]b83e5202012-06-27 07:50:24281 callback.Run(*to_fetch, *to_upload);
[email protected]8764a392012-06-20 06:43:08282}
283
[email protected]4324fdc2012-06-29 05:32:48284// Runs callback with pointers dereferenced.
[email protected]85b62192012-06-29 19:56:38285// Used to implement GetResourceIdsOfExistingPinnedFilesOnUIThread().
286void RunGetResourceIdsCallback(
287 const GetResourceIdsCallback& callback,
288 std::vector<std::string>* resource_ids) {
289 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
290 DCHECK(resource_ids);
291
292 if (!callback.is_null())
293 callback.Run(*resource_ids);
294}
295
296// Runs callback with pointers dereferenced.
[email protected]4324fdc2012-06-29 05:32:48297// Used to implement GetCacheEntryOnUIThread().
298void RunGetCacheEntryCallback(
[email protected]fae353a2012-07-11 23:30:27299 const GetCacheEntryCallback& callback,
[email protected]4324fdc2012-06-29 05:32:48300 bool* success,
[email protected]28a64092012-08-21 10:01:12301 DriveCacheEntry* cache_entry) {
[email protected]4324fdc2012-06-29 05:32:48302 DCHECK(success);
303 DCHECK(cache_entry);
304
305 if (!callback.is_null())
306 callback.Run(*success, *cache_entry);
307}
308
[email protected]a321b9632012-06-14 03:29:17309} // namespace
[email protected]32a7fc852012-06-08 17:25:50310
[email protected]fb371812012-08-22 16:05:23311DriveCache::DriveCache(const FilePath& cache_root_path,
[email protected]ddbf2052012-07-13 15:07:02312 base::SequencedTaskRunner* blocking_task_runner)
[email protected]01ba15f72012-06-09 00:41:05313 : cache_root_path_(cache_root_path),
[email protected]6b70c7b2012-06-14 03:10:43314 cache_paths_(GetCachePaths(cache_root_path_)),
[email protected]ddbf2052012-07-13 15:07:02315 blocking_task_runner_(blocking_task_runner),
[email protected]dc2e8f7b2012-08-30 20:22:44316 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
[email protected]73f9c742012-06-15 07:37:13317 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]3653146a2012-05-29 13:41:47318}
319
[email protected]fb371812012-08-22 16:05:23320DriveCache::~DriveCache() {
[email protected]73f9c742012-06-15 07:37:13321 AssertOnSequencedWorkerPool();
[email protected]3653146a2012-05-29 13:41:47322}
323
[email protected]fb371812012-08-22 16:05:23324FilePath DriveCache::GetCacheDirectoryPath(
[email protected]32a7fc852012-06-08 17:25:50325 CacheSubDirectoryType sub_dir_type) const {
326 DCHECK_LE(0, sub_dir_type);
327 DCHECK_GT(NUM_CACHE_TYPES, sub_dir_type);
328 return cache_paths_[sub_dir_type];
329}
330
[email protected]fb371812012-08-22 16:05:23331FilePath DriveCache::GetCacheFilePath(const std::string& resource_id,
[email protected]32a7fc852012-06-08 17:25:50332 const std::string& md5,
333 CacheSubDirectoryType sub_dir_type,
334 CachedFileOrigin file_origin) const {
335 DCHECK(sub_dir_type != CACHE_TYPE_META);
336
337 // Runs on any thread.
338 // Filename is formatted as resource_id.md5, i.e. resource_id is the base
339 // name and md5 is the extension.
340 std::string base_name = util::EscapeCacheFileName(resource_id);
341 if (file_origin == CACHED_FILE_LOCALLY_MODIFIED) {
342 DCHECK(sub_dir_type == CACHE_TYPE_PERSISTENT);
343 base_name += FilePath::kExtensionSeparator;
[email protected]b83e5202012-06-27 07:50:24344 base_name += util::kLocallyModifiedFileExtension;
[email protected]32a7fc852012-06-08 17:25:50345 } else if (!md5.empty()) {
346 base_name += FilePath::kExtensionSeparator;
347 base_name += util::EscapeCacheFileName(md5);
348 }
349 // For mounted archives the filename is formatted as resource_id.md5.mounted,
350 // i.e. resource_id.md5 is the base name and ".mounted" is the extension
351 if (file_origin == CACHED_FILE_MOUNTED) {
[email protected]a321b9632012-06-14 03:29:17352 DCHECK(sub_dir_type == CACHE_TYPE_PERSISTENT);
353 base_name += FilePath::kExtensionSeparator;
[email protected]ca5f6da2012-06-18 12:54:59354 base_name += util::kMountedArchiveFileExtension;
[email protected]32a7fc852012-06-08 17:25:50355 }
356 return GetCacheDirectoryPath(sub_dir_type).Append(base_name);
357}
358
[email protected]fb371812012-08-22 16:05:23359void DriveCache::AssertOnSequencedWorkerPool() {
[email protected]ddbf2052012-07-13 15:07:02360 DCHECK(!blocking_task_runner_ ||
361 blocking_task_runner_->RunsTasksOnCurrentThread());
[email protected]fcc92a52012-06-08 22:54:16362}
363
[email protected]fb371812012-08-22 16:05:23364bool DriveCache::IsUnderDriveCacheDirectory(const FilePath& path) const {
[email protected]01ba15f72012-06-09 00:41:05365 return cache_root_path_ == path || cache_root_path_.IsParent(path);
366}
367
[email protected]fb371812012-08-22 16:05:23368void DriveCache::AddObserver(Observer* observer) {
[email protected]73f9c742012-06-15 07:37:13369 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
370 observers_.AddObserver(observer);
371}
372
[email protected]fb371812012-08-22 16:05:23373void DriveCache::RemoveObserver(Observer* observer) {
[email protected]73f9c742012-06-15 07:37:13374 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
375 observers_.RemoveObserver(observer);
376}
377
[email protected]fb371812012-08-22 16:05:23378void DriveCache::GetCacheEntryOnUIThread(
[email protected]4324fdc2012-06-29 05:32:48379 const std::string& resource_id,
380 const std::string& md5,
381 const GetCacheEntryCallback& callback) {
382 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
383
384 bool* success = new bool(false);
[email protected]28a64092012-08-21 10:01:12385 DriveCacheEntry* cache_entry = new DriveCacheEntry;
[email protected]ddbf2052012-07-13 15:07:02386 blocking_task_runner_->PostTaskAndReply(
[email protected]4324fdc2012-06-29 05:32:48387 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23388 base::Bind(&DriveCache::GetCacheEntryHelper,
[email protected]4324fdc2012-06-29 05:32:48389 base::Unretained(this),
390 resource_id,
391 md5,
392 success,
393 cache_entry),
394 base::Bind(&RunGetCacheEntryCallback,
395 callback,
396 base::Owned(success),
397 base::Owned(cache_entry)));
398}
399
[email protected]fb371812012-08-22 16:05:23400void DriveCache::GetResourceIdsOfBacklogOnUIThread(
[email protected]85b62192012-06-29 19:56:38401 const GetResourceIdsOfBacklogCallback& callback) {
[email protected]8764a392012-06-20 06:43:08402 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
403
[email protected]b83e5202012-06-27 07:50:24404 std::vector<std::string>* to_fetch = new std::vector<std::string>;
405 std::vector<std::string>* to_upload = new std::vector<std::string>;
[email protected]ddbf2052012-07-13 15:07:02406 blocking_task_runner_->PostTaskAndReply(
[email protected]8764a392012-06-20 06:43:08407 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23408 base::Bind(&DriveCache::GetResourceIdsOfBacklog,
[email protected]8764a392012-06-20 06:43:08409 base::Unretained(this),
[email protected]b83e5202012-06-27 07:50:24410 to_fetch,
411 to_upload),
[email protected]85b62192012-06-29 19:56:38412 base::Bind(&RunGetResourceIdsOfBacklogCallback,
[email protected]8764a392012-06-20 06:43:08413 callback,
[email protected]b83e5202012-06-27 07:50:24414 base::Owned(to_fetch),
415 base::Owned(to_upload)));
[email protected]8764a392012-06-20 06:43:08416}
417
[email protected]fb371812012-08-22 16:05:23418void DriveCache::GetResourceIdsOfExistingPinnedFilesOnUIThread(
[email protected]85b62192012-06-29 19:56:38419 const GetResourceIdsCallback& callback) {
420 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
421
422 std::vector<std::string>* resource_ids = new std::vector<std::string>;
[email protected]ddbf2052012-07-13 15:07:02423 blocking_task_runner_->PostTaskAndReply(
[email protected]85b62192012-06-29 19:56:38424 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23425 base::Bind(&DriveCache::GetResourceIdsOfExistingPinnedFiles,
[email protected]85b62192012-06-29 19:56:38426 base::Unretained(this),
427 resource_ids),
428 base::Bind(&RunGetResourceIdsCallback,
429 callback,
430 base::Owned(resource_ids)));
431}
432
[email protected]fb371812012-08-22 16:05:23433void DriveCache::GetResourceIdsOfAllFilesOnUIThread(
[email protected]cd236432012-07-27 18:03:30434 const GetResourceIdsCallback& callback) {
435 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
436
437 std::vector<std::string>* resource_ids = new std::vector<std::string>;
438 blocking_task_runner_->PostTaskAndReply(
439 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23440 base::Bind(&DriveCache::GetResourceIdsOfAllFiles,
[email protected]cd236432012-07-27 18:03:30441 base::Unretained(this),
442 resource_ids),
443 base::Bind(&RunGetResourceIdsCallback,
444 callback,
445 base::Owned(resource_ids)));
446}
447
[email protected]fb371812012-08-22 16:05:23448void DriveCache::FreeDiskSpaceIfNeededFor(int64 num_bytes,
[email protected]a321b9632012-06-14 03:29:17449 bool* has_enough_space) {
450 AssertOnSequencedWorkerPool();
451
452 // Do nothing and return if we have enough space.
453 *has_enough_space = HasEnoughSpaceFor(num_bytes);
454 if (*has_enough_space)
455 return;
456
457 // Otherwise, try to free up the disk space.
458 DVLOG(1) << "Freeing up disk space for " << num_bytes;
459 // First remove temporary files from the cache map.
[email protected]ca5f6da2012-06-18 12:54:59460 metadata_->RemoveTemporaryFiles();
[email protected]a321b9632012-06-14 03:29:17461 // Then remove all files under "tmp" directory.
[email protected]fb371812012-08-22 16:05:23462 RemoveAllFiles(GetCacheDirectoryPath(DriveCache::CACHE_TYPE_TMP));
[email protected]a321b9632012-06-14 03:29:17463
464 // Check the disk space again.
465 *has_enough_space = HasEnoughSpaceFor(num_bytes);
466}
467
[email protected]fb371812012-08-22 16:05:23468void DriveCache::GetFileOnUIThread(const std::string& resource_id,
[email protected]c960d222012-06-15 10:03:50469 const std::string& md5,
470 const GetFileFromCacheCallback& callback) {
471 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]a321b9632012-06-14 03:29:17472
[email protected]11f60db2012-08-23 16:28:15473 DriveFileError* error = new DriveFileError(DRIVE_FILE_OK);
[email protected]c960d222012-06-15 10:03:50474 FilePath* cache_file_path = new FilePath;
[email protected]ddbf2052012-07-13 15:07:02475 blocking_task_runner_->PostTaskAndReply(
[email protected]c960d222012-06-15 10:03:50476 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23477 base::Bind(&DriveCache::GetFile,
[email protected]c960d222012-06-15 10:03:50478 base::Unretained(this),
479 resource_id,
480 md5,
481 error,
482 cache_file_path),
483 base::Bind(&RunGetFileFromCacheCallback,
484 callback,
485 base::Owned(error),
486 resource_id,
487 md5,
488 base::Owned(cache_file_path)));
[email protected]a321b9632012-06-14 03:29:17489}
490
[email protected]fb371812012-08-22 16:05:23491void DriveCache::StoreOnUIThread(const std::string& resource_id,
[email protected]73f9c742012-06-15 07:37:13492 const std::string& md5,
493 const FilePath& source_path,
494 FileOperationType file_operation_type,
495 const CacheOperationCallback& callback) {
496 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
497
[email protected]11f60db2012-08-23 16:28:15498 DriveFileError* error = new DriveFileError(DRIVE_FILE_OK);
[email protected]ddbf2052012-07-13 15:07:02499 blocking_task_runner_->PostTaskAndReply(
[email protected]73f9c742012-06-15 07:37:13500 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23501 base::Bind(&DriveCache::Store,
[email protected]73f9c742012-06-15 07:37:13502 base::Unretained(this),
503 resource_id,
504 md5,
505 source_path,
506 file_operation_type,
507 error),
508 base::Bind(&RunCacheOperationCallback,
509 callback,
510 base::Owned(error),
511 resource_id,
512 md5));
513}
514
[email protected]fb371812012-08-22 16:05:23515void DriveCache::PinOnUIThread(const std::string& resource_id,
[email protected]44c0584e2012-06-15 23:55:41516 const std::string& md5,
517 const CacheOperationCallback& callback) {
[email protected]73f9c742012-06-15 07:37:13518 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
519
[email protected]11f60db2012-08-23 16:28:15520 DriveFileError* error = new DriveFileError(DRIVE_FILE_OK);
[email protected]ddbf2052012-07-13 15:07:02521 blocking_task_runner_->PostTaskAndReply(
[email protected]73f9c742012-06-15 07:37:13522 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23523 base::Bind(&DriveCache::Pin,
[email protected]73f9c742012-06-15 07:37:13524 base::Unretained(this),
525 resource_id,
526 md5,
[email protected]fb371812012-08-22 16:05:23527 DriveCache::FILE_OPERATION_MOVE,
[email protected]73f9c742012-06-15 07:37:13528 error),
[email protected]fb371812012-08-22 16:05:23529 base::Bind(&DriveCache::OnPinned,
[email protected]e53ac8f2012-08-02 07:05:00530 weak_ptr_factory_.GetWeakPtr(),
[email protected]73f9c742012-06-15 07:37:13531 base::Owned(error),
532 resource_id,
533 md5,
534 callback));
535}
536
[email protected]fb371812012-08-22 16:05:23537void DriveCache::UnpinOnUIThread(const std::string& resource_id,
[email protected]73f9c742012-06-15 07:37:13538 const std::string& md5,
539 const CacheOperationCallback& callback) {
540 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]11f60db2012-08-23 16:28:15541 DriveFileError* error = new DriveFileError(DRIVE_FILE_OK);
[email protected]ddbf2052012-07-13 15:07:02542 blocking_task_runner_->PostTaskAndReply(
[email protected]73f9c742012-06-15 07:37:13543 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23544 base::Bind(&DriveCache::Unpin,
[email protected]73f9c742012-06-15 07:37:13545 base::Unretained(this),
546 resource_id,
547 md5,
[email protected]fb371812012-08-22 16:05:23548 DriveCache::FILE_OPERATION_MOVE,
[email protected]73f9c742012-06-15 07:37:13549 error),
[email protected]fb371812012-08-22 16:05:23550 base::Bind(&DriveCache::OnUnpinned,
[email protected]e53ac8f2012-08-02 07:05:00551 weak_ptr_factory_.GetWeakPtr(),
[email protected]73f9c742012-06-15 07:37:13552 base::Owned(error),
553 resource_id,
554 md5,
555 callback));
556}
557
[email protected]fb371812012-08-22 16:05:23558void DriveCache::SetMountedStateOnUIThread(
[email protected]73f9c742012-06-15 07:37:13559 const FilePath& file_path,
560 bool to_mount,
[email protected]f861b392012-08-03 20:41:12561 const ChangeCacheStateCallback& callback) {
[email protected]73f9c742012-06-15 07:37:13562 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
563
[email protected]11f60db2012-08-23 16:28:15564 DriveFileError* error = new DriveFileError(DRIVE_FILE_OK);
[email protected]73f9c742012-06-15 07:37:13565 FilePath* cache_file_path = new FilePath;
[email protected]ddbf2052012-07-13 15:07:02566 blocking_task_runner_->PostTaskAndReply(
[email protected]73f9c742012-06-15 07:37:13567 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23568 base::Bind(&DriveCache::SetMountedState,
[email protected]73f9c742012-06-15 07:37:13569 base::Unretained(this),
570 file_path,
571 to_mount,
572 error,
573 cache_file_path),
[email protected]f861b392012-08-03 20:41:12574 base::Bind(&RunChangeCacheStateCallback,
[email protected]73f9c742012-06-15 07:37:13575 callback,
576 base::Owned(error),
577 base::Owned(cache_file_path)));
578}
579
[email protected]fb371812012-08-22 16:05:23580void DriveCache::MarkDirtyOnUIThread(const std::string& resource_id,
[email protected]c960d222012-06-15 10:03:50581 const std::string& md5,
582 const GetFileFromCacheCallback& callback) {
583 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]73f9c742012-06-15 07:37:13584
[email protected]11f60db2012-08-23 16:28:15585 DriveFileError* error = new DriveFileError(DRIVE_FILE_OK);
[email protected]c960d222012-06-15 10:03:50586 FilePath* cache_file_path = new FilePath;
[email protected]ddbf2052012-07-13 15:07:02587 blocking_task_runner_->PostTaskAndReply(
[email protected]c960d222012-06-15 10:03:50588 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23589 base::Bind(&DriveCache::MarkDirty,
[email protected]c960d222012-06-15 10:03:50590 base::Unretained(this),
591 resource_id,
592 md5,
[email protected]fb371812012-08-22 16:05:23593 DriveCache::FILE_OPERATION_MOVE,
[email protected]c960d222012-06-15 10:03:50594 error,
595 cache_file_path),
596 base::Bind(&RunGetFileFromCacheCallback,
597 callback,
598 base::Owned(error),
599 resource_id,
600 md5,
601 base::Owned(cache_file_path)));
[email protected]73f9c742012-06-15 07:37:13602}
603
[email protected]fb371812012-08-22 16:05:23604void DriveCache::CommitDirtyOnUIThread(const std::string& resource_id,
[email protected]73f9c742012-06-15 07:37:13605 const std::string& md5,
606 const CacheOperationCallback& callback) {
607 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
608
[email protected]11f60db2012-08-23 16:28:15609 DriveFileError* error = new DriveFileError(DRIVE_FILE_OK);
[email protected]ddbf2052012-07-13 15:07:02610 blocking_task_runner_->PostTaskAndReply(
[email protected]73f9c742012-06-15 07:37:13611 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23612 base::Bind(&DriveCache::CommitDirty,
[email protected]73f9c742012-06-15 07:37:13613 base::Unretained(this),
614 resource_id,
615 md5,
[email protected]fb371812012-08-22 16:05:23616 DriveCache::FILE_OPERATION_MOVE,
[email protected]73f9c742012-06-15 07:37:13617 error),
[email protected]fb371812012-08-22 16:05:23618 base::Bind(&DriveCache::OnCommitDirty,
[email protected]e53ac8f2012-08-02 07:05:00619 weak_ptr_factory_.GetWeakPtr(),
[email protected]73f9c742012-06-15 07:37:13620 base::Owned(error),
621 resource_id,
[email protected]d7664c22012-06-18 19:35:49622 md5,
623 callback));
[email protected]73f9c742012-06-15 07:37:13624}
625
[email protected]fb371812012-08-22 16:05:23626void DriveCache::ClearDirtyOnUIThread(const std::string& resource_id,
[email protected]73f9c742012-06-15 07:37:13627 const std::string& md5,
628 const CacheOperationCallback& callback) {
629 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
630
[email protected]11f60db2012-08-23 16:28:15631 DriveFileError* error = new DriveFileError(DRIVE_FILE_OK);
[email protected]ddbf2052012-07-13 15:07:02632 blocking_task_runner_->PostTaskAndReply(
[email protected]73f9c742012-06-15 07:37:13633 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23634 base::Bind(&DriveCache::ClearDirty,
[email protected]73f9c742012-06-15 07:37:13635 base::Unretained(this),
636 resource_id,
637 md5,
[email protected]fb371812012-08-22 16:05:23638 DriveCache::FILE_OPERATION_MOVE,
[email protected]73f9c742012-06-15 07:37:13639 error),
640 base::Bind(&RunCacheOperationCallback,
641 callback,
642 base::Owned(error),
643 resource_id,
644 md5));
645}
646
[email protected]fb371812012-08-22 16:05:23647void DriveCache::RemoveOnUIThread(const std::string& resource_id,
[email protected]73f9c742012-06-15 07:37:13648 const CacheOperationCallback& callback) {
649 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
650
[email protected]11f60db2012-08-23 16:28:15651 DriveFileError* error = new DriveFileError(DRIVE_FILE_OK);
[email protected]ddbf2052012-07-13 15:07:02652 blocking_task_runner_->PostTaskAndReply(
[email protected]73f9c742012-06-15 07:37:13653 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23654 base::Bind(&DriveCache::Remove,
[email protected]73f9c742012-06-15 07:37:13655 base::Unretained(this),
656 resource_id,
657 error),
658 base::Bind(&RunCacheOperationCallback,
659 callback,
660 base::Owned(error),
661 resource_id,
662 "" /* md5 */));
663}
664
[email protected]fb371812012-08-22 16:05:23665void DriveCache::ClearAllOnUIThread(const ChangeCacheStateCallback& callback) {
[email protected]f861b392012-08-03 20:41:12666 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
667
[email protected]11f60db2012-08-23 16:28:15668 DriveFileError* error = new DriveFileError(DRIVE_FILE_OK);
[email protected]f861b392012-08-03 20:41:12669 blocking_task_runner_->PostTaskAndReply(
670 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23671 base::Bind(&DriveCache::ClearAll,
[email protected]f861b392012-08-03 20:41:12672 base::Unretained(this),
673 error),
674 base::Bind(&RunChangeCacheStateCallback,
675 callback,
676 base::Owned(error),
677 &cache_root_path_));
678}
679
[email protected]fb371812012-08-22 16:05:23680void DriveCache::RequestInitializeOnUIThread() {
[email protected]73f9c742012-06-15 07:37:13681 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
682
[email protected]ddbf2052012-07-13 15:07:02683 blocking_task_runner_->PostTask(
[email protected]73f9c742012-06-15 07:37:13684 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23685 base::Bind(&DriveCache::Initialize, base::Unretained(this)));
[email protected]73f9c742012-06-15 07:37:13686}
687
[email protected]fb371812012-08-22 16:05:23688void DriveCache::RequestInitializeOnUIThreadForTesting() {
[email protected]d310bfc2012-08-10 09:41:28689 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
690
691 blocking_task_runner_->PostTask(
692 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23693 base::Bind(&DriveCache::InitializeForTesting, base::Unretained(this)));
[email protected]d310bfc2012-08-10 09:41:28694}
695
[email protected]fb371812012-08-22 16:05:23696void DriveCache::ForceRescanOnUIThreadForTesting() {
[email protected]79c3752d2012-07-17 12:10:08697 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
698
699 blocking_task_runner_->PostTask(
700 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23701 base::Bind(&DriveCache::ForceRescanForTesting, base::Unretained(this)));
[email protected]79c3752d2012-07-17 12:10:08702}
703
[email protected]fb371812012-08-22 16:05:23704bool DriveCache::GetCacheEntry(const std::string& resource_id,
[email protected]b22f87f2012-07-12 10:53:17705 const std::string& md5,
[email protected]28a64092012-08-21 10:01:12706 DriveCacheEntry* entry) {
[email protected]b22f87f2012-07-12 10:53:17707 DCHECK(entry);
[email protected]73f9c742012-06-15 07:37:13708 AssertOnSequencedWorkerPool();
[email protected]b22f87f2012-07-12 10:53:17709 return metadata_->GetCacheEntry(resource_id, md5, entry);
[email protected]73f9c742012-06-15 07:37:13710}
711
712// static
[email protected]fb371812012-08-22 16:05:23713DriveCache* DriveCache::CreateDriveCacheOnUIThread(
[email protected]73f9c742012-06-15 07:37:13714 const FilePath& cache_root_path,
[email protected]ddbf2052012-07-13 15:07:02715 base::SequencedTaskRunner* blocking_task_runner) {
[email protected]73f9c742012-06-15 07:37:13716 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]fb371812012-08-22 16:05:23717 return new DriveCache(cache_root_path, blocking_task_runner);
[email protected]73f9c742012-06-15 07:37:13718}
719
[email protected]fb371812012-08-22 16:05:23720void DriveCache::DestroyOnUIThread() {
[email protected]73f9c742012-06-15 07:37:13721 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
722
723 // Invalidate the weak pointer.
[email protected]e53ac8f2012-08-02 07:05:00724 weak_ptr_factory_.InvalidateWeakPtrs();
[email protected]73f9c742012-06-15 07:37:13725
726 // Destroy myself on the blocking pool.
[email protected]ddbf2052012-07-13 15:07:02727 blocking_task_runner_->PostTask(
[email protected]73f9c742012-06-15 07:37:13728 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23729 base::Bind(&DriveCache::Destroy,
[email protected]73f9c742012-06-15 07:37:13730 base::Unretained(this)));
731}
732
[email protected]fb371812012-08-22 16:05:23733void DriveCache::Initialize() {
[email protected]ca5f6da2012-06-18 12:54:59734 AssertOnSequencedWorkerPool();
735
[email protected]79c3752d2012-07-17 12:10:08736 InitCachePaths(cache_paths_);
[email protected]fb371812012-08-22 16:05:23737 metadata_ = DriveCacheMetadata::CreateDriveCacheMetadata(
[email protected]f9e5cc02012-07-13 20:08:56738 blocking_task_runner_).Pass();
739 metadata_->Initialize(cache_paths_);
[email protected]ca5f6da2012-06-18 12:54:59740}
741
[email protected]fb371812012-08-22 16:05:23742void DriveCache::InitializeForTesting() {
[email protected]d310bfc2012-08-10 09:41:28743 AssertOnSequencedWorkerPool();
744
745 InitCachePaths(cache_paths_);
[email protected]fb371812012-08-22 16:05:23746 metadata_ = DriveCacheMetadata::CreateDriveCacheMetadataForTesting(
[email protected]d310bfc2012-08-10 09:41:28747 blocking_task_runner_).Pass();
748 metadata_->Initialize(cache_paths_);
749}
750
[email protected]fb371812012-08-22 16:05:23751void DriveCache::Destroy() {
[email protected]73f9c742012-06-15 07:37:13752 AssertOnSequencedWorkerPool();
753 delete this;
754}
755
[email protected]fb371812012-08-22 16:05:23756void DriveCache::ForceRescanForTesting() {
[email protected]79c3752d2012-07-17 12:10:08757 AssertOnSequencedWorkerPool();
758 metadata_->ForceRescanForTesting(cache_paths_);
759}
760
[email protected]fb371812012-08-22 16:05:23761void DriveCache::GetResourceIdsOfBacklog(
[email protected]b83e5202012-06-27 07:50:24762 std::vector<std::string>* to_fetch,
763 std::vector<std::string>* to_upload) {
[email protected]8764a392012-06-20 06:43:08764 AssertOnSequencedWorkerPool();
[email protected]b83e5202012-06-27 07:50:24765 DCHECK(to_fetch);
766 DCHECK(to_upload);
[email protected]8764a392012-06-20 06:43:08767
[email protected]b83e5202012-06-27 07:50:24768 metadata_->Iterate(base::Bind(&CollectBacklog, to_fetch, to_upload));
[email protected]8764a392012-06-20 06:43:08769}
770
[email protected]fb371812012-08-22 16:05:23771void DriveCache::GetResourceIdsOfExistingPinnedFiles(
[email protected]85b62192012-06-29 19:56:38772 std::vector<std::string>* resource_ids) {
773 AssertOnSequencedWorkerPool();
774 DCHECK(resource_ids);
775
776 metadata_->Iterate(base::Bind(&CollectExistingPinnedFile, resource_ids));
777}
778
[email protected]fb371812012-08-22 16:05:23779void DriveCache::GetResourceIdsOfAllFiles(
[email protected]cd236432012-07-27 18:03:30780 std::vector<std::string>* resource_ids) {
781 AssertOnSequencedWorkerPool();
782 DCHECK(resource_ids);
783
784 metadata_->Iterate(base::Bind(&CollectAnyFile, resource_ids));
785}
786
[email protected]fb371812012-08-22 16:05:23787void DriveCache::GetFile(const std::string& resource_id,
[email protected]c960d222012-06-15 10:03:50788 const std::string& md5,
[email protected]11f60db2012-08-23 16:28:15789 DriveFileError* error,
[email protected]c960d222012-06-15 10:03:50790 FilePath* cache_file_path) {
791 AssertOnSequencedWorkerPool();
792 DCHECK(error);
793 DCHECK(cache_file_path);
794
[email protected]28a64092012-08-21 10:01:12795 DriveCacheEntry cache_entry;
[email protected]b22f87f2012-07-12 10:53:17796 if (GetCacheEntry(resource_id, md5, &cache_entry) &&
[email protected]02821102012-07-12 20:19:17797 cache_entry.is_present()) {
[email protected]c960d222012-06-15 10:03:50798 CachedFileOrigin file_origin;
[email protected]02821102012-07-12 20:19:17799 if (cache_entry.is_mounted()) {
[email protected]c960d222012-06-15 10:03:50800 file_origin = CACHED_FILE_MOUNTED;
[email protected]02821102012-07-12 20:19:17801 } else if (cache_entry.is_dirty()) {
[email protected]c960d222012-06-15 10:03:50802 file_origin = CACHED_FILE_LOCALLY_MODIFIED;
803 } else {
804 file_origin = CACHED_FILE_FROM_SERVER;
805 }
806 *cache_file_path = GetCacheFilePath(
807 resource_id,
808 md5,
[email protected]b22f87f2012-07-12 10:53:17809 GetSubDirectoryType(cache_entry),
[email protected]c960d222012-06-15 10:03:50810 file_origin);
[email protected]11f60db2012-08-23 16:28:15811 *error = DRIVE_FILE_OK;
[email protected]c960d222012-06-15 10:03:50812 } else {
[email protected]11f60db2012-08-23 16:28:15813 *error = DRIVE_FILE_ERROR_NOT_FOUND;
[email protected]c960d222012-06-15 10:03:50814 }
815}
816
[email protected]fb371812012-08-22 16:05:23817void DriveCache::Store(const std::string& resource_id,
[email protected]a321b9632012-06-14 03:29:17818 const std::string& md5,
819 const FilePath& source_path,
820 FileOperationType file_operation_type,
[email protected]11f60db2012-08-23 16:28:15821 DriveFileError* error) {
[email protected]a321b9632012-06-14 03:29:17822 AssertOnSequencedWorkerPool();
823 DCHECK(error);
824
[email protected]f0c67002012-08-15 04:10:38825 if (file_operation_type == FILE_OPERATION_COPY) {
826 int64 file_size;
827 if (!file_util::GetFileSize(source_path, &file_size)) {
828 LOG(WARNING) << "Couldn't get file size for: " << source_path.value();
[email protected]11f60db2012-08-23 16:28:15829 *error = DRIVE_FILE_ERROR_FAILED;
[email protected]f0c67002012-08-15 04:10:38830 return;
831 }
832
833 bool enough_space = false;
834 FreeDiskSpaceIfNeededFor(file_size, &enough_space);
835 if (!enough_space) {
[email protected]11f60db2012-08-23 16:28:15836 *error = DRIVE_FILE_ERROR_NO_SPACE;
[email protected]f0c67002012-08-15 04:10:38837 return;
838 }
839 }
840
[email protected]a321b9632012-06-14 03:29:17841 FilePath dest_path;
842 FilePath symlink_path;
[email protected]a321b9632012-06-14 03:29:17843 CacheSubDirectoryType sub_dir_type = CACHE_TYPE_TMP;
844
[email protected]a321b9632012-06-14 03:29:17845 // If file was previously pinned, store it in persistent dir and create
846 // symlink in pinned dir.
[email protected]28a64092012-08-21 10:01:12847 DriveCacheEntry cache_entry;
[email protected]b22f87f2012-07-12 10:53:17848 if (GetCacheEntry(resource_id, md5, &cache_entry)) { // File exists in cache.
[email protected]a321b9632012-06-14 03:29:17849 // If file is dirty or mounted, return error.
[email protected]02821102012-07-12 20:19:17850 if (cache_entry.is_dirty() || cache_entry.is_mounted()) {
[email protected]a321b9632012-06-14 03:29:17851 LOG(WARNING) << "Can't store a file to replace a "
[email protected]02821102012-07-12 20:19:17852 << (cache_entry.is_dirty() ? "dirty" : "mounted")
[email protected]a321b9632012-06-14 03:29:17853 << " file: res_id=" << resource_id
854 << ", md5=" << md5;
[email protected]11f60db2012-08-23 16:28:15855 *error = DRIVE_FILE_ERROR_IN_USE;
[email protected]a321b9632012-06-14 03:29:17856 return;
857 }
858
[email protected]a321b9632012-06-14 03:29:17859 // If file is pinned, determines destination path.
[email protected]02821102012-07-12 20:19:17860 if (cache_entry.is_pinned()) {
[email protected]a321b9632012-06-14 03:29:17861 sub_dir_type = CACHE_TYPE_PERSISTENT;
862 dest_path = GetCacheFilePath(resource_id, md5, sub_dir_type,
863 CACHED_FILE_FROM_SERVER);
864 symlink_path = GetCacheFilePath(
865 resource_id, std::string(), CACHE_TYPE_PINNED,
866 CACHED_FILE_FROM_SERVER);
867 }
868 }
869
870 // File wasn't pinned or doesn't exist in cache, store in tmp dir.
871 if (dest_path.empty()) {
872 DCHECK_EQ(CACHE_TYPE_TMP, sub_dir_type);
873 dest_path = GetCacheFilePath(resource_id, md5, sub_dir_type,
874 CACHED_FILE_FROM_SERVER);
875 }
876
877 *error = ModifyCacheState(
878 source_path,
879 dest_path,
880 file_operation_type,
881 symlink_path,
882 !symlink_path.empty()); // create symlink
883
884 // Determine search pattern for stale filenames corrresponding to resource_id,
885 // either "<resource_id>*" or "<resource_id>.*".
886 FilePath stale_filenames_pattern;
887 if (md5.empty()) {
888 // No md5 means no extension, append '*' after base name, i.e.
889 // "<resource_id>*".
890 // Cannot call |dest_path|.ReplaceExtension when there's no md5 extension:
891 // if base name of |dest_path| (i.e. escaped resource_id) contains the
892 // extension separator '.', ReplaceExtension will remove it and everything
893 // after it. The result will be nothing like the escaped resource_id.
[email protected]ca5f6da2012-06-18 12:54:59894 stale_filenames_pattern = FilePath(dest_path.value() + util::kWildCard);
[email protected]a321b9632012-06-14 03:29:17895 } else {
896 // Replace md5 extension with '*' i.e. "<resource_id>.*".
897 // Note that ReplaceExtension automatically prefixes the extension with the
898 // extension separator '.'.
[email protected]ca5f6da2012-06-18 12:54:59899 stale_filenames_pattern = dest_path.ReplaceExtension(util::kWildCard);
[email protected]a321b9632012-06-14 03:29:17900 }
901
902 // Delete files that match |stale_filenames_pattern| except for |dest_path|.
903 DeleteFilesSelectively(stale_filenames_pattern, dest_path);
904
[email protected]11f60db2012-08-23 16:28:15905 if (*error == DRIVE_FILE_OK) {
[email protected]a321b9632012-06-14 03:29:17906 // Now that file operations have completed, update cache map.
[email protected]b22f87f2012-07-12 10:53:17907 cache_entry.set_md5(md5);
[email protected]02821102012-07-12 20:19:17908 cache_entry.set_is_present(true);
909 cache_entry.set_is_persistent(sub_dir_type == CACHE_TYPE_PERSISTENT);
[email protected]b22f87f2012-07-12 10:53:17910 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry);
[email protected]a321b9632012-06-14 03:29:17911 }
912}
913
[email protected]fb371812012-08-22 16:05:23914void DriveCache::Pin(const std::string& resource_id,
[email protected]a321b9632012-06-14 03:29:17915 const std::string& md5,
916 FileOperationType file_operation_type,
[email protected]11f60db2012-08-23 16:28:15917 DriveFileError* error) {
[email protected]a321b9632012-06-14 03:29:17918 AssertOnSequencedWorkerPool();
919 DCHECK(error);
920
921 FilePath source_path;
922 FilePath dest_path;
923 FilePath symlink_path;
924 bool create_symlink = true;
[email protected]a321b9632012-06-14 03:29:17925 CacheSubDirectoryType sub_dir_type = CACHE_TYPE_PERSISTENT;
926
[email protected]28a64092012-08-21 10:01:12927 DriveCacheEntry cache_entry;
[email protected]b22f87f2012-07-12 10:53:17928 if (!GetCacheEntry(resource_id, md5, &cache_entry)) {
929 // Entry does not exist in cache.
[email protected]a321b9632012-06-14 03:29:17930 // Set both |dest_path| and |source_path| to /dev/null, so that:
931 // 1) ModifyCacheState won't move files when |source_path| and |dest_path|
932 // are the same.
933 // 2) symlinks to /dev/null will be picked up by GDataSyncClient to download
934 // pinned files that don't exist in cache.
[email protected]30d9dda2012-06-30 05:56:28935 dest_path = FilePath::FromUTF8Unsafe(util::kSymLinkToDevNull);
[email protected]a321b9632012-06-14 03:29:17936 source_path = dest_path;
937
[email protected]2a6fe6e2012-07-10 06:01:04938 // Set sub_dir_type to TMP. The file will be first downloaded in 'tmp',
939 // then moved to 'persistent'.
940 sub_dir_type = CACHE_TYPE_TMP;
[email protected]109eb5c2012-07-12 03:20:05941 } else { // File exists in cache, determines destination path.
[email protected]a321b9632012-06-14 03:29:17942 // Determine source and destination paths.
943
944 // If file is dirty or mounted, don't move it, so determine |dest_path| and
945 // set |source_path| the same, because ModifyCacheState only moves files if
946 // source and destination are different.
[email protected]02821102012-07-12 20:19:17947 if (cache_entry.is_dirty() || cache_entry.is_mounted()) {
948 DCHECK(cache_entry.is_persistent());
[email protected]a321b9632012-06-14 03:29:17949 dest_path = GetCacheFilePath(resource_id,
950 md5,
[email protected]b22f87f2012-07-12 10:53:17951 GetSubDirectoryType(cache_entry),
[email protected]a321b9632012-06-14 03:29:17952 CACHED_FILE_LOCALLY_MODIFIED);
953 source_path = dest_path;
954 } else {
955 // Gets the current path of the file in cache.
956 source_path = GetCacheFilePath(resource_id,
957 md5,
[email protected]b22f87f2012-07-12 10:53:17958 GetSubDirectoryType(cache_entry),
[email protected]a321b9632012-06-14 03:29:17959 CACHED_FILE_FROM_SERVER);
960
961 // If file was pinned before but actual file blob doesn't exist in cache:
962 // - don't need to move the file, so set |dest_path| to |source_path|,
963 // because ModifyCacheState only moves files if source and destination
964 // are different
965 // - don't create symlink since it already exists.
[email protected]02821102012-07-12 20:19:17966 if (!cache_entry.is_present()) {
[email protected]a321b9632012-06-14 03:29:17967 dest_path = source_path;
968 create_symlink = false;
969 } else { // File exists, move it to persistent dir.
970 dest_path = GetCacheFilePath(resource_id,
971 md5,
972 CACHE_TYPE_PERSISTENT,
973 CACHED_FILE_FROM_SERVER);
974 }
975 }
976 }
977
978 // Create symlink in pinned dir.
979 if (create_symlink) {
980 symlink_path = GetCacheFilePath(resource_id,
981 std::string(),
982 CACHE_TYPE_PINNED,
983 CACHED_FILE_FROM_SERVER);
984 }
985
986 *error = ModifyCacheState(source_path,
987 dest_path,
988 file_operation_type,
989 symlink_path,
990 create_symlink);
991
[email protected]11f60db2012-08-23 16:28:15992 if (*error == DRIVE_FILE_OK) {
[email protected]a321b9632012-06-14 03:29:17993 // Now that file operations have completed, update cache map.
[email protected]b22f87f2012-07-12 10:53:17994 cache_entry.set_md5(md5);
[email protected]02821102012-07-12 20:19:17995 cache_entry.set_is_pinned(true);
996 cache_entry.set_is_persistent(sub_dir_type == CACHE_TYPE_PERSISTENT);
[email protected]b22f87f2012-07-12 10:53:17997 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry);
[email protected]a321b9632012-06-14 03:29:17998 }
999}
1000
[email protected]fb371812012-08-22 16:05:231001void DriveCache::Unpin(const std::string& resource_id,
[email protected]a321b9632012-06-14 03:29:171002 const std::string& md5,
1003 FileOperationType file_operation_type,
[email protected]11f60db2012-08-23 16:28:151004 DriveFileError* error) {
[email protected]a321b9632012-06-14 03:29:171005 AssertOnSequencedWorkerPool();
1006 DCHECK(error);
1007
[email protected]a321b9632012-06-14 03:29:171008 // Unpinning a file means its entry must exist in cache.
[email protected]28a64092012-08-21 10:01:121009 DriveCacheEntry cache_entry;
[email protected]b22f87f2012-07-12 10:53:171010 if (!GetCacheEntry(resource_id, md5, &cache_entry)) {
[email protected]a321b9632012-06-14 03:29:171011 LOG(WARNING) << "Can't unpin a file that wasn't pinned or cached: res_id="
1012 << resource_id
1013 << ", md5=" << md5;
[email protected]11f60db2012-08-23 16:28:151014 *error = DRIVE_FILE_ERROR_NOT_FOUND;
[email protected]a321b9632012-06-14 03:29:171015 return;
1016 }
1017
1018 // Entry exists in cache, determines source and destination paths.
1019
1020 FilePath source_path;
1021 FilePath dest_path;
1022 CacheSubDirectoryType sub_dir_type = CACHE_TYPE_TMP;
1023
1024 // If file is dirty or mounted, don't move it, so determine |dest_path| and
1025 // set |source_path| the same, because ModifyCacheState moves files if source
1026 // and destination are different.
[email protected]02821102012-07-12 20:19:171027 if (cache_entry.is_dirty() || cache_entry.is_mounted()) {
[email protected]a321b9632012-06-14 03:29:171028 sub_dir_type = CACHE_TYPE_PERSISTENT;
[email protected]02821102012-07-12 20:19:171029 DCHECK(cache_entry.is_persistent());
[email protected]a321b9632012-06-14 03:29:171030 dest_path = GetCacheFilePath(resource_id,
1031 md5,
[email protected]b22f87f2012-07-12 10:53:171032 GetSubDirectoryType(cache_entry),
[email protected]a321b9632012-06-14 03:29:171033 CACHED_FILE_LOCALLY_MODIFIED);
1034 source_path = dest_path;
1035 } else {
1036 // Gets the current path of the file in cache.
1037 source_path = GetCacheFilePath(resource_id,
1038 md5,
[email protected]b22f87f2012-07-12 10:53:171039 GetSubDirectoryType(cache_entry),
[email protected]a321b9632012-06-14 03:29:171040 CACHED_FILE_FROM_SERVER);
1041
1042 // If file was pinned but actual file blob still doesn't exist in cache,
1043 // don't need to move the file, so set |dest_path| to |source_path|, because
1044 // ModifyCacheState only moves files if source and destination are
1045 // different.
[email protected]02821102012-07-12 20:19:171046 if (!cache_entry.is_present()) {
[email protected]a321b9632012-06-14 03:29:171047 dest_path = source_path;
1048 } else { // File exists, move it to tmp dir.
1049 dest_path = GetCacheFilePath(resource_id, md5,
1050 CACHE_TYPE_TMP,
1051 CACHED_FILE_FROM_SERVER);
1052 }
1053 }
1054
1055 // If file was pinned, get absolute path of symlink in pinned dir so as to
1056 // remove it.
1057 FilePath symlink_path;
[email protected]02821102012-07-12 20:19:171058 if (cache_entry.is_pinned()) {
[email protected]a321b9632012-06-14 03:29:171059 symlink_path = GetCacheFilePath(resource_id,
1060 std::string(),
1061 CACHE_TYPE_PINNED,
1062 CACHED_FILE_FROM_SERVER);
1063 }
1064
1065 *error = ModifyCacheState(
1066 source_path,
1067 dest_path,
1068 file_operation_type,
1069 symlink_path, // This will be deleted if it exists.
1070 false /* don't create symlink*/);
1071
[email protected]11f60db2012-08-23 16:28:151072 if (*error == DRIVE_FILE_OK) {
[email protected]a321b9632012-06-14 03:29:171073 // Now that file operations have completed, update cache map.
[email protected]02821102012-07-12 20:19:171074 if (cache_entry.is_present()) {
[email protected]48477fe2012-07-12 17:45:081075 cache_entry.set_md5(md5);
[email protected]02821102012-07-12 20:19:171076 cache_entry.set_is_pinned(false);
1077 cache_entry.set_is_persistent(sub_dir_type == CACHE_TYPE_PERSISTENT);
[email protected]48477fe2012-07-12 17:45:081078 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry);
[email protected]3423871a2012-07-12 00:41:271079 } else {
1080 // Remove the existing entry if we are unpinning a non-present file.
1081 metadata_->RemoveCacheEntry(resource_id);
1082 }
[email protected]a321b9632012-06-14 03:29:171083 }
1084}
1085
[email protected]fb371812012-08-22 16:05:231086void DriveCache::SetMountedState(const FilePath& file_path,
[email protected]a321b9632012-06-14 03:29:171087 bool to_mount,
[email protected]11f60db2012-08-23 16:28:151088 DriveFileError *error,
[email protected]a321b9632012-06-14 03:29:171089 FilePath* cache_file_path) {
1090 AssertOnSequencedWorkerPool();
1091 DCHECK(error);
1092 DCHECK(cache_file_path);
1093
1094 // Parse file path to obtain resource_id, md5 and extra_extension.
1095 std::string resource_id;
1096 std::string md5;
1097 std::string extra_extension;
1098 util::ParseCacheFilePath(file_path, &resource_id, &md5, &extra_extension);
1099 // The extra_extension shall be ".mounted" iff we're unmounting.
[email protected]ca5f6da2012-06-18 12:54:591100 DCHECK(!to_mount == (extra_extension == util::kMountedArchiveFileExtension));
[email protected]a321b9632012-06-14 03:29:171101
1102 // Get cache entry associated with the resource_id and md5
[email protected]28a64092012-08-21 10:01:121103 DriveCacheEntry cache_entry;
[email protected]b22f87f2012-07-12 10:53:171104 if (!GetCacheEntry(resource_id, md5, &cache_entry)) {
[email protected]11f60db2012-08-23 16:28:151105 *error = DRIVE_FILE_ERROR_NOT_FOUND;
[email protected]a321b9632012-06-14 03:29:171106 return;
1107 }
[email protected]02821102012-07-12 20:19:171108 if (to_mount == cache_entry.is_mounted()) {
[email protected]11f60db2012-08-23 16:28:151109 *error = DRIVE_FILE_ERROR_INVALID_OPERATION;
[email protected]a321b9632012-06-14 03:29:171110 return;
1111 }
1112
1113 // Get the subdir type and path for the unmounted state.
1114 CacheSubDirectoryType unmounted_subdir =
[email protected]02821102012-07-12 20:19:171115 cache_entry.is_pinned() ? CACHE_TYPE_PERSISTENT : CACHE_TYPE_TMP;
[email protected]a321b9632012-06-14 03:29:171116 FilePath unmounted_path = GetCacheFilePath(
1117 resource_id, md5, unmounted_subdir, CACHED_FILE_FROM_SERVER);
1118
1119 // Get the subdir type and path for the mounted state.
1120 CacheSubDirectoryType mounted_subdir = CACHE_TYPE_PERSISTENT;
1121 FilePath mounted_path = GetCacheFilePath(
1122 resource_id, md5, mounted_subdir, CACHED_FILE_MOUNTED);
1123
1124 // Determine the source and destination paths for moving the cache blob.
1125 FilePath source_path;
1126 CacheSubDirectoryType dest_subdir;
[email protected]a321b9632012-06-14 03:29:171127 if (to_mount) {
1128 source_path = unmounted_path;
1129 *cache_file_path = mounted_path;
1130 dest_subdir = mounted_subdir;
[email protected]02821102012-07-12 20:19:171131 cache_entry.set_is_mounted(true);
[email protected]a321b9632012-06-14 03:29:171132 } else {
1133 source_path = mounted_path;
1134 *cache_file_path = unmounted_path;
1135 dest_subdir = unmounted_subdir;
[email protected]02821102012-07-12 20:19:171136 cache_entry.set_is_mounted(false);
[email protected]a321b9632012-06-14 03:29:171137 }
1138
1139 // Move cache blob from source path to destination path.
1140 *error = ModifyCacheState(source_path, *cache_file_path,
1141 FILE_OPERATION_MOVE, FilePath(), false);
[email protected]11f60db2012-08-23 16:28:151142 if (*error == DRIVE_FILE_OK) {
[email protected]a321b9632012-06-14 03:29:171143 // Now that cache operation is complete, update cache map
[email protected]48477fe2012-07-12 17:45:081144 cache_entry.set_md5(md5);
[email protected]02821102012-07-12 20:19:171145 cache_entry.set_is_persistent(dest_subdir == CACHE_TYPE_PERSISTENT);
[email protected]48477fe2012-07-12 17:45:081146 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry);
[email protected]a321b9632012-06-14 03:29:171147 }
1148}
1149
[email protected]fb371812012-08-22 16:05:231150void DriveCache::MarkDirty(const std::string& resource_id,
[email protected]c960d222012-06-15 10:03:501151 const std::string& md5,
1152 FileOperationType file_operation_type,
[email protected]11f60db2012-08-23 16:28:151153 DriveFileError* error,
[email protected]c960d222012-06-15 10:03:501154 FilePath* cache_file_path) {
1155 AssertOnSequencedWorkerPool();
1156 DCHECK(error);
1157 DCHECK(cache_file_path);
1158
1159 // If file has already been marked dirty in previous instance of chrome, we
1160 // would have lost the md5 info during cache initialization, because the file
1161 // would have been renamed to .local extension.
1162 // So, search for entry in cache without comparing md5.
[email protected]c960d222012-06-15 10:03:501163
1164 // Marking a file dirty means its entry and actual file blob must exist in
1165 // cache.
[email protected]28a64092012-08-21 10:01:121166 DriveCacheEntry cache_entry;
[email protected]b22f87f2012-07-12 10:53:171167 if (!GetCacheEntry(resource_id, std::string(), &cache_entry) ||
[email protected]02821102012-07-12 20:19:171168 !cache_entry.is_present()) {
[email protected]c960d222012-06-15 10:03:501169 LOG(WARNING) << "Can't mark dirty a file that wasn't cached: res_id="
1170 << resource_id
1171 << ", md5=" << md5;
[email protected]11f60db2012-08-23 16:28:151172 *error = DRIVE_FILE_ERROR_NOT_FOUND;
[email protected]c960d222012-06-15 10:03:501173 return;
1174 }
1175
1176 // If a file is already dirty (i.e. MarkDirtyInCache was called before),
1177 // delete outgoing symlink if it exists.
1178 // TODO(benchan): We should only delete outgoing symlink if file is currently
1179 // not being uploaded. However, for now, cache doesn't know if uploading of a
1180 // file is in progress. Per zel, the upload process should be canceled before
1181 // MarkDirtyInCache is called again.
[email protected]02821102012-07-12 20:19:171182 if (cache_entry.is_dirty()) {
[email protected]c960d222012-06-15 10:03:501183 // The file must be in persistent dir.
[email protected]02821102012-07-12 20:19:171184 DCHECK(cache_entry.is_persistent());
[email protected]c960d222012-06-15 10:03:501185
1186 // Determine symlink path in outgoing dir, so as to remove it.
1187 FilePath symlink_path = GetCacheFilePath(
1188 resource_id,
1189 std::string(),
1190 CACHE_TYPE_OUTGOING,
1191 CACHED_FILE_FROM_SERVER);
1192
1193 // We're not moving files here, so simply use empty FilePath for both
1194 // |source_path| and |dest_path| because ModifyCacheState only move files
1195 // if source and destination are different.
1196 *error = ModifyCacheState(
1197 FilePath(), // non-applicable source path
1198 FilePath(), // non-applicable dest path
1199 file_operation_type,
1200 symlink_path,
1201 false /* don't create symlink */);
1202
1203 // Determine current path of dirty file.
[email protected]11f60db2012-08-23 16:28:151204 if (*error == DRIVE_FILE_OK) {
[email protected]c960d222012-06-15 10:03:501205 *cache_file_path = GetCacheFilePath(
1206 resource_id,
1207 md5,
1208 CACHE_TYPE_PERSISTENT,
1209 CACHED_FILE_LOCALLY_MODIFIED);
1210 }
1211 return;
1212 }
1213
1214 // Move file to persistent dir with new .local extension.
1215
1216 // Get the current path of the file in cache.
1217 FilePath source_path = GetCacheFilePath(
1218 resource_id,
1219 md5,
[email protected]b22f87f2012-07-12 10:53:171220 GetSubDirectoryType(cache_entry),
[email protected]c960d222012-06-15 10:03:501221 CACHED_FILE_FROM_SERVER);
1222
1223 // Determine destination path.
[email protected]3dc88ee2012-07-11 21:04:111224 const CacheSubDirectoryType sub_dir_type = CACHE_TYPE_PERSISTENT;
[email protected]c960d222012-06-15 10:03:501225 *cache_file_path = GetCacheFilePath(resource_id,
1226 md5,
1227 sub_dir_type,
1228 CACHED_FILE_LOCALLY_MODIFIED);
1229
1230 // If file is pinned, update symlink in pinned dir.
1231 FilePath symlink_path;
[email protected]02821102012-07-12 20:19:171232 if (cache_entry.is_pinned()) {
[email protected]c960d222012-06-15 10:03:501233 symlink_path = GetCacheFilePath(resource_id,
1234 std::string(),
1235 CACHE_TYPE_PINNED,
1236 CACHED_FILE_FROM_SERVER);
1237 }
1238
1239 *error = ModifyCacheState(
1240 source_path,
1241 *cache_file_path,
1242 file_operation_type,
1243 symlink_path,
1244 !symlink_path.empty() /* create symlink */);
1245
[email protected]11f60db2012-08-23 16:28:151246 if (*error == DRIVE_FILE_OK) {
[email protected]c960d222012-06-15 10:03:501247 // Now that file operations have completed, update cache map.
[email protected]48477fe2012-07-12 17:45:081248 cache_entry.set_md5(md5);
[email protected]02821102012-07-12 20:19:171249 cache_entry.set_is_dirty(true);
1250 cache_entry.set_is_persistent(sub_dir_type == CACHE_TYPE_PERSISTENT);
[email protected]48477fe2012-07-12 17:45:081251 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry);
[email protected]c960d222012-06-15 10:03:501252 }
1253}
1254
[email protected]fb371812012-08-22 16:05:231255void DriveCache::CommitDirty(const std::string& resource_id,
[email protected]a321b9632012-06-14 03:29:171256 const std::string& md5,
1257 FileOperationType file_operation_type,
[email protected]11f60db2012-08-23 16:28:151258 DriveFileError* error) {
[email protected]a321b9632012-06-14 03:29:171259 AssertOnSequencedWorkerPool();
1260 DCHECK(error);
1261
1262 // If file has already been marked dirty in previous instance of chrome, we
1263 // would have lost the md5 info during cache initialization, because the file
1264 // would have been renamed to .local extension.
1265 // So, search for entry in cache without comparing md5.
[email protected]a321b9632012-06-14 03:29:171266
1267 // Committing a file dirty means its entry and actual file blob must exist in
1268 // cache.
[email protected]28a64092012-08-21 10:01:121269 DriveCacheEntry cache_entry;
[email protected]b22f87f2012-07-12 10:53:171270 if (!GetCacheEntry(resource_id, std::string(), &cache_entry) ||
[email protected]02821102012-07-12 20:19:171271 !cache_entry.is_present()) {
[email protected]a321b9632012-06-14 03:29:171272 LOG(WARNING) << "Can't commit dirty a file that wasn't cached: res_id="
1273 << resource_id
1274 << ", md5=" << md5;
[email protected]11f60db2012-08-23 16:28:151275 *error = DRIVE_FILE_ERROR_NOT_FOUND;
[email protected]a321b9632012-06-14 03:29:171276 return;
1277 }
1278
1279 // If a file is not dirty (it should have been marked dirty via
1280 // MarkDirtyInCache), committing it dirty is an invalid operation.
[email protected]02821102012-07-12 20:19:171281 if (!cache_entry.is_dirty()) {
[email protected]a321b9632012-06-14 03:29:171282 LOG(WARNING) << "Can't commit a non-dirty file: res_id="
1283 << resource_id
1284 << ", md5=" << md5;
[email protected]11f60db2012-08-23 16:28:151285 *error = DRIVE_FILE_ERROR_INVALID_OPERATION;
[email protected]a321b9632012-06-14 03:29:171286 return;
1287 }
1288
1289 // Dirty files must be in persistent dir.
[email protected]02821102012-07-12 20:19:171290 DCHECK(cache_entry.is_persistent());
[email protected]a321b9632012-06-14 03:29:171291
1292 // Create symlink in outgoing dir.
1293 FilePath symlink_path = GetCacheFilePath(resource_id,
1294 std::string(),
1295 CACHE_TYPE_OUTGOING,
1296 CACHED_FILE_FROM_SERVER);
1297
1298 // Get target path of symlink i.e. current path of the file in cache.
1299 FilePath target_path = GetCacheFilePath(resource_id,
1300 md5,
[email protected]b22f87f2012-07-12 10:53:171301 GetSubDirectoryType(cache_entry),
[email protected]a321b9632012-06-14 03:29:171302 CACHED_FILE_LOCALLY_MODIFIED);
1303
1304 // Since there's no need to move files, use |target_path| for both
1305 // |source_path| and |dest_path|, because ModifyCacheState only moves files
1306 // if source and destination are different.
1307 *error = ModifyCacheState(target_path, // source
1308 target_path, // destination
1309 file_operation_type,
1310 symlink_path,
1311 true /* create symlink */);
1312}
1313
[email protected]fb371812012-08-22 16:05:231314void DriveCache::ClearDirty(const std::string& resource_id,
[email protected]a321b9632012-06-14 03:29:171315 const std::string& md5,
1316 FileOperationType file_operation_type,
[email protected]11f60db2012-08-23 16:28:151317 DriveFileError* error) {
[email protected]a321b9632012-06-14 03:29:171318 AssertOnSequencedWorkerPool();
1319 DCHECK(error);
1320
1321 // |md5| is the new .<md5> extension to rename the file to.
1322 // So, search for entry in cache without comparing md5.
[email protected]28a64092012-08-21 10:01:121323 DriveCacheEntry cache_entry;
[email protected]a321b9632012-06-14 03:29:171324
1325 // Clearing a dirty file means its entry and actual file blob must exist in
1326 // cache.
[email protected]b22f87f2012-07-12 10:53:171327 if (!GetCacheEntry(resource_id, std::string(), &cache_entry) ||
[email protected]02821102012-07-12 20:19:171328 !cache_entry.is_present()) {
[email protected]a321b9632012-06-14 03:29:171329 LOG(WARNING) << "Can't clear dirty state of a file that wasn't cached: "
1330 << "res_id=" << resource_id
1331 << ", md5=" << md5;
[email protected]11f60db2012-08-23 16:28:151332 *error = DRIVE_FILE_ERROR_NOT_FOUND;
[email protected]a321b9632012-06-14 03:29:171333 return;
1334 }
1335
1336 // If a file is not dirty (it should have been marked dirty via
1337 // MarkDirtyInCache), clearing its dirty state is an invalid operation.
[email protected]02821102012-07-12 20:19:171338 if (!cache_entry.is_dirty()) {
[email protected]a321b9632012-06-14 03:29:171339 LOG(WARNING) << "Can't clear dirty state of a non-dirty file: res_id="
1340 << resource_id
1341 << ", md5=" << md5;
[email protected]11f60db2012-08-23 16:28:151342 *error = DRIVE_FILE_ERROR_INVALID_OPERATION;
[email protected]a321b9632012-06-14 03:29:171343 return;
1344 }
1345
1346 // File must be dirty and hence in persistent dir.
[email protected]02821102012-07-12 20:19:171347 DCHECK(cache_entry.is_persistent());
[email protected]a321b9632012-06-14 03:29:171348
1349 // Get the current path of the file in cache.
1350 FilePath source_path = GetCacheFilePath(resource_id,
1351 md5,
[email protected]b22f87f2012-07-12 10:53:171352 GetSubDirectoryType(cache_entry),
[email protected]a321b9632012-06-14 03:29:171353 CACHED_FILE_LOCALLY_MODIFIED);
1354
1355 // Determine destination path.
1356 // If file is pinned, move it to persistent dir with .md5 extension;
1357 // otherwise, move it to tmp dir with .md5 extension.
[email protected]3dc88ee2012-07-11 21:04:111358 const CacheSubDirectoryType sub_dir_type =
[email protected]02821102012-07-12 20:19:171359 cache_entry.is_pinned() ? CACHE_TYPE_PERSISTENT : CACHE_TYPE_TMP;
[email protected]a321b9632012-06-14 03:29:171360 FilePath dest_path = GetCacheFilePath(resource_id,
1361 md5,
1362 sub_dir_type,
1363 CACHED_FILE_FROM_SERVER);
1364
1365 // Delete symlink in outgoing dir.
1366 FilePath symlink_path = GetCacheFilePath(resource_id,
1367 std::string(),
1368 CACHE_TYPE_OUTGOING,
1369 CACHED_FILE_FROM_SERVER);
1370
1371 *error = ModifyCacheState(source_path,
1372 dest_path,
1373 file_operation_type,
1374 symlink_path,
1375 false /* don't create symlink */);
1376
1377 // If file is pinned, update symlink in pinned dir.
[email protected]11f60db2012-08-23 16:28:151378 if (*error == DRIVE_FILE_OK && cache_entry.is_pinned()) {
[email protected]a321b9632012-06-14 03:29:171379 symlink_path = GetCacheFilePath(resource_id,
1380 std::string(),
1381 CACHE_TYPE_PINNED,
1382 CACHED_FILE_FROM_SERVER);
1383
1384 // Since there's no moving of files here, use |dest_path| for both
1385 // |source_path| and |dest_path|, because ModifyCacheState only moves files
1386 // if source and destination are different.
1387 *error = ModifyCacheState(dest_path, // source path
1388 dest_path, // destination path
1389 file_operation_type,
1390 symlink_path,
1391 true /* create symlink */);
1392 }
1393
[email protected]11f60db2012-08-23 16:28:151394 if (*error == DRIVE_FILE_OK) {
[email protected]a321b9632012-06-14 03:29:171395 // Now that file operations have completed, update cache map.
[email protected]48477fe2012-07-12 17:45:081396 cache_entry.set_md5(md5);
[email protected]02821102012-07-12 20:19:171397 cache_entry.set_is_dirty(false);
1398 cache_entry.set_is_persistent(sub_dir_type == CACHE_TYPE_PERSISTENT);
[email protected]48477fe2012-07-12 17:45:081399 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry);
[email protected]a321b9632012-06-14 03:29:171400 }
1401}
1402
[email protected]fb371812012-08-22 16:05:231403void DriveCache::Remove(const std::string& resource_id,
[email protected]11f60db2012-08-23 16:28:151404 DriveFileError* error) {
[email protected]a321b9632012-06-14 03:29:171405 AssertOnSequencedWorkerPool();
1406 DCHECK(error);
1407
[email protected]3423871a2012-07-12 00:41:271408 // MD5 is not passed into RemoveCacheEntry because we would delete all
1409 // cache files corresponding to <resource_id> regardless of the md5.
[email protected]a321b9632012-06-14 03:29:171410 // So, search for entry in cache without taking md5 into account.
[email protected]28a64092012-08-21 10:01:121411 DriveCacheEntry cache_entry;
[email protected]a321b9632012-06-14 03:29:171412
1413 // If entry doesn't exist or is dirty or mounted in cache, nothing to do.
[email protected]b22f87f2012-07-12 10:53:171414 const bool entry_found =
1415 GetCacheEntry(resource_id, std::string(), &cache_entry);
[email protected]02821102012-07-12 20:19:171416 if (!entry_found || cache_entry.is_dirty() || cache_entry.is_mounted()) {
[email protected]a321b9632012-06-14 03:29:171417 DVLOG(1) << "Entry is "
[email protected]b22f87f2012-07-12 10:53:171418 << (entry_found ?
[email protected]02821102012-07-12 20:19:171419 (cache_entry.is_dirty() ? "dirty" : "mounted") :
[email protected]a321b9632012-06-14 03:29:171420 "non-existent")
1421 << " in cache, not removing";
[email protected]11f60db2012-08-23 16:28:151422 *error = DRIVE_FILE_OK;
[email protected]a321b9632012-06-14 03:29:171423 return;
1424 }
1425
1426 // Determine paths to delete all cache versions of |resource_id| in
1427 // persistent, tmp and pinned directories.
1428 std::vector<FilePath> paths_to_delete;
1429
1430 // For files in persistent and tmp dirs, delete files that match
1431 // "<resource_id>.*".
1432 paths_to_delete.push_back(GetCacheFilePath(resource_id,
[email protected]ca5f6da2012-06-18 12:54:591433 util::kWildCard,
[email protected]a321b9632012-06-14 03:29:171434 CACHE_TYPE_PERSISTENT,
1435 CACHED_FILE_FROM_SERVER));
1436 paths_to_delete.push_back(GetCacheFilePath(resource_id,
[email protected]ca5f6da2012-06-18 12:54:591437 util::kWildCard,
[email protected]a321b9632012-06-14 03:29:171438 CACHE_TYPE_TMP,
1439 CACHED_FILE_FROM_SERVER));
1440
1441 // For pinned files, filename is "<resource_id>" with no extension, so delete
1442 // "<resource_id>".
1443 paths_to_delete.push_back(GetCacheFilePath(resource_id,
1444 std::string(),
1445 CACHE_TYPE_PINNED,
1446 CACHED_FILE_FROM_SERVER));
1447
1448 // Don't delete locally modified (i.e. dirty and possibly outgoing) files.
1449 // Since we're not deleting outgoing symlinks, we don't need to append
1450 // outgoing path to |paths_to_delete|.
1451 FilePath path_to_keep = GetCacheFilePath(resource_id,
1452 std::string(),
1453 CACHE_TYPE_PERSISTENT,
1454 CACHED_FILE_LOCALLY_MODIFIED);
1455
1456 for (size_t i = 0; i < paths_to_delete.size(); ++i) {
1457 DeleteFilesSelectively(paths_to_delete[i], path_to_keep);
1458 }
1459
1460 // Now that all file operations have completed, remove from cache map.
[email protected]3423871a2012-07-12 00:41:271461 metadata_->RemoveCacheEntry(resource_id);
[email protected]a321b9632012-06-14 03:29:171462
[email protected]11f60db2012-08-23 16:28:151463 *error = DRIVE_FILE_OK;
[email protected]a321b9632012-06-14 03:29:171464}
1465
[email protected]11f60db2012-08-23 16:28:151466void DriveCache::ClearAll(DriveFileError* error) {
[email protected]f861b392012-08-03 20:41:121467 AssertOnSequencedWorkerPool();
1468 DCHECK(error);
1469
1470 bool success = file_util::Delete(cache_root_path_, true);
1471 Initialize();
1472
[email protected]11f60db2012-08-23 16:28:151473 *error = success ? DRIVE_FILE_OK : DRIVE_FILE_ERROR_FAILED;
[email protected]f861b392012-08-03 20:41:121474}
1475
[email protected]11f60db2012-08-23 16:28:151476void DriveCache::OnPinned(DriveFileError* error,
[email protected]73f9c742012-06-15 07:37:131477 const std::string& resource_id,
1478 const std::string& md5,
1479 const CacheOperationCallback& callback) {
1480 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1481 DCHECK(error);
1482
1483 if (!callback.is_null())
1484 callback.Run(*error, resource_id, md5);
1485
[email protected]11f60db2012-08-23 16:28:151486 if (*error == DRIVE_FILE_OK)
[email protected]73f9c742012-06-15 07:37:131487 FOR_EACH_OBSERVER(Observer, observers_, OnCachePinned(resource_id, md5));
[email protected]3653146a2012-05-29 13:41:471488}
1489
[email protected]11f60db2012-08-23 16:28:151490void DriveCache::OnUnpinned(DriveFileError* error,
[email protected]73f9c742012-06-15 07:37:131491 const std::string& resource_id,
1492 const std::string& md5,
1493 const CacheOperationCallback& callback) {
1494 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1495 DCHECK(error);
[email protected]a321b9632012-06-14 03:29:171496
[email protected]73f9c742012-06-15 07:37:131497 if (!callback.is_null())
1498 callback.Run(*error, resource_id, md5);
[email protected]a321b9632012-06-14 03:29:171499
[email protected]11f60db2012-08-23 16:28:151500 if (*error == DRIVE_FILE_OK)
[email protected]73f9c742012-06-15 07:37:131501 FOR_EACH_OBSERVER(Observer, observers_, OnCacheUnpinned(resource_id, md5));
[email protected]a321b9632012-06-14 03:29:171502
[email protected]73f9c742012-06-15 07:37:131503 // Now the file is moved from "persistent" to "tmp" directory.
1504 // It's a chance to free up space if needed.
1505 bool* has_enough_space = new bool(false);
[email protected]ddbf2052012-07-13 15:07:021506 blocking_task_runner_->PostTask(
[email protected]73f9c742012-06-15 07:37:131507 FROM_HERE,
[email protected]fb371812012-08-22 16:05:231508 base::Bind(&DriveCache::FreeDiskSpaceIfNeededFor,
[email protected]73f9c742012-06-15 07:37:131509 base::Unretained(this),
1510 0,
1511 base::Owned(has_enough_space)));
[email protected]3653146a2012-05-29 13:41:471512}
1513
[email protected]11f60db2012-08-23 16:28:151514void DriveCache::OnCommitDirty(DriveFileError* error,
[email protected]d7664c22012-06-18 19:35:491515 const std::string& resource_id,
1516 const std::string& md5,
1517 const CacheOperationCallback& callback) {
1518 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1519 DCHECK(error);
1520
1521 if (!callback.is_null())
1522 callback.Run(*error, resource_id, md5);
1523
[email protected]11f60db2012-08-23 16:28:151524 if (*error == DRIVE_FILE_OK)
[email protected]d7664c22012-06-18 19:35:491525 FOR_EACH_OBSERVER(Observer, observers_, OnCacheCommitted(resource_id));
1526}
1527
[email protected]fb371812012-08-22 16:05:231528void DriveCache::GetCacheEntryHelper(const std::string& resource_id,
[email protected]4324fdc2012-06-29 05:32:481529 const std::string& md5,
1530 bool* success,
[email protected]28a64092012-08-21 10:01:121531 DriveCacheEntry* cache_entry) {
[email protected]4324fdc2012-06-29 05:32:481532 AssertOnSequencedWorkerPool();
1533 DCHECK(success);
1534 DCHECK(cache_entry);
1535
[email protected]b22f87f2012-07-12 10:53:171536 *success = GetCacheEntry(resource_id, md5, cache_entry);
[email protected]4324fdc2012-06-29 05:32:481537}
1538
[email protected]01ba15f72012-06-09 00:41:051539// static
[email protected]fb371812012-08-22 16:05:231540FilePath DriveCache::GetCacheRootPath(Profile* profile) {
[email protected]01ba15f72012-06-09 00:41:051541 FilePath cache_base_path;
1542 chrome::GetUserCacheDirectory(profile->GetPath(), &cache_base_path);
1543 FilePath cache_root_path =
[email protected]fb371812012-08-22 16:05:231544 cache_base_path.Append(chrome::kDriveCacheDirname);
1545 return cache_root_path.Append(kDriveCacheVersionDir);
[email protected]01ba15f72012-06-09 00:41:051546}
1547
[email protected]30d9dda2012-06-30 05:56:281548// static
[email protected]fb371812012-08-22 16:05:231549std::vector<FilePath> DriveCache::GetCachePaths(
[email protected]30d9dda2012-06-30 05:56:281550 const FilePath& cache_root_path) {
1551 std::vector<FilePath> cache_paths;
[email protected]fb371812012-08-22 16:05:231552 // The order should match DriveCache::CacheSubDirectoryType enum.
1553 cache_paths.push_back(cache_root_path.Append(kDriveCacheMetaDir));
1554 cache_paths.push_back(cache_root_path.Append(kDriveCachePinnedDir));
1555 cache_paths.push_back(cache_root_path.Append(kDriveCacheOutgoingDir));
1556 cache_paths.push_back(cache_root_path.Append(kDriveCachePersistentDir));
1557 cache_paths.push_back(cache_root_path.Append(kDriveCacheTmpDir));
1558 cache_paths.push_back(cache_root_path.Append(kDriveCacheTmpDownloadsDir));
1559 cache_paths.push_back(cache_root_path.Append(kDriveCacheTmpDocumentsDir));
[email protected]30d9dda2012-06-30 05:56:281560 return cache_paths;
1561}
1562
1563// static
[email protected]fb371812012-08-22 16:05:231564bool DriveCache::CreateCacheDirectories(
[email protected]30d9dda2012-06-30 05:56:281565 const std::vector<FilePath>& paths_to_create) {
1566 bool success = true;
1567
1568 for (size_t i = 0; i < paths_to_create.size(); ++i) {
1569 if (file_util::DirectoryExists(paths_to_create[i]))
1570 continue;
1571
1572 if (!file_util::CreateDirectory(paths_to_create[i])) {
1573 // Error creating this directory, record error and proceed with next one.
1574 success = false;
1575 PLOG(ERROR) << "Error creating directory " << paths_to_create[i].value();
1576 } else {
1577 DVLOG(1) << "Created directory " << paths_to_create[i].value();
1578 }
1579 }
1580 return success;
1581}
1582
[email protected]fae353a2012-07-11 23:30:271583// static
[email protected]fb371812012-08-22 16:05:231584DriveCache::CacheSubDirectoryType DriveCache::GetSubDirectoryType(
[email protected]28a64092012-08-21 10:01:121585 const DriveCacheEntry& cache_entry) {
[email protected]02821102012-07-12 20:19:171586 return cache_entry.is_persistent() ? CACHE_TYPE_PERSISTENT : CACHE_TYPE_TMP;
[email protected]fae353a2012-07-11 23:30:271587}
1588
[email protected]a321b9632012-06-14 03:29:171589void SetFreeDiskSpaceGetterForTesting(FreeDiskSpaceGetterInterface* getter) {
1590 delete global_free_disk_getter_for_testing; // Safe to delete NULL;
1591 global_free_disk_getter_for_testing = getter;
1592}
1593
[email protected]3653146a2012-05-29 13:41:471594} // namespace gdata