blob: 2c85631c4b9d675ea8ed2d0978f8ad516d368d17 [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]774727282012-08-06 09:14:4411#include "base/path_service.h"
[email protected]3653146a2012-05-29 13:41:4712#include "base/stringprintf.h"
13#include "base/string_util.h"
[email protected]a321b9632012-06-14 03:29:1714#include "base/sys_info.h"
[email protected]15de8142012-10-11 06:00:5415#include "chrome/browser/chromeos/drive/drive.pb.h"
16#include "chrome/browser/chromeos/drive/drive_cache_metadata.h"
17#include "chrome/browser/chromeos/drive/drive_cache_observer.h"
18#include "chrome/browser/chromeos/drive/drive_file_system_util.h"
[email protected]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
[email protected]d9d04df2012-10-12 07:06:3526namespace drive {
[email protected]3653146a2012-05-29 13:41:4727namespace {
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.
[email protected]322e0032012-10-07 01:55:5369bool 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.";
[email protected]322e0032012-10-07 01:55:5373 return false;
[email protected]79c3752d2012-07-17 12:10:0874 }
75
[email protected]fb371812012-08-22 16:05:2376 if (!DriveCache::CreateCacheDirectories(cache_paths))
[email protected]322e0032012-10-07 01:55:5377 return false;
[email protected]79c3752d2012-07-17 12:10:0878
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);
[email protected]322e0032012-10-07 01:55:5386
87 return true;
[email protected]79c3752d2012-07-17 12:10:0888}
89
[email protected]a321b9632012-06-14 03:29:1790// Remove all files under the given directory, non-recursively.
[email protected]d7754f52012-08-01 08:45:3391// Do not remove recursively as we don't want to touch <gcache>/tmp/downloads,
[email protected]a321b9632012-06-14 03:29:1792// which is used for user initiated downloads like "Save As"
93void RemoveAllFiles(const FilePath& directory) {
94 using file_util::FileEnumerator;
95
96 FileEnumerator enumerator(directory, false /* recursive */,
97 FileEnumerator::FILES);
98 for (FilePath file_path = enumerator.Next(); !file_path.empty();
99 file_path = enumerator.Next()) {
100 DVLOG(1) << "Removing " << file_path.value();
101 if (!file_util::Delete(file_path, false /* recursive */))
102 LOG(WARNING) << "Failed to delete " << file_path.value();
103 }
104}
105
[email protected]a321b9632012-06-14 03:29:17106// Modifies cache state of file on blocking pool, which involves:
107// - moving or copying file (per |file_operation_type|) from |source_path| to
108// |dest_path| if they're different
109// - deleting symlink if |symlink_path| is not empty
110// - creating symlink if |symlink_path| is not empty and |create_symlink| is
111// true.
[email protected]11f60db2012-08-23 16:28:15112DriveFileError ModifyCacheState(
[email protected]a321b9632012-06-14 03:29:17113 const FilePath& source_path,
114 const FilePath& dest_path,
[email protected]fb371812012-08-22 16:05:23115 DriveCache::FileOperationType file_operation_type,
[email protected]a321b9632012-06-14 03:29:17116 const FilePath& symlink_path,
117 bool create_symlink) {
118 // Move or copy |source_path| to |dest_path| if they are different.
119 if (source_path != dest_path) {
120 bool success = false;
[email protected]fb371812012-08-22 16:05:23121 if (file_operation_type == DriveCache::FILE_OPERATION_MOVE)
[email protected]a321b9632012-06-14 03:29:17122 success = file_util::Move(source_path, dest_path);
[email protected]fb371812012-08-22 16:05:23123 else if (file_operation_type == DriveCache::FILE_OPERATION_COPY)
[email protected]a321b9632012-06-14 03:29:17124 success = file_util::CopyFile(source_path, dest_path);
125 if (!success) {
[email protected]750af1d2012-07-13 14:32:43126 LOG(ERROR) << "Failed to "
[email protected]fb371812012-08-22 16:05:23127 << (file_operation_type == DriveCache::FILE_OPERATION_MOVE ?
[email protected]750af1d2012-07-13 14:32:43128 "move " : "copy ")
129 << source_path.value()
130 << " to " << dest_path.value();
[email protected]11f60db2012-08-23 16:28:15131 return DRIVE_FILE_ERROR_FAILED;
[email protected]a321b9632012-06-14 03:29:17132 } else {
[email protected]fb371812012-08-22 16:05:23133 DVLOG(1) << (file_operation_type == DriveCache::FILE_OPERATION_MOVE ?
[email protected]a321b9632012-06-14 03:29:17134 "Moved " : "Copied ")
135 << source_path.value()
136 << " to " << dest_path.value();
137 }
138 } else {
139 DVLOG(1) << "No need to move file: source = destination";
140 }
141
142 if (symlink_path.empty())
[email protected]11f60db2012-08-23 16:28:15143 return DRIVE_FILE_OK;
[email protected]a321b9632012-06-14 03:29:17144
145 // Remove symlink regardless of |create_symlink| because creating a link will
146 // not overwrite an existing one.
[email protected]a321b9632012-06-14 03:29:17147 // We try to save one file operation by not checking if link exists before
148 // deleting it, so unlink may return error if link doesn't exist, but it
149 // doesn't really matter to us.
[email protected]750af1d2012-07-13 14:32:43150 file_util::Delete(symlink_path, false);
[email protected]a321b9632012-06-14 03:29:17151
152 if (!create_symlink)
[email protected]11f60db2012-08-23 16:28:15153 return DRIVE_FILE_OK;
[email protected]a321b9632012-06-14 03:29:17154
155 // Create new symlink to |dest_path|.
156 if (!file_util::CreateSymbolicLink(dest_path, symlink_path)) {
[email protected]750af1d2012-07-13 14:32:43157 LOG(ERROR) << "Failed to create a symlink from " << symlink_path.value()
158 << " to " << dest_path.value();
[email protected]11f60db2012-08-23 16:28:15159 return DRIVE_FILE_ERROR_FAILED;
[email protected]a321b9632012-06-14 03:29:17160 }
161
[email protected]11f60db2012-08-23 16:28:15162 return DRIVE_FILE_OK;
[email protected]a321b9632012-06-14 03:29:17163}
164
165// Deletes all files that match |path_to_delete_pattern| except for
166// |path_to_keep| on blocking pool.
167// If |path_to_keep| is empty, all files in |path_to_delete_pattern| are
168// deleted.
169void DeleteFilesSelectively(const FilePath& path_to_delete_pattern,
170 const FilePath& path_to_keep) {
171 // Enumerate all files in directory of |path_to_delete_pattern| that match
172 // base name of |path_to_delete_pattern|.
173 // If a file is not |path_to_keep|, delete it.
174 bool success = true;
[email protected]84c3f162012-08-12 01:57:23175 file_util::FileEnumerator enumerator(path_to_delete_pattern.DirName(),
[email protected]a321b9632012-06-14 03:29:17176 false, // not recursive
[email protected]84c3f162012-08-12 01:57:23177 file_util::FileEnumerator::FILES |
178 file_util::FileEnumerator::SHOW_SYM_LINKS,
[email protected]a321b9632012-06-14 03:29:17179 path_to_delete_pattern.BaseName().value());
180 for (FilePath current = enumerator.Next(); !current.empty();
181 current = enumerator.Next()) {
182 // If |path_to_keep| is not empty and same as current, don't delete it.
183 if (!path_to_keep.empty() && current == path_to_keep)
184 continue;
185
[email protected]0b8d4cee2012-07-02 20:46:26186 success = file_util::Delete(current, false);
[email protected]a321b9632012-06-14 03:29:17187 if (!success)
188 DVLOG(1) << "Error deleting " << current.value();
189 else
190 DVLOG(1) << "Deleted " << current.value();
191 }
192}
193
[email protected]b83e5202012-06-27 07:50:24194// Appends |resource_id| ID to |to_fetch| if the file is pinned but not
195// fetched (not present locally), or to |to_upload| if the file is dirty
196// but not uploaded.
197void CollectBacklog(std::vector<std::string>* to_fetch,
198 std::vector<std::string>* to_upload,
199 const std::string& resource_id,
[email protected]28a64092012-08-21 10:01:12200 const DriveCacheEntry& cache_entry) {
[email protected]b83e5202012-06-27 07:50:24201 DCHECK(to_fetch);
202 DCHECK(to_upload);
[email protected]8764a392012-06-20 06:43:08203
[email protected]02821102012-07-12 20:19:17204 if (cache_entry.is_pinned() && !cache_entry.is_present())
[email protected]b83e5202012-06-27 07:50:24205 to_fetch->push_back(resource_id);
206
[email protected]02821102012-07-12 20:19:17207 if (cache_entry.is_dirty())
[email protected]b83e5202012-06-27 07:50:24208 to_upload->push_back(resource_id);
[email protected]8764a392012-06-20 06:43:08209}
210
[email protected]85b62192012-06-29 19:56:38211// Appends |resource_id| ID to |resource_ids| if the file is pinned and
212// present (cached locally).
213void CollectExistingPinnedFile(std::vector<std::string>* resource_ids,
214 const std::string& resource_id,
[email protected]28a64092012-08-21 10:01:12215 const DriveCacheEntry& cache_entry) {
[email protected]85b62192012-06-29 19:56:38216 DCHECK(resource_ids);
217
[email protected]02821102012-07-12 20:19:17218 if (cache_entry.is_pinned() && cache_entry.is_present())
[email protected]85b62192012-06-29 19:56:38219 resource_ids->push_back(resource_id);
220}
[email protected]8764a392012-06-20 06:43:08221
[email protected]cd236432012-07-27 18:03:30222// Appends |resource_id| ID to |resource_ids| unconditionally.
223void CollectAnyFile(std::vector<std::string>* resource_ids,
224 const std::string& resource_id,
[email protected]28a64092012-08-21 10:01:12225 const DriveCacheEntry& /* cache_entry */) {
[email protected]cd236432012-07-27 18:03:30226 DCHECK(resource_ids);
227
228 resource_ids->push_back(resource_id);
229}
230
[email protected]7986b8d2012-06-14 15:05:14231// Runs callback with pointers dereferenced.
[email protected]f861b392012-08-03 20:41:12232// Used to implement SetMountedStateOnUIThread and ClearAllOnUIThread.
233void RunChangeCacheStateCallback(const ChangeCacheStateCallback& callback,
[email protected]11f60db2012-08-23 16:28:15234 const DriveFileError* error,
[email protected]f861b392012-08-03 20:41:12235 const FilePath* cache_file_path) {
[email protected]7986b8d2012-06-14 15:05:14236 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
237 DCHECK(error);
238 DCHECK(cache_file_path);
239
240 if (!callback.is_null())
241 callback.Run(*error, *cache_file_path);
242}
243
[email protected]73f9c742012-06-15 07:37:13244// Runs callback with pointers dereferenced.
245// Used to implement *OnUIThread methods.
246void RunCacheOperationCallback(const CacheOperationCallback& callback,
[email protected]11f60db2012-08-23 16:28:15247 DriveFileError* error,
[email protected]73f9c742012-06-15 07:37:13248 const std::string& resource_id,
249 const std::string& md5) {
250 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
251 DCHECK(error);
252
253 if (!callback.is_null())
254 callback.Run(*error, resource_id, md5);
255}
256
[email protected]c960d222012-06-15 10:03:50257// Runs callback with pointers dereferenced.
258// Used to implement *OnUIThread methods.
259void RunGetFileFromCacheCallback(const GetFileFromCacheCallback& callback,
[email protected]11f60db2012-08-23 16:28:15260 DriveFileError* error,
[email protected]c960d222012-06-15 10:03:50261 FilePath* cache_file_path) {
262 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
263 DCHECK(error);
264 DCHECK(cache_file_path);
265
266 if (!callback.is_null())
[email protected]3cacd172e22012-09-06 22:52:45267 callback.Run(*error, *cache_file_path);
[email protected]c960d222012-06-15 10:03:50268}
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]322e0032012-10-07 01:55:53309// Runs InitializeCacheCallback with a pointer dereferenced.
310void RunInitializeCacheCallback(const InitializeCacheCallback& callback,
311 bool* success) {
312 DCHECK(success);
313
314 if (!callback.is_null())
315 callback.Run(*success);
316}
317
[email protected]a321b9632012-06-14 03:29:17318} // namespace
[email protected]32a7fc852012-06-08 17:25:50319
[email protected]fb371812012-08-22 16:05:23320DriveCache::DriveCache(const FilePath& cache_root_path,
[email protected]ddbf2052012-07-13 15:07:02321 base::SequencedTaskRunner* blocking_task_runner)
[email protected]01ba15f72012-06-09 00:41:05322 : cache_root_path_(cache_root_path),
[email protected]6b70c7b2012-06-14 03:10:43323 cache_paths_(GetCachePaths(cache_root_path_)),
[email protected]ddbf2052012-07-13 15:07:02324 blocking_task_runner_(blocking_task_runner),
[email protected]dc2e8f7b2012-08-30 20:22:44325 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
[email protected]73f9c742012-06-15 07:37:13326 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]3653146a2012-05-29 13:41:47327}
328
[email protected]fb371812012-08-22 16:05:23329DriveCache::~DriveCache() {
[email protected]73f9c742012-06-15 07:37:13330 AssertOnSequencedWorkerPool();
[email protected]3653146a2012-05-29 13:41:47331}
332
[email protected]fb371812012-08-22 16:05:23333FilePath DriveCache::GetCacheDirectoryPath(
[email protected]32a7fc852012-06-08 17:25:50334 CacheSubDirectoryType sub_dir_type) const {
335 DCHECK_LE(0, sub_dir_type);
336 DCHECK_GT(NUM_CACHE_TYPES, sub_dir_type);
337 return cache_paths_[sub_dir_type];
338}
339
[email protected]fb371812012-08-22 16:05:23340FilePath DriveCache::GetCacheFilePath(const std::string& resource_id,
[email protected]32a7fc852012-06-08 17:25:50341 const std::string& md5,
342 CacheSubDirectoryType sub_dir_type,
343 CachedFileOrigin file_origin) const {
344 DCHECK(sub_dir_type != CACHE_TYPE_META);
345
346 // Runs on any thread.
347 // Filename is formatted as resource_id.md5, i.e. resource_id is the base
348 // name and md5 is the extension.
349 std::string base_name = util::EscapeCacheFileName(resource_id);
350 if (file_origin == CACHED_FILE_LOCALLY_MODIFIED) {
351 DCHECK(sub_dir_type == CACHE_TYPE_PERSISTENT);
352 base_name += FilePath::kExtensionSeparator;
[email protected]b83e5202012-06-27 07:50:24353 base_name += util::kLocallyModifiedFileExtension;
[email protected]32a7fc852012-06-08 17:25:50354 } else if (!md5.empty()) {
355 base_name += FilePath::kExtensionSeparator;
356 base_name += util::EscapeCacheFileName(md5);
357 }
358 // For mounted archives the filename is formatted as resource_id.md5.mounted,
359 // i.e. resource_id.md5 is the base name and ".mounted" is the extension
360 if (file_origin == CACHED_FILE_MOUNTED) {
[email protected]a321b9632012-06-14 03:29:17361 DCHECK(sub_dir_type == CACHE_TYPE_PERSISTENT);
362 base_name += FilePath::kExtensionSeparator;
[email protected]ca5f6da2012-06-18 12:54:59363 base_name += util::kMountedArchiveFileExtension;
[email protected]32a7fc852012-06-08 17:25:50364 }
365 return GetCacheDirectoryPath(sub_dir_type).Append(base_name);
366}
367
[email protected]fb371812012-08-22 16:05:23368void DriveCache::AssertOnSequencedWorkerPool() {
[email protected]ddbf2052012-07-13 15:07:02369 DCHECK(!blocking_task_runner_ ||
370 blocking_task_runner_->RunsTasksOnCurrentThread());
[email protected]fcc92a52012-06-08 22:54:16371}
372
[email protected]fb371812012-08-22 16:05:23373bool DriveCache::IsUnderDriveCacheDirectory(const FilePath& path) const {
[email protected]01ba15f72012-06-09 00:41:05374 return cache_root_path_ == path || cache_root_path_.IsParent(path);
375}
376
[email protected]a09275502012-10-10 04:48:01377void DriveCache::AddObserver(DriveCacheObserver* observer) {
[email protected]73f9c742012-06-15 07:37:13378 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
379 observers_.AddObserver(observer);
380}
381
[email protected]a09275502012-10-10 04:48:01382void DriveCache::RemoveObserver(DriveCacheObserver* observer) {
[email protected]73f9c742012-06-15 07:37:13383 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
384 observers_.RemoveObserver(observer);
385}
386
[email protected]fb371812012-08-22 16:05:23387void DriveCache::GetCacheEntryOnUIThread(
[email protected]4324fdc2012-06-29 05:32:48388 const std::string& resource_id,
389 const std::string& md5,
390 const GetCacheEntryCallback& callback) {
391 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
392
393 bool* success = new bool(false);
[email protected]28a64092012-08-21 10:01:12394 DriveCacheEntry* cache_entry = new DriveCacheEntry;
[email protected]ddbf2052012-07-13 15:07:02395 blocking_task_runner_->PostTaskAndReply(
[email protected]4324fdc2012-06-29 05:32:48396 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23397 base::Bind(&DriveCache::GetCacheEntryHelper,
[email protected]4324fdc2012-06-29 05:32:48398 base::Unretained(this),
399 resource_id,
400 md5,
401 success,
402 cache_entry),
403 base::Bind(&RunGetCacheEntryCallback,
404 callback,
405 base::Owned(success),
406 base::Owned(cache_entry)));
407}
408
[email protected]fb371812012-08-22 16:05:23409void DriveCache::GetResourceIdsOfBacklogOnUIThread(
[email protected]85b62192012-06-29 19:56:38410 const GetResourceIdsOfBacklogCallback& callback) {
[email protected]8764a392012-06-20 06:43:08411 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
412
[email protected]b83e5202012-06-27 07:50:24413 std::vector<std::string>* to_fetch = new std::vector<std::string>;
414 std::vector<std::string>* to_upload = new std::vector<std::string>;
[email protected]ddbf2052012-07-13 15:07:02415 blocking_task_runner_->PostTaskAndReply(
[email protected]8764a392012-06-20 06:43:08416 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23417 base::Bind(&DriveCache::GetResourceIdsOfBacklog,
[email protected]8764a392012-06-20 06:43:08418 base::Unretained(this),
[email protected]b83e5202012-06-27 07:50:24419 to_fetch,
420 to_upload),
[email protected]85b62192012-06-29 19:56:38421 base::Bind(&RunGetResourceIdsOfBacklogCallback,
[email protected]8764a392012-06-20 06:43:08422 callback,
[email protected]b83e5202012-06-27 07:50:24423 base::Owned(to_fetch),
424 base::Owned(to_upload)));
[email protected]8764a392012-06-20 06:43:08425}
426
[email protected]fb371812012-08-22 16:05:23427void DriveCache::GetResourceIdsOfExistingPinnedFilesOnUIThread(
[email protected]85b62192012-06-29 19:56:38428 const GetResourceIdsCallback& callback) {
429 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
430
431 std::vector<std::string>* resource_ids = new std::vector<std::string>;
[email protected]ddbf2052012-07-13 15:07:02432 blocking_task_runner_->PostTaskAndReply(
[email protected]85b62192012-06-29 19:56:38433 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23434 base::Bind(&DriveCache::GetResourceIdsOfExistingPinnedFiles,
[email protected]85b62192012-06-29 19:56:38435 base::Unretained(this),
436 resource_ids),
437 base::Bind(&RunGetResourceIdsCallback,
438 callback,
439 base::Owned(resource_ids)));
440}
441
[email protected]fb371812012-08-22 16:05:23442void DriveCache::GetResourceIdsOfAllFilesOnUIThread(
[email protected]cd236432012-07-27 18:03:30443 const GetResourceIdsCallback& callback) {
444 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
445
446 std::vector<std::string>* resource_ids = new std::vector<std::string>;
447 blocking_task_runner_->PostTaskAndReply(
448 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23449 base::Bind(&DriveCache::GetResourceIdsOfAllFiles,
[email protected]cd236432012-07-27 18:03:30450 base::Unretained(this),
451 resource_ids),
452 base::Bind(&RunGetResourceIdsCallback,
453 callback,
454 base::Owned(resource_ids)));
455}
456
[email protected]fb371812012-08-22 16:05:23457void DriveCache::FreeDiskSpaceIfNeededFor(int64 num_bytes,
[email protected]a321b9632012-06-14 03:29:17458 bool* has_enough_space) {
459 AssertOnSequencedWorkerPool();
460
461 // Do nothing and return if we have enough space.
462 *has_enough_space = HasEnoughSpaceFor(num_bytes);
463 if (*has_enough_space)
464 return;
465
466 // Otherwise, try to free up the disk space.
467 DVLOG(1) << "Freeing up disk space for " << num_bytes;
468 // First remove temporary files from the cache map.
[email protected]ca5f6da2012-06-18 12:54:59469 metadata_->RemoveTemporaryFiles();
[email protected]a321b9632012-06-14 03:29:17470 // Then remove all files under "tmp" directory.
[email protected]fb371812012-08-22 16:05:23471 RemoveAllFiles(GetCacheDirectoryPath(DriveCache::CACHE_TYPE_TMP));
[email protected]a321b9632012-06-14 03:29:17472
473 // Check the disk space again.
474 *has_enough_space = HasEnoughSpaceFor(num_bytes);
475}
476
[email protected]fb371812012-08-22 16:05:23477void DriveCache::GetFileOnUIThread(const std::string& resource_id,
[email protected]c960d222012-06-15 10:03:50478 const std::string& md5,
479 const GetFileFromCacheCallback& callback) {
480 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]a321b9632012-06-14 03:29:17481
[email protected]11f60db2012-08-23 16:28:15482 DriveFileError* error = new DriveFileError(DRIVE_FILE_OK);
[email protected]c960d222012-06-15 10:03:50483 FilePath* cache_file_path = new FilePath;
[email protected]ddbf2052012-07-13 15:07:02484 blocking_task_runner_->PostTaskAndReply(
[email protected]c960d222012-06-15 10:03:50485 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23486 base::Bind(&DriveCache::GetFile,
[email protected]c960d222012-06-15 10:03:50487 base::Unretained(this),
488 resource_id,
489 md5,
490 error,
491 cache_file_path),
492 base::Bind(&RunGetFileFromCacheCallback,
493 callback,
494 base::Owned(error),
[email protected]c960d222012-06-15 10:03:50495 base::Owned(cache_file_path)));
[email protected]a321b9632012-06-14 03:29:17496}
497
[email protected]fb371812012-08-22 16:05:23498void DriveCache::StoreOnUIThread(const std::string& resource_id,
[email protected]73f9c742012-06-15 07:37:13499 const std::string& md5,
500 const FilePath& source_path,
501 FileOperationType file_operation_type,
502 const CacheOperationCallback& callback) {
503 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
504
[email protected]11f60db2012-08-23 16:28:15505 DriveFileError* error = new DriveFileError(DRIVE_FILE_OK);
[email protected]ddbf2052012-07-13 15:07:02506 blocking_task_runner_->PostTaskAndReply(
[email protected]73f9c742012-06-15 07:37:13507 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23508 base::Bind(&DriveCache::Store,
[email protected]73f9c742012-06-15 07:37:13509 base::Unretained(this),
510 resource_id,
511 md5,
512 source_path,
513 file_operation_type,
514 error),
515 base::Bind(&RunCacheOperationCallback,
516 callback,
517 base::Owned(error),
518 resource_id,
519 md5));
520}
521
[email protected]fb371812012-08-22 16:05:23522void DriveCache::PinOnUIThread(const std::string& resource_id,
[email protected]44c0584e2012-06-15 23:55:41523 const std::string& md5,
524 const CacheOperationCallback& callback) {
[email protected]73f9c742012-06-15 07:37:13525 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
526
[email protected]11f60db2012-08-23 16:28:15527 DriveFileError* error = new DriveFileError(DRIVE_FILE_OK);
[email protected]ddbf2052012-07-13 15:07:02528 blocking_task_runner_->PostTaskAndReply(
[email protected]73f9c742012-06-15 07:37:13529 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23530 base::Bind(&DriveCache::Pin,
[email protected]73f9c742012-06-15 07:37:13531 base::Unretained(this),
532 resource_id,
533 md5,
[email protected]fb371812012-08-22 16:05:23534 DriveCache::FILE_OPERATION_MOVE,
[email protected]73f9c742012-06-15 07:37:13535 error),
[email protected]fb371812012-08-22 16:05:23536 base::Bind(&DriveCache::OnPinned,
[email protected]e53ac8f2012-08-02 07:05:00537 weak_ptr_factory_.GetWeakPtr(),
[email protected]73f9c742012-06-15 07:37:13538 base::Owned(error),
539 resource_id,
540 md5,
541 callback));
542}
543
[email protected]fb371812012-08-22 16:05:23544void DriveCache::UnpinOnUIThread(const std::string& resource_id,
[email protected]73f9c742012-06-15 07:37:13545 const std::string& md5,
546 const CacheOperationCallback& callback) {
547 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]11f60db2012-08-23 16:28:15548 DriveFileError* error = new DriveFileError(DRIVE_FILE_OK);
[email protected]ddbf2052012-07-13 15:07:02549 blocking_task_runner_->PostTaskAndReply(
[email protected]73f9c742012-06-15 07:37:13550 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23551 base::Bind(&DriveCache::Unpin,
[email protected]73f9c742012-06-15 07:37:13552 base::Unretained(this),
553 resource_id,
554 md5,
[email protected]fb371812012-08-22 16:05:23555 DriveCache::FILE_OPERATION_MOVE,
[email protected]73f9c742012-06-15 07:37:13556 error),
[email protected]fb371812012-08-22 16:05:23557 base::Bind(&DriveCache::OnUnpinned,
[email protected]e53ac8f2012-08-02 07:05:00558 weak_ptr_factory_.GetWeakPtr(),
[email protected]73f9c742012-06-15 07:37:13559 base::Owned(error),
560 resource_id,
561 md5,
562 callback));
563}
564
[email protected]fb371812012-08-22 16:05:23565void DriveCache::SetMountedStateOnUIThread(
[email protected]73f9c742012-06-15 07:37:13566 const FilePath& file_path,
567 bool to_mount,
[email protected]f861b392012-08-03 20:41:12568 const ChangeCacheStateCallback& callback) {
[email protected]73f9c742012-06-15 07:37:13569 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
570
[email protected]11f60db2012-08-23 16:28:15571 DriveFileError* error = new DriveFileError(DRIVE_FILE_OK);
[email protected]73f9c742012-06-15 07:37:13572 FilePath* cache_file_path = new FilePath;
[email protected]ddbf2052012-07-13 15:07:02573 blocking_task_runner_->PostTaskAndReply(
[email protected]73f9c742012-06-15 07:37:13574 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23575 base::Bind(&DriveCache::SetMountedState,
[email protected]73f9c742012-06-15 07:37:13576 base::Unretained(this),
577 file_path,
578 to_mount,
579 error,
580 cache_file_path),
[email protected]f861b392012-08-03 20:41:12581 base::Bind(&RunChangeCacheStateCallback,
[email protected]73f9c742012-06-15 07:37:13582 callback,
583 base::Owned(error),
584 base::Owned(cache_file_path)));
585}
586
[email protected]fb371812012-08-22 16:05:23587void DriveCache::MarkDirtyOnUIThread(const std::string& resource_id,
[email protected]c960d222012-06-15 10:03:50588 const std::string& md5,
589 const GetFileFromCacheCallback& callback) {
590 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]73f9c742012-06-15 07:37:13591
[email protected]11f60db2012-08-23 16:28:15592 DriveFileError* error = new DriveFileError(DRIVE_FILE_OK);
[email protected]c960d222012-06-15 10:03:50593 FilePath* cache_file_path = new FilePath;
[email protected]ddbf2052012-07-13 15:07:02594 blocking_task_runner_->PostTaskAndReply(
[email protected]c960d222012-06-15 10:03:50595 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23596 base::Bind(&DriveCache::MarkDirty,
[email protected]c960d222012-06-15 10:03:50597 base::Unretained(this),
598 resource_id,
599 md5,
[email protected]fb371812012-08-22 16:05:23600 DriveCache::FILE_OPERATION_MOVE,
[email protected]c960d222012-06-15 10:03:50601 error,
602 cache_file_path),
603 base::Bind(&RunGetFileFromCacheCallback,
604 callback,
605 base::Owned(error),
[email protected]c960d222012-06-15 10:03:50606 base::Owned(cache_file_path)));
[email protected]73f9c742012-06-15 07:37:13607}
608
[email protected]fb371812012-08-22 16:05:23609void DriveCache::CommitDirtyOnUIThread(const std::string& resource_id,
[email protected]73f9c742012-06-15 07:37:13610 const std::string& md5,
611 const CacheOperationCallback& callback) {
612 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
613
[email protected]11f60db2012-08-23 16:28:15614 DriveFileError* error = new DriveFileError(DRIVE_FILE_OK);
[email protected]ddbf2052012-07-13 15:07:02615 blocking_task_runner_->PostTaskAndReply(
[email protected]73f9c742012-06-15 07:37:13616 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23617 base::Bind(&DriveCache::CommitDirty,
[email protected]73f9c742012-06-15 07:37:13618 base::Unretained(this),
619 resource_id,
620 md5,
[email protected]fb371812012-08-22 16:05:23621 DriveCache::FILE_OPERATION_MOVE,
[email protected]73f9c742012-06-15 07:37:13622 error),
[email protected]fb371812012-08-22 16:05:23623 base::Bind(&DriveCache::OnCommitDirty,
[email protected]e53ac8f2012-08-02 07:05:00624 weak_ptr_factory_.GetWeakPtr(),
[email protected]73f9c742012-06-15 07:37:13625 base::Owned(error),
626 resource_id,
[email protected]d7664c22012-06-18 19:35:49627 md5,
628 callback));
[email protected]73f9c742012-06-15 07:37:13629}
630
[email protected]fb371812012-08-22 16:05:23631void DriveCache::ClearDirtyOnUIThread(const std::string& resource_id,
[email protected]73f9c742012-06-15 07:37:13632 const std::string& md5,
633 const CacheOperationCallback& callback) {
634 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
635
[email protected]11f60db2012-08-23 16:28:15636 DriveFileError* error = new DriveFileError(DRIVE_FILE_OK);
[email protected]ddbf2052012-07-13 15:07:02637 blocking_task_runner_->PostTaskAndReply(
[email protected]73f9c742012-06-15 07:37:13638 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23639 base::Bind(&DriveCache::ClearDirty,
[email protected]73f9c742012-06-15 07:37:13640 base::Unretained(this),
641 resource_id,
642 md5,
[email protected]fb371812012-08-22 16:05:23643 DriveCache::FILE_OPERATION_MOVE,
[email protected]73f9c742012-06-15 07:37:13644 error),
645 base::Bind(&RunCacheOperationCallback,
646 callback,
647 base::Owned(error),
648 resource_id,
649 md5));
650}
651
[email protected]fb371812012-08-22 16:05:23652void DriveCache::RemoveOnUIThread(const std::string& resource_id,
[email protected]73f9c742012-06-15 07:37:13653 const CacheOperationCallback& callback) {
654 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
655
[email protected]11f60db2012-08-23 16:28:15656 DriveFileError* error = new DriveFileError(DRIVE_FILE_OK);
[email protected]ddbf2052012-07-13 15:07:02657 blocking_task_runner_->PostTaskAndReply(
[email protected]73f9c742012-06-15 07:37:13658 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23659 base::Bind(&DriveCache::Remove,
[email protected]73f9c742012-06-15 07:37:13660 base::Unretained(this),
661 resource_id,
662 error),
663 base::Bind(&RunCacheOperationCallback,
664 callback,
665 base::Owned(error),
666 resource_id,
667 "" /* md5 */));
668}
669
[email protected]fb371812012-08-22 16:05:23670void DriveCache::ClearAllOnUIThread(const ChangeCacheStateCallback& callback) {
[email protected]f861b392012-08-03 20:41:12671 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
672
[email protected]11f60db2012-08-23 16:28:15673 DriveFileError* error = new DriveFileError(DRIVE_FILE_OK);
[email protected]f861b392012-08-03 20:41:12674 blocking_task_runner_->PostTaskAndReply(
675 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23676 base::Bind(&DriveCache::ClearAll,
[email protected]f861b392012-08-03 20:41:12677 base::Unretained(this),
678 error),
679 base::Bind(&RunChangeCacheStateCallback,
680 callback,
681 base::Owned(error),
682 &cache_root_path_));
683}
684
[email protected]322e0032012-10-07 01:55:53685void DriveCache::RequestInitializeOnUIThread(
686 const InitializeCacheCallback& callback) {
[email protected]73f9c742012-06-15 07:37:13687 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]322e0032012-10-07 01:55:53688 DCHECK(!callback.is_null());
[email protected]73f9c742012-06-15 07:37:13689
[email protected]322e0032012-10-07 01:55:53690 bool* success = new bool(false);
691 blocking_task_runner_->PostTaskAndReply(
[email protected]73f9c742012-06-15 07:37:13692 FROM_HERE,
[email protected]322e0032012-10-07 01:55:53693 base::Bind(&DriveCache::Initialize,
694 base::Unretained(this),
695 success),
696 base::Bind(&RunInitializeCacheCallback,
697 callback,
698 base::Owned(success)));
[email protected]73f9c742012-06-15 07:37:13699}
700
[email protected]fb371812012-08-22 16:05:23701void DriveCache::RequestInitializeOnUIThreadForTesting() {
[email protected]d310bfc2012-08-10 09:41:28702 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
703
704 blocking_task_runner_->PostTask(
705 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23706 base::Bind(&DriveCache::InitializeForTesting, base::Unretained(this)));
[email protected]d310bfc2012-08-10 09:41:28707}
708
[email protected]fb371812012-08-22 16:05:23709void DriveCache::ForceRescanOnUIThreadForTesting() {
[email protected]79c3752d2012-07-17 12:10:08710 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
711
712 blocking_task_runner_->PostTask(
713 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23714 base::Bind(&DriveCache::ForceRescanForTesting, base::Unretained(this)));
[email protected]79c3752d2012-07-17 12:10:08715}
716
[email protected]fb371812012-08-22 16:05:23717bool DriveCache::GetCacheEntry(const std::string& resource_id,
[email protected]b22f87f2012-07-12 10:53:17718 const std::string& md5,
[email protected]28a64092012-08-21 10:01:12719 DriveCacheEntry* entry) {
[email protected]b22f87f2012-07-12 10:53:17720 DCHECK(entry);
[email protected]73f9c742012-06-15 07:37:13721 AssertOnSequencedWorkerPool();
[email protected]b22f87f2012-07-12 10:53:17722 return metadata_->GetCacheEntry(resource_id, md5, entry);
[email protected]73f9c742012-06-15 07:37:13723}
724
725// static
[email protected]fb371812012-08-22 16:05:23726DriveCache* DriveCache::CreateDriveCacheOnUIThread(
[email protected]73f9c742012-06-15 07:37:13727 const FilePath& cache_root_path,
[email protected]ddbf2052012-07-13 15:07:02728 base::SequencedTaskRunner* blocking_task_runner) {
[email protected]73f9c742012-06-15 07:37:13729 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]fb371812012-08-22 16:05:23730 return new DriveCache(cache_root_path, blocking_task_runner);
[email protected]73f9c742012-06-15 07:37:13731}
732
[email protected]fb371812012-08-22 16:05:23733void DriveCache::DestroyOnUIThread() {
[email protected]73f9c742012-06-15 07:37:13734 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
735
736 // Invalidate the weak pointer.
[email protected]e53ac8f2012-08-02 07:05:00737 weak_ptr_factory_.InvalidateWeakPtrs();
[email protected]73f9c742012-06-15 07:37:13738
739 // Destroy myself on the blocking pool.
[email protected]ddbf2052012-07-13 15:07:02740 blocking_task_runner_->PostTask(
[email protected]73f9c742012-06-15 07:37:13741 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23742 base::Bind(&DriveCache::Destroy,
[email protected]73f9c742012-06-15 07:37:13743 base::Unretained(this)));
744}
745
[email protected]322e0032012-10-07 01:55:53746void DriveCache::Initialize(bool* success) {
[email protected]ca5f6da2012-06-18 12:54:59747 AssertOnSequencedWorkerPool();
[email protected]322e0032012-10-07 01:55:53748 DCHECK(success);
[email protected]ca5f6da2012-06-18 12:54:59749
[email protected]322e0032012-10-07 01:55:53750 if (!InitCachePaths(cache_paths_)) {
751 *success = false;
752 return;
753 }
754
[email protected]fb371812012-08-22 16:05:23755 metadata_ = DriveCacheMetadata::CreateDriveCacheMetadata(
[email protected]f9e5cc02012-07-13 20:08:56756 blocking_task_runner_).Pass();
[email protected]322e0032012-10-07 01:55:53757 *success = metadata_->Initialize(cache_paths_);
[email protected]ca5f6da2012-06-18 12:54:59758}
759
[email protected]fb371812012-08-22 16:05:23760void DriveCache::InitializeForTesting() {
[email protected]d310bfc2012-08-10 09:41:28761 AssertOnSequencedWorkerPool();
762
763 InitCachePaths(cache_paths_);
[email protected]fb371812012-08-22 16:05:23764 metadata_ = DriveCacheMetadata::CreateDriveCacheMetadataForTesting(
[email protected]d310bfc2012-08-10 09:41:28765 blocking_task_runner_).Pass();
766 metadata_->Initialize(cache_paths_);
767}
768
[email protected]fb371812012-08-22 16:05:23769void DriveCache::Destroy() {
[email protected]73f9c742012-06-15 07:37:13770 AssertOnSequencedWorkerPool();
771 delete this;
772}
773
[email protected]fb371812012-08-22 16:05:23774void DriveCache::ForceRescanForTesting() {
[email protected]79c3752d2012-07-17 12:10:08775 AssertOnSequencedWorkerPool();
776 metadata_->ForceRescanForTesting(cache_paths_);
777}
778
[email protected]fb371812012-08-22 16:05:23779void DriveCache::GetResourceIdsOfBacklog(
[email protected]b83e5202012-06-27 07:50:24780 std::vector<std::string>* to_fetch,
781 std::vector<std::string>* to_upload) {
[email protected]8764a392012-06-20 06:43:08782 AssertOnSequencedWorkerPool();
[email protected]b83e5202012-06-27 07:50:24783 DCHECK(to_fetch);
784 DCHECK(to_upload);
[email protected]8764a392012-06-20 06:43:08785
[email protected]b83e5202012-06-27 07:50:24786 metadata_->Iterate(base::Bind(&CollectBacklog, to_fetch, to_upload));
[email protected]8764a392012-06-20 06:43:08787}
788
[email protected]fb371812012-08-22 16:05:23789void DriveCache::GetResourceIdsOfExistingPinnedFiles(
[email protected]85b62192012-06-29 19:56:38790 std::vector<std::string>* resource_ids) {
791 AssertOnSequencedWorkerPool();
792 DCHECK(resource_ids);
793
794 metadata_->Iterate(base::Bind(&CollectExistingPinnedFile, resource_ids));
795}
796
[email protected]fb371812012-08-22 16:05:23797void DriveCache::GetResourceIdsOfAllFiles(
[email protected]cd236432012-07-27 18:03:30798 std::vector<std::string>* resource_ids) {
799 AssertOnSequencedWorkerPool();
800 DCHECK(resource_ids);
801
802 metadata_->Iterate(base::Bind(&CollectAnyFile, resource_ids));
803}
804
[email protected]fb371812012-08-22 16:05:23805void DriveCache::GetFile(const std::string& resource_id,
[email protected]c960d222012-06-15 10:03:50806 const std::string& md5,
[email protected]11f60db2012-08-23 16:28:15807 DriveFileError* error,
[email protected]c960d222012-06-15 10:03:50808 FilePath* cache_file_path) {
809 AssertOnSequencedWorkerPool();
810 DCHECK(error);
811 DCHECK(cache_file_path);
812
[email protected]28a64092012-08-21 10:01:12813 DriveCacheEntry cache_entry;
[email protected]b22f87f2012-07-12 10:53:17814 if (GetCacheEntry(resource_id, md5, &cache_entry) &&
[email protected]02821102012-07-12 20:19:17815 cache_entry.is_present()) {
[email protected]c960d222012-06-15 10:03:50816 CachedFileOrigin file_origin;
[email protected]02821102012-07-12 20:19:17817 if (cache_entry.is_mounted()) {
[email protected]c960d222012-06-15 10:03:50818 file_origin = CACHED_FILE_MOUNTED;
[email protected]02821102012-07-12 20:19:17819 } else if (cache_entry.is_dirty()) {
[email protected]c960d222012-06-15 10:03:50820 file_origin = CACHED_FILE_LOCALLY_MODIFIED;
821 } else {
822 file_origin = CACHED_FILE_FROM_SERVER;
823 }
824 *cache_file_path = GetCacheFilePath(
825 resource_id,
826 md5,
[email protected]b22f87f2012-07-12 10:53:17827 GetSubDirectoryType(cache_entry),
[email protected]c960d222012-06-15 10:03:50828 file_origin);
[email protected]11f60db2012-08-23 16:28:15829 *error = DRIVE_FILE_OK;
[email protected]c960d222012-06-15 10:03:50830 } else {
[email protected]11f60db2012-08-23 16:28:15831 *error = DRIVE_FILE_ERROR_NOT_FOUND;
[email protected]c960d222012-06-15 10:03:50832 }
833}
834
[email protected]fb371812012-08-22 16:05:23835void DriveCache::Store(const std::string& resource_id,
[email protected]a321b9632012-06-14 03:29:17836 const std::string& md5,
837 const FilePath& source_path,
838 FileOperationType file_operation_type,
[email protected]11f60db2012-08-23 16:28:15839 DriveFileError* error) {
[email protected]a321b9632012-06-14 03:29:17840 AssertOnSequencedWorkerPool();
841 DCHECK(error);
842
[email protected]f0c67002012-08-15 04:10:38843 if (file_operation_type == FILE_OPERATION_COPY) {
844 int64 file_size;
845 if (!file_util::GetFileSize(source_path, &file_size)) {
846 LOG(WARNING) << "Couldn't get file size for: " << source_path.value();
[email protected]11f60db2012-08-23 16:28:15847 *error = DRIVE_FILE_ERROR_FAILED;
[email protected]f0c67002012-08-15 04:10:38848 return;
849 }
850
851 bool enough_space = false;
852 FreeDiskSpaceIfNeededFor(file_size, &enough_space);
853 if (!enough_space) {
[email protected]11f60db2012-08-23 16:28:15854 *error = DRIVE_FILE_ERROR_NO_SPACE;
[email protected]f0c67002012-08-15 04:10:38855 return;
856 }
857 }
858
[email protected]a321b9632012-06-14 03:29:17859 FilePath dest_path;
860 FilePath symlink_path;
[email protected]a321b9632012-06-14 03:29:17861 CacheSubDirectoryType sub_dir_type = CACHE_TYPE_TMP;
862
[email protected]a321b9632012-06-14 03:29:17863 // If file was previously pinned, store it in persistent dir and create
864 // symlink in pinned dir.
[email protected]28a64092012-08-21 10:01:12865 DriveCacheEntry cache_entry;
[email protected]b22f87f2012-07-12 10:53:17866 if (GetCacheEntry(resource_id, md5, &cache_entry)) { // File exists in cache.
[email protected]a321b9632012-06-14 03:29:17867 // If file is dirty or mounted, return error.
[email protected]02821102012-07-12 20:19:17868 if (cache_entry.is_dirty() || cache_entry.is_mounted()) {
[email protected]a321b9632012-06-14 03:29:17869 LOG(WARNING) << "Can't store a file to replace a "
[email protected]02821102012-07-12 20:19:17870 << (cache_entry.is_dirty() ? "dirty" : "mounted")
[email protected]a321b9632012-06-14 03:29:17871 << " file: res_id=" << resource_id
872 << ", md5=" << md5;
[email protected]11f60db2012-08-23 16:28:15873 *error = DRIVE_FILE_ERROR_IN_USE;
[email protected]a321b9632012-06-14 03:29:17874 return;
875 }
876
[email protected]a321b9632012-06-14 03:29:17877 // If file is pinned, determines destination path.
[email protected]02821102012-07-12 20:19:17878 if (cache_entry.is_pinned()) {
[email protected]a321b9632012-06-14 03:29:17879 sub_dir_type = CACHE_TYPE_PERSISTENT;
880 dest_path = GetCacheFilePath(resource_id, md5, sub_dir_type,
881 CACHED_FILE_FROM_SERVER);
882 symlink_path = GetCacheFilePath(
883 resource_id, std::string(), CACHE_TYPE_PINNED,
884 CACHED_FILE_FROM_SERVER);
885 }
886 }
887
888 // File wasn't pinned or doesn't exist in cache, store in tmp dir.
889 if (dest_path.empty()) {
890 DCHECK_EQ(CACHE_TYPE_TMP, sub_dir_type);
891 dest_path = GetCacheFilePath(resource_id, md5, sub_dir_type,
892 CACHED_FILE_FROM_SERVER);
893 }
894
895 *error = ModifyCacheState(
896 source_path,
897 dest_path,
898 file_operation_type,
899 symlink_path,
900 !symlink_path.empty()); // create symlink
901
[email protected]f60c670b2012-09-13 06:19:25902 // Determine search pattern for stale filenames corresponding to resource_id,
[email protected]a321b9632012-06-14 03:29:17903 // either "<resource_id>*" or "<resource_id>.*".
904 FilePath stale_filenames_pattern;
905 if (md5.empty()) {
906 // No md5 means no extension, append '*' after base name, i.e.
907 // "<resource_id>*".
908 // Cannot call |dest_path|.ReplaceExtension when there's no md5 extension:
909 // if base name of |dest_path| (i.e. escaped resource_id) contains the
910 // extension separator '.', ReplaceExtension will remove it and everything
911 // after it. The result will be nothing like the escaped resource_id.
[email protected]ca5f6da2012-06-18 12:54:59912 stale_filenames_pattern = FilePath(dest_path.value() + util::kWildCard);
[email protected]a321b9632012-06-14 03:29:17913 } else {
914 // Replace md5 extension with '*' i.e. "<resource_id>.*".
915 // Note that ReplaceExtension automatically prefixes the extension with the
916 // extension separator '.'.
[email protected]ca5f6da2012-06-18 12:54:59917 stale_filenames_pattern = dest_path.ReplaceExtension(util::kWildCard);
[email protected]a321b9632012-06-14 03:29:17918 }
919
920 // Delete files that match |stale_filenames_pattern| except for |dest_path|.
921 DeleteFilesSelectively(stale_filenames_pattern, dest_path);
922
[email protected]11f60db2012-08-23 16:28:15923 if (*error == DRIVE_FILE_OK) {
[email protected]a321b9632012-06-14 03:29:17924 // Now that file operations have completed, update cache map.
[email protected]b22f87f2012-07-12 10:53:17925 cache_entry.set_md5(md5);
[email protected]02821102012-07-12 20:19:17926 cache_entry.set_is_present(true);
927 cache_entry.set_is_persistent(sub_dir_type == CACHE_TYPE_PERSISTENT);
[email protected]b22f87f2012-07-12 10:53:17928 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry);
[email protected]a321b9632012-06-14 03:29:17929 }
930}
931
[email protected]fb371812012-08-22 16:05:23932void DriveCache::Pin(const std::string& resource_id,
[email protected]a321b9632012-06-14 03:29:17933 const std::string& md5,
934 FileOperationType file_operation_type,
[email protected]11f60db2012-08-23 16:28:15935 DriveFileError* error) {
[email protected]a321b9632012-06-14 03:29:17936 AssertOnSequencedWorkerPool();
937 DCHECK(error);
938
939 FilePath source_path;
940 FilePath dest_path;
941 FilePath symlink_path;
942 bool create_symlink = true;
[email protected]a321b9632012-06-14 03:29:17943 CacheSubDirectoryType sub_dir_type = CACHE_TYPE_PERSISTENT;
944
[email protected]28a64092012-08-21 10:01:12945 DriveCacheEntry cache_entry;
[email protected]b22f87f2012-07-12 10:53:17946 if (!GetCacheEntry(resource_id, md5, &cache_entry)) {
947 // Entry does not exist in cache.
[email protected]a321b9632012-06-14 03:29:17948 // Set both |dest_path| and |source_path| to /dev/null, so that:
949 // 1) ModifyCacheState won't move files when |source_path| and |dest_path|
950 // are the same.
[email protected]9935913b2012-09-06 14:09:57951 // 2) symlinks to /dev/null will be picked up by DriveSyncClient to download
[email protected]a321b9632012-06-14 03:29:17952 // pinned files that don't exist in cache.
[email protected]30d9dda2012-06-30 05:56:28953 dest_path = FilePath::FromUTF8Unsafe(util::kSymLinkToDevNull);
[email protected]a321b9632012-06-14 03:29:17954 source_path = dest_path;
955
[email protected]2a6fe6e2012-07-10 06:01:04956 // Set sub_dir_type to TMP. The file will be first downloaded in 'tmp',
957 // then moved to 'persistent'.
958 sub_dir_type = CACHE_TYPE_TMP;
[email protected]109eb5c2012-07-12 03:20:05959 } else { // File exists in cache, determines destination path.
[email protected]a321b9632012-06-14 03:29:17960 // Determine source and destination paths.
961
962 // If file is dirty or mounted, don't move it, so determine |dest_path| and
963 // set |source_path| the same, because ModifyCacheState only moves files if
964 // source and destination are different.
[email protected]02821102012-07-12 20:19:17965 if (cache_entry.is_dirty() || cache_entry.is_mounted()) {
966 DCHECK(cache_entry.is_persistent());
[email protected]a321b9632012-06-14 03:29:17967 dest_path = GetCacheFilePath(resource_id,
968 md5,
[email protected]b22f87f2012-07-12 10:53:17969 GetSubDirectoryType(cache_entry),
[email protected]a321b9632012-06-14 03:29:17970 CACHED_FILE_LOCALLY_MODIFIED);
971 source_path = dest_path;
972 } else {
973 // Gets the current path of the file in cache.
974 source_path = GetCacheFilePath(resource_id,
975 md5,
[email protected]b22f87f2012-07-12 10:53:17976 GetSubDirectoryType(cache_entry),
[email protected]a321b9632012-06-14 03:29:17977 CACHED_FILE_FROM_SERVER);
978
979 // If file was pinned before but actual file blob doesn't exist in cache:
980 // - don't need to move the file, so set |dest_path| to |source_path|,
981 // because ModifyCacheState only moves files if source and destination
982 // are different
983 // - don't create symlink since it already exists.
[email protected]02821102012-07-12 20:19:17984 if (!cache_entry.is_present()) {
[email protected]a321b9632012-06-14 03:29:17985 dest_path = source_path;
986 create_symlink = false;
987 } else { // File exists, move it to persistent dir.
988 dest_path = GetCacheFilePath(resource_id,
989 md5,
990 CACHE_TYPE_PERSISTENT,
991 CACHED_FILE_FROM_SERVER);
992 }
993 }
994 }
995
996 // Create symlink in pinned dir.
997 if (create_symlink) {
998 symlink_path = GetCacheFilePath(resource_id,
999 std::string(),
1000 CACHE_TYPE_PINNED,
1001 CACHED_FILE_FROM_SERVER);
1002 }
1003
1004 *error = ModifyCacheState(source_path,
1005 dest_path,
1006 file_operation_type,
1007 symlink_path,
1008 create_symlink);
1009
[email protected]11f60db2012-08-23 16:28:151010 if (*error == DRIVE_FILE_OK) {
[email protected]a321b9632012-06-14 03:29:171011 // Now that file operations have completed, update cache map.
[email protected]b22f87f2012-07-12 10:53:171012 cache_entry.set_md5(md5);
[email protected]02821102012-07-12 20:19:171013 cache_entry.set_is_pinned(true);
1014 cache_entry.set_is_persistent(sub_dir_type == CACHE_TYPE_PERSISTENT);
[email protected]b22f87f2012-07-12 10:53:171015 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry);
[email protected]a321b9632012-06-14 03:29:171016 }
1017}
1018
[email protected]fb371812012-08-22 16:05:231019void DriveCache::Unpin(const std::string& resource_id,
[email protected]a321b9632012-06-14 03:29:171020 const std::string& md5,
1021 FileOperationType file_operation_type,
[email protected]11f60db2012-08-23 16:28:151022 DriveFileError* error) {
[email protected]a321b9632012-06-14 03:29:171023 AssertOnSequencedWorkerPool();
1024 DCHECK(error);
1025
[email protected]a321b9632012-06-14 03:29:171026 // Unpinning a file means its entry must exist in cache.
[email protected]28a64092012-08-21 10:01:121027 DriveCacheEntry cache_entry;
[email protected]b22f87f2012-07-12 10:53:171028 if (!GetCacheEntry(resource_id, md5, &cache_entry)) {
[email protected]a321b9632012-06-14 03:29:171029 LOG(WARNING) << "Can't unpin a file that wasn't pinned or cached: res_id="
1030 << resource_id
1031 << ", md5=" << md5;
[email protected]11f60db2012-08-23 16:28:151032 *error = DRIVE_FILE_ERROR_NOT_FOUND;
[email protected]a321b9632012-06-14 03:29:171033 return;
1034 }
1035
1036 // Entry exists in cache, determines source and destination paths.
1037
1038 FilePath source_path;
1039 FilePath dest_path;
1040 CacheSubDirectoryType sub_dir_type = CACHE_TYPE_TMP;
1041
1042 // If file is dirty or mounted, don't move it, so determine |dest_path| and
1043 // set |source_path| the same, because ModifyCacheState moves files if source
1044 // and destination are different.
[email protected]02821102012-07-12 20:19:171045 if (cache_entry.is_dirty() || cache_entry.is_mounted()) {
[email protected]a321b9632012-06-14 03:29:171046 sub_dir_type = CACHE_TYPE_PERSISTENT;
[email protected]02821102012-07-12 20:19:171047 DCHECK(cache_entry.is_persistent());
[email protected]a321b9632012-06-14 03:29:171048 dest_path = GetCacheFilePath(resource_id,
1049 md5,
[email protected]b22f87f2012-07-12 10:53:171050 GetSubDirectoryType(cache_entry),
[email protected]a321b9632012-06-14 03:29:171051 CACHED_FILE_LOCALLY_MODIFIED);
1052 source_path = dest_path;
1053 } else {
1054 // Gets the current path of the file in cache.
1055 source_path = GetCacheFilePath(resource_id,
1056 md5,
[email protected]b22f87f2012-07-12 10:53:171057 GetSubDirectoryType(cache_entry),
[email protected]a321b9632012-06-14 03:29:171058 CACHED_FILE_FROM_SERVER);
1059
1060 // If file was pinned but actual file blob still doesn't exist in cache,
1061 // don't need to move the file, so set |dest_path| to |source_path|, because
1062 // ModifyCacheState only moves files if source and destination are
1063 // different.
[email protected]02821102012-07-12 20:19:171064 if (!cache_entry.is_present()) {
[email protected]a321b9632012-06-14 03:29:171065 dest_path = source_path;
1066 } else { // File exists, move it to tmp dir.
1067 dest_path = GetCacheFilePath(resource_id, md5,
1068 CACHE_TYPE_TMP,
1069 CACHED_FILE_FROM_SERVER);
1070 }
1071 }
1072
1073 // If file was pinned, get absolute path of symlink in pinned dir so as to
1074 // remove it.
1075 FilePath symlink_path;
[email protected]02821102012-07-12 20:19:171076 if (cache_entry.is_pinned()) {
[email protected]a321b9632012-06-14 03:29:171077 symlink_path = GetCacheFilePath(resource_id,
1078 std::string(),
1079 CACHE_TYPE_PINNED,
1080 CACHED_FILE_FROM_SERVER);
1081 }
1082
1083 *error = ModifyCacheState(
1084 source_path,
1085 dest_path,
1086 file_operation_type,
1087 symlink_path, // This will be deleted if it exists.
1088 false /* don't create symlink*/);
1089
[email protected]11f60db2012-08-23 16:28:151090 if (*error == DRIVE_FILE_OK) {
[email protected]a321b9632012-06-14 03:29:171091 // Now that file operations have completed, update cache map.
[email protected]02821102012-07-12 20:19:171092 if (cache_entry.is_present()) {
[email protected]48477fe2012-07-12 17:45:081093 cache_entry.set_md5(md5);
[email protected]02821102012-07-12 20:19:171094 cache_entry.set_is_pinned(false);
1095 cache_entry.set_is_persistent(sub_dir_type == CACHE_TYPE_PERSISTENT);
[email protected]48477fe2012-07-12 17:45:081096 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry);
[email protected]3423871a2012-07-12 00:41:271097 } else {
1098 // Remove the existing entry if we are unpinning a non-present file.
1099 metadata_->RemoveCacheEntry(resource_id);
1100 }
[email protected]a321b9632012-06-14 03:29:171101 }
1102}
1103
[email protected]fb371812012-08-22 16:05:231104void DriveCache::SetMountedState(const FilePath& file_path,
[email protected]a321b9632012-06-14 03:29:171105 bool to_mount,
[email protected]11f60db2012-08-23 16:28:151106 DriveFileError *error,
[email protected]a321b9632012-06-14 03:29:171107 FilePath* cache_file_path) {
1108 AssertOnSequencedWorkerPool();
1109 DCHECK(error);
1110 DCHECK(cache_file_path);
1111
1112 // Parse file path to obtain resource_id, md5 and extra_extension.
1113 std::string resource_id;
1114 std::string md5;
1115 std::string extra_extension;
1116 util::ParseCacheFilePath(file_path, &resource_id, &md5, &extra_extension);
1117 // The extra_extension shall be ".mounted" iff we're unmounting.
[email protected]ca5f6da2012-06-18 12:54:591118 DCHECK(!to_mount == (extra_extension == util::kMountedArchiveFileExtension));
[email protected]a321b9632012-06-14 03:29:171119
1120 // Get cache entry associated with the resource_id and md5
[email protected]28a64092012-08-21 10:01:121121 DriveCacheEntry cache_entry;
[email protected]b22f87f2012-07-12 10:53:171122 if (!GetCacheEntry(resource_id, md5, &cache_entry)) {
[email protected]11f60db2012-08-23 16:28:151123 *error = DRIVE_FILE_ERROR_NOT_FOUND;
[email protected]a321b9632012-06-14 03:29:171124 return;
1125 }
[email protected]02821102012-07-12 20:19:171126 if (to_mount == cache_entry.is_mounted()) {
[email protected]11f60db2012-08-23 16:28:151127 *error = DRIVE_FILE_ERROR_INVALID_OPERATION;
[email protected]a321b9632012-06-14 03:29:171128 return;
1129 }
1130
1131 // Get the subdir type and path for the unmounted state.
1132 CacheSubDirectoryType unmounted_subdir =
[email protected]02821102012-07-12 20:19:171133 cache_entry.is_pinned() ? CACHE_TYPE_PERSISTENT : CACHE_TYPE_TMP;
[email protected]a321b9632012-06-14 03:29:171134 FilePath unmounted_path = GetCacheFilePath(
1135 resource_id, md5, unmounted_subdir, CACHED_FILE_FROM_SERVER);
1136
1137 // Get the subdir type and path for the mounted state.
1138 CacheSubDirectoryType mounted_subdir = CACHE_TYPE_PERSISTENT;
1139 FilePath mounted_path = GetCacheFilePath(
1140 resource_id, md5, mounted_subdir, CACHED_FILE_MOUNTED);
1141
1142 // Determine the source and destination paths for moving the cache blob.
1143 FilePath source_path;
1144 CacheSubDirectoryType dest_subdir;
[email protected]a321b9632012-06-14 03:29:171145 if (to_mount) {
1146 source_path = unmounted_path;
1147 *cache_file_path = mounted_path;
1148 dest_subdir = mounted_subdir;
[email protected]02821102012-07-12 20:19:171149 cache_entry.set_is_mounted(true);
[email protected]a321b9632012-06-14 03:29:171150 } else {
1151 source_path = mounted_path;
1152 *cache_file_path = unmounted_path;
1153 dest_subdir = unmounted_subdir;
[email protected]02821102012-07-12 20:19:171154 cache_entry.set_is_mounted(false);
[email protected]a321b9632012-06-14 03:29:171155 }
1156
1157 // Move cache blob from source path to destination path.
1158 *error = ModifyCacheState(source_path, *cache_file_path,
1159 FILE_OPERATION_MOVE, FilePath(), false);
[email protected]11f60db2012-08-23 16:28:151160 if (*error == DRIVE_FILE_OK) {
[email protected]a321b9632012-06-14 03:29:171161 // Now that cache operation is complete, update cache map
[email protected]48477fe2012-07-12 17:45:081162 cache_entry.set_md5(md5);
[email protected]02821102012-07-12 20:19:171163 cache_entry.set_is_persistent(dest_subdir == CACHE_TYPE_PERSISTENT);
[email protected]48477fe2012-07-12 17:45:081164 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry);
[email protected]a321b9632012-06-14 03:29:171165 }
1166}
1167
[email protected]fb371812012-08-22 16:05:231168void DriveCache::MarkDirty(const std::string& resource_id,
[email protected]c960d222012-06-15 10:03:501169 const std::string& md5,
1170 FileOperationType file_operation_type,
[email protected]11f60db2012-08-23 16:28:151171 DriveFileError* error,
[email protected]c960d222012-06-15 10:03:501172 FilePath* cache_file_path) {
1173 AssertOnSequencedWorkerPool();
1174 DCHECK(error);
1175 DCHECK(cache_file_path);
1176
1177 // If file has already been marked dirty in previous instance of chrome, we
1178 // would have lost the md5 info during cache initialization, because the file
1179 // would have been renamed to .local extension.
1180 // So, search for entry in cache without comparing md5.
[email protected]c960d222012-06-15 10:03:501181
1182 // Marking a file dirty means its entry and actual file blob must exist in
1183 // cache.
[email protected]28a64092012-08-21 10:01:121184 DriveCacheEntry cache_entry;
[email protected]b22f87f2012-07-12 10:53:171185 if (!GetCacheEntry(resource_id, std::string(), &cache_entry) ||
[email protected]02821102012-07-12 20:19:171186 !cache_entry.is_present()) {
[email protected]c960d222012-06-15 10:03:501187 LOG(WARNING) << "Can't mark dirty a file that wasn't cached: res_id="
1188 << resource_id
1189 << ", md5=" << md5;
[email protected]11f60db2012-08-23 16:28:151190 *error = DRIVE_FILE_ERROR_NOT_FOUND;
[email protected]c960d222012-06-15 10:03:501191 return;
1192 }
1193
1194 // If a file is already dirty (i.e. MarkDirtyInCache was called before),
1195 // delete outgoing symlink if it exists.
1196 // TODO(benchan): We should only delete outgoing symlink if file is currently
1197 // not being uploaded. However, for now, cache doesn't know if uploading of a
1198 // file is in progress. Per zel, the upload process should be canceled before
1199 // MarkDirtyInCache is called again.
[email protected]02821102012-07-12 20:19:171200 if (cache_entry.is_dirty()) {
[email protected]c960d222012-06-15 10:03:501201 // The file must be in persistent dir.
[email protected]02821102012-07-12 20:19:171202 DCHECK(cache_entry.is_persistent());
[email protected]c960d222012-06-15 10:03:501203
1204 // Determine symlink path in outgoing dir, so as to remove it.
1205 FilePath symlink_path = GetCacheFilePath(
1206 resource_id,
1207 std::string(),
1208 CACHE_TYPE_OUTGOING,
1209 CACHED_FILE_FROM_SERVER);
1210
1211 // We're not moving files here, so simply use empty FilePath for both
1212 // |source_path| and |dest_path| because ModifyCacheState only move files
1213 // if source and destination are different.
1214 *error = ModifyCacheState(
1215 FilePath(), // non-applicable source path
1216 FilePath(), // non-applicable dest path
1217 file_operation_type,
1218 symlink_path,
1219 false /* don't create symlink */);
1220
1221 // Determine current path of dirty file.
[email protected]11f60db2012-08-23 16:28:151222 if (*error == DRIVE_FILE_OK) {
[email protected]c960d222012-06-15 10:03:501223 *cache_file_path = GetCacheFilePath(
1224 resource_id,
1225 md5,
1226 CACHE_TYPE_PERSISTENT,
1227 CACHED_FILE_LOCALLY_MODIFIED);
1228 }
1229 return;
1230 }
1231
1232 // Move file to persistent dir with new .local extension.
1233
1234 // Get the current path of the file in cache.
1235 FilePath source_path = GetCacheFilePath(
1236 resource_id,
1237 md5,
[email protected]b22f87f2012-07-12 10:53:171238 GetSubDirectoryType(cache_entry),
[email protected]c960d222012-06-15 10:03:501239 CACHED_FILE_FROM_SERVER);
1240
1241 // Determine destination path.
[email protected]3dc88ee2012-07-11 21:04:111242 const CacheSubDirectoryType sub_dir_type = CACHE_TYPE_PERSISTENT;
[email protected]c960d222012-06-15 10:03:501243 *cache_file_path = GetCacheFilePath(resource_id,
1244 md5,
1245 sub_dir_type,
1246 CACHED_FILE_LOCALLY_MODIFIED);
1247
1248 // If file is pinned, update symlink in pinned dir.
1249 FilePath symlink_path;
[email protected]02821102012-07-12 20:19:171250 if (cache_entry.is_pinned()) {
[email protected]c960d222012-06-15 10:03:501251 symlink_path = GetCacheFilePath(resource_id,
1252 std::string(),
1253 CACHE_TYPE_PINNED,
1254 CACHED_FILE_FROM_SERVER);
1255 }
1256
1257 *error = ModifyCacheState(
1258 source_path,
1259 *cache_file_path,
1260 file_operation_type,
1261 symlink_path,
1262 !symlink_path.empty() /* create symlink */);
1263
[email protected]11f60db2012-08-23 16:28:151264 if (*error == DRIVE_FILE_OK) {
[email protected]c960d222012-06-15 10:03:501265 // Now that file operations have completed, update cache map.
[email protected]48477fe2012-07-12 17:45:081266 cache_entry.set_md5(md5);
[email protected]02821102012-07-12 20:19:171267 cache_entry.set_is_dirty(true);
1268 cache_entry.set_is_persistent(sub_dir_type == CACHE_TYPE_PERSISTENT);
[email protected]48477fe2012-07-12 17:45:081269 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry);
[email protected]c960d222012-06-15 10:03:501270 }
1271}
1272
[email protected]fb371812012-08-22 16:05:231273void DriveCache::CommitDirty(const std::string& resource_id,
[email protected]a321b9632012-06-14 03:29:171274 const std::string& md5,
1275 FileOperationType file_operation_type,
[email protected]11f60db2012-08-23 16:28:151276 DriveFileError* error) {
[email protected]a321b9632012-06-14 03:29:171277 AssertOnSequencedWorkerPool();
1278 DCHECK(error);
1279
1280 // If file has already been marked dirty in previous instance of chrome, we
1281 // would have lost the md5 info during cache initialization, because the file
1282 // would have been renamed to .local extension.
1283 // So, search for entry in cache without comparing md5.
[email protected]a321b9632012-06-14 03:29:171284
1285 // Committing a file dirty means its entry and actual file blob must exist in
1286 // cache.
[email protected]28a64092012-08-21 10:01:121287 DriveCacheEntry cache_entry;
[email protected]b22f87f2012-07-12 10:53:171288 if (!GetCacheEntry(resource_id, std::string(), &cache_entry) ||
[email protected]02821102012-07-12 20:19:171289 !cache_entry.is_present()) {
[email protected]a321b9632012-06-14 03:29:171290 LOG(WARNING) << "Can't commit dirty a file that wasn't cached: res_id="
1291 << resource_id
1292 << ", md5=" << md5;
[email protected]11f60db2012-08-23 16:28:151293 *error = DRIVE_FILE_ERROR_NOT_FOUND;
[email protected]a321b9632012-06-14 03:29:171294 return;
1295 }
1296
1297 // If a file is not dirty (it should have been marked dirty via
1298 // MarkDirtyInCache), committing it dirty is an invalid operation.
[email protected]02821102012-07-12 20:19:171299 if (!cache_entry.is_dirty()) {
[email protected]a321b9632012-06-14 03:29:171300 LOG(WARNING) << "Can't commit a non-dirty file: res_id="
1301 << resource_id
1302 << ", md5=" << md5;
[email protected]11f60db2012-08-23 16:28:151303 *error = DRIVE_FILE_ERROR_INVALID_OPERATION;
[email protected]a321b9632012-06-14 03:29:171304 return;
1305 }
1306
1307 // Dirty files must be in persistent dir.
[email protected]02821102012-07-12 20:19:171308 DCHECK(cache_entry.is_persistent());
[email protected]a321b9632012-06-14 03:29:171309
1310 // Create symlink in outgoing dir.
1311 FilePath symlink_path = GetCacheFilePath(resource_id,
1312 std::string(),
1313 CACHE_TYPE_OUTGOING,
1314 CACHED_FILE_FROM_SERVER);
1315
1316 // Get target path of symlink i.e. current path of the file in cache.
1317 FilePath target_path = GetCacheFilePath(resource_id,
1318 md5,
[email protected]b22f87f2012-07-12 10:53:171319 GetSubDirectoryType(cache_entry),
[email protected]a321b9632012-06-14 03:29:171320 CACHED_FILE_LOCALLY_MODIFIED);
1321
1322 // Since there's no need to move files, use |target_path| for both
1323 // |source_path| and |dest_path|, because ModifyCacheState only moves files
1324 // if source and destination are different.
1325 *error = ModifyCacheState(target_path, // source
1326 target_path, // destination
1327 file_operation_type,
1328 symlink_path,
1329 true /* create symlink */);
1330}
1331
[email protected]fb371812012-08-22 16:05:231332void DriveCache::ClearDirty(const std::string& resource_id,
[email protected]a321b9632012-06-14 03:29:171333 const std::string& md5,
1334 FileOperationType file_operation_type,
[email protected]11f60db2012-08-23 16:28:151335 DriveFileError* error) {
[email protected]a321b9632012-06-14 03:29:171336 AssertOnSequencedWorkerPool();
1337 DCHECK(error);
1338
1339 // |md5| is the new .<md5> extension to rename the file to.
1340 // So, search for entry in cache without comparing md5.
[email protected]28a64092012-08-21 10:01:121341 DriveCacheEntry cache_entry;
[email protected]a321b9632012-06-14 03:29:171342
1343 // Clearing a dirty file means its entry and actual file blob must exist in
1344 // cache.
[email protected]b22f87f2012-07-12 10:53:171345 if (!GetCacheEntry(resource_id, std::string(), &cache_entry) ||
[email protected]02821102012-07-12 20:19:171346 !cache_entry.is_present()) {
[email protected]a321b9632012-06-14 03:29:171347 LOG(WARNING) << "Can't clear dirty state of a file that wasn't cached: "
1348 << "res_id=" << resource_id
1349 << ", md5=" << md5;
[email protected]11f60db2012-08-23 16:28:151350 *error = DRIVE_FILE_ERROR_NOT_FOUND;
[email protected]a321b9632012-06-14 03:29:171351 return;
1352 }
1353
1354 // If a file is not dirty (it should have been marked dirty via
1355 // MarkDirtyInCache), clearing its dirty state is an invalid operation.
[email protected]02821102012-07-12 20:19:171356 if (!cache_entry.is_dirty()) {
[email protected]a321b9632012-06-14 03:29:171357 LOG(WARNING) << "Can't clear dirty state of a non-dirty file: res_id="
1358 << resource_id
1359 << ", md5=" << md5;
[email protected]11f60db2012-08-23 16:28:151360 *error = DRIVE_FILE_ERROR_INVALID_OPERATION;
[email protected]a321b9632012-06-14 03:29:171361 return;
1362 }
1363
1364 // File must be dirty and hence in persistent dir.
[email protected]02821102012-07-12 20:19:171365 DCHECK(cache_entry.is_persistent());
[email protected]a321b9632012-06-14 03:29:171366
1367 // Get the current path of the file in cache.
1368 FilePath source_path = GetCacheFilePath(resource_id,
1369 md5,
[email protected]b22f87f2012-07-12 10:53:171370 GetSubDirectoryType(cache_entry),
[email protected]a321b9632012-06-14 03:29:171371 CACHED_FILE_LOCALLY_MODIFIED);
1372
1373 // Determine destination path.
1374 // If file is pinned, move it to persistent dir with .md5 extension;
1375 // otherwise, move it to tmp dir with .md5 extension.
[email protected]3dc88ee2012-07-11 21:04:111376 const CacheSubDirectoryType sub_dir_type =
[email protected]02821102012-07-12 20:19:171377 cache_entry.is_pinned() ? CACHE_TYPE_PERSISTENT : CACHE_TYPE_TMP;
[email protected]a321b9632012-06-14 03:29:171378 FilePath dest_path = GetCacheFilePath(resource_id,
1379 md5,
1380 sub_dir_type,
1381 CACHED_FILE_FROM_SERVER);
1382
1383 // Delete symlink in outgoing dir.
1384 FilePath symlink_path = GetCacheFilePath(resource_id,
1385 std::string(),
1386 CACHE_TYPE_OUTGOING,
1387 CACHED_FILE_FROM_SERVER);
1388
1389 *error = ModifyCacheState(source_path,
1390 dest_path,
1391 file_operation_type,
1392 symlink_path,
1393 false /* don't create symlink */);
1394
1395 // If file is pinned, update symlink in pinned dir.
[email protected]11f60db2012-08-23 16:28:151396 if (*error == DRIVE_FILE_OK && cache_entry.is_pinned()) {
[email protected]a321b9632012-06-14 03:29:171397 symlink_path = GetCacheFilePath(resource_id,
1398 std::string(),
1399 CACHE_TYPE_PINNED,
1400 CACHED_FILE_FROM_SERVER);
1401
1402 // Since there's no moving of files here, use |dest_path| for both
1403 // |source_path| and |dest_path|, because ModifyCacheState only moves files
1404 // if source and destination are different.
1405 *error = ModifyCacheState(dest_path, // source path
1406 dest_path, // destination path
1407 file_operation_type,
1408 symlink_path,
1409 true /* create symlink */);
1410 }
1411
[email protected]11f60db2012-08-23 16:28:151412 if (*error == DRIVE_FILE_OK) {
[email protected]a321b9632012-06-14 03:29:171413 // Now that file operations have completed, update cache map.
[email protected]48477fe2012-07-12 17:45:081414 cache_entry.set_md5(md5);
[email protected]02821102012-07-12 20:19:171415 cache_entry.set_is_dirty(false);
1416 cache_entry.set_is_persistent(sub_dir_type == CACHE_TYPE_PERSISTENT);
[email protected]48477fe2012-07-12 17:45:081417 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry);
[email protected]a321b9632012-06-14 03:29:171418 }
1419}
1420
[email protected]fb371812012-08-22 16:05:231421void DriveCache::Remove(const std::string& resource_id,
[email protected]11f60db2012-08-23 16:28:151422 DriveFileError* error) {
[email protected]a321b9632012-06-14 03:29:171423 AssertOnSequencedWorkerPool();
1424 DCHECK(error);
1425
[email protected]3423871a2012-07-12 00:41:271426 // MD5 is not passed into RemoveCacheEntry because we would delete all
1427 // cache files corresponding to <resource_id> regardless of the md5.
[email protected]a321b9632012-06-14 03:29:171428 // So, search for entry in cache without taking md5 into account.
[email protected]28a64092012-08-21 10:01:121429 DriveCacheEntry cache_entry;
[email protected]a321b9632012-06-14 03:29:171430
1431 // If entry doesn't exist or is dirty or mounted in cache, nothing to do.
[email protected]b22f87f2012-07-12 10:53:171432 const bool entry_found =
1433 GetCacheEntry(resource_id, std::string(), &cache_entry);
[email protected]02821102012-07-12 20:19:171434 if (!entry_found || cache_entry.is_dirty() || cache_entry.is_mounted()) {
[email protected]a321b9632012-06-14 03:29:171435 DVLOG(1) << "Entry is "
[email protected]b22f87f2012-07-12 10:53:171436 << (entry_found ?
[email protected]02821102012-07-12 20:19:171437 (cache_entry.is_dirty() ? "dirty" : "mounted") :
[email protected]a321b9632012-06-14 03:29:171438 "non-existent")
1439 << " in cache, not removing";
[email protected]11f60db2012-08-23 16:28:151440 *error = DRIVE_FILE_OK;
[email protected]a321b9632012-06-14 03:29:171441 return;
1442 }
1443
1444 // Determine paths to delete all cache versions of |resource_id| in
1445 // persistent, tmp and pinned directories.
1446 std::vector<FilePath> paths_to_delete;
1447
1448 // For files in persistent and tmp dirs, delete files that match
1449 // "<resource_id>.*".
1450 paths_to_delete.push_back(GetCacheFilePath(resource_id,
[email protected]ca5f6da2012-06-18 12:54:591451 util::kWildCard,
[email protected]a321b9632012-06-14 03:29:171452 CACHE_TYPE_PERSISTENT,
1453 CACHED_FILE_FROM_SERVER));
1454 paths_to_delete.push_back(GetCacheFilePath(resource_id,
[email protected]ca5f6da2012-06-18 12:54:591455 util::kWildCard,
[email protected]a321b9632012-06-14 03:29:171456 CACHE_TYPE_TMP,
1457 CACHED_FILE_FROM_SERVER));
1458
1459 // For pinned files, filename is "<resource_id>" with no extension, so delete
1460 // "<resource_id>".
1461 paths_to_delete.push_back(GetCacheFilePath(resource_id,
1462 std::string(),
1463 CACHE_TYPE_PINNED,
1464 CACHED_FILE_FROM_SERVER));
1465
1466 // Don't delete locally modified (i.e. dirty and possibly outgoing) files.
1467 // Since we're not deleting outgoing symlinks, we don't need to append
1468 // outgoing path to |paths_to_delete|.
1469 FilePath path_to_keep = GetCacheFilePath(resource_id,
1470 std::string(),
1471 CACHE_TYPE_PERSISTENT,
1472 CACHED_FILE_LOCALLY_MODIFIED);
1473
1474 for (size_t i = 0; i < paths_to_delete.size(); ++i) {
1475 DeleteFilesSelectively(paths_to_delete[i], path_to_keep);
1476 }
1477
1478 // Now that all file operations have completed, remove from cache map.
[email protected]3423871a2012-07-12 00:41:271479 metadata_->RemoveCacheEntry(resource_id);
[email protected]a321b9632012-06-14 03:29:171480
[email protected]11f60db2012-08-23 16:28:151481 *error = DRIVE_FILE_OK;
[email protected]a321b9632012-06-14 03:29:171482}
1483
[email protected]11f60db2012-08-23 16:28:151484void DriveCache::ClearAll(DriveFileError* error) {
[email protected]f861b392012-08-03 20:41:121485 AssertOnSequencedWorkerPool();
1486 DCHECK(error);
1487
1488 bool success = file_util::Delete(cache_root_path_, true);
[email protected]322e0032012-10-07 01:55:531489 if (!success) {
1490 LOG(WARNING) << "Failed to delete the cache directory";
1491 *error = DRIVE_FILE_ERROR_FAILED;
1492 return;
1493 }
[email protected]f861b392012-08-03 20:41:121494
[email protected]322e0032012-10-07 01:55:531495 Initialize(&success);
1496 if (!success) {
1497 LOG(WARNING) << "Failed to initialize the cache";
1498 *error = DRIVE_FILE_ERROR_FAILED;
1499 return;
1500 }
1501
1502 *error = DRIVE_FILE_OK;
1503 return;
[email protected]f861b392012-08-03 20:41:121504}
1505
[email protected]11f60db2012-08-23 16:28:151506void DriveCache::OnPinned(DriveFileError* error,
[email protected]73f9c742012-06-15 07:37:131507 const std::string& resource_id,
1508 const std::string& md5,
1509 const CacheOperationCallback& callback) {
1510 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1511 DCHECK(error);
1512
1513 if (!callback.is_null())
1514 callback.Run(*error, resource_id, md5);
1515
[email protected]11f60db2012-08-23 16:28:151516 if (*error == DRIVE_FILE_OK)
[email protected]a09275502012-10-10 04:48:011517 FOR_EACH_OBSERVER(DriveCacheObserver,
1518 observers_,
1519 OnCachePinned(resource_id, md5));
[email protected]3653146a2012-05-29 13:41:471520}
1521
[email protected]11f60db2012-08-23 16:28:151522void DriveCache::OnUnpinned(DriveFileError* error,
[email protected]73f9c742012-06-15 07:37:131523 const std::string& resource_id,
1524 const std::string& md5,
1525 const CacheOperationCallback& callback) {
1526 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1527 DCHECK(error);
[email protected]a321b9632012-06-14 03:29:171528
[email protected]73f9c742012-06-15 07:37:131529 if (!callback.is_null())
1530 callback.Run(*error, resource_id, md5);
[email protected]a321b9632012-06-14 03:29:171531
[email protected]11f60db2012-08-23 16:28:151532 if (*error == DRIVE_FILE_OK)
[email protected]a09275502012-10-10 04:48:011533 FOR_EACH_OBSERVER(DriveCacheObserver,
1534 observers_,
1535 OnCacheUnpinned(resource_id, md5));
[email protected]a321b9632012-06-14 03:29:171536
[email protected]73f9c742012-06-15 07:37:131537 // Now the file is moved from "persistent" to "tmp" directory.
1538 // It's a chance to free up space if needed.
1539 bool* has_enough_space = new bool(false);
[email protected]ddbf2052012-07-13 15:07:021540 blocking_task_runner_->PostTask(
[email protected]73f9c742012-06-15 07:37:131541 FROM_HERE,
[email protected]fb371812012-08-22 16:05:231542 base::Bind(&DriveCache::FreeDiskSpaceIfNeededFor,
[email protected]73f9c742012-06-15 07:37:131543 base::Unretained(this),
1544 0,
1545 base::Owned(has_enough_space)));
[email protected]3653146a2012-05-29 13:41:471546}
1547
[email protected]11f60db2012-08-23 16:28:151548void DriveCache::OnCommitDirty(DriveFileError* error,
[email protected]d7664c22012-06-18 19:35:491549 const std::string& resource_id,
1550 const std::string& md5,
1551 const CacheOperationCallback& callback) {
1552 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1553 DCHECK(error);
1554
1555 if (!callback.is_null())
1556 callback.Run(*error, resource_id, md5);
1557
[email protected]11f60db2012-08-23 16:28:151558 if (*error == DRIVE_FILE_OK)
[email protected]a09275502012-10-10 04:48:011559 FOR_EACH_OBSERVER(DriveCacheObserver,
1560 observers_,
1561 OnCacheCommitted(resource_id));
[email protected]d7664c22012-06-18 19:35:491562}
1563
[email protected]fb371812012-08-22 16:05:231564void DriveCache::GetCacheEntryHelper(const std::string& resource_id,
[email protected]4324fdc2012-06-29 05:32:481565 const std::string& md5,
1566 bool* success,
[email protected]28a64092012-08-21 10:01:121567 DriveCacheEntry* cache_entry) {
[email protected]4324fdc2012-06-29 05:32:481568 AssertOnSequencedWorkerPool();
1569 DCHECK(success);
1570 DCHECK(cache_entry);
1571
[email protected]b22f87f2012-07-12 10:53:171572 *success = GetCacheEntry(resource_id, md5, cache_entry);
[email protected]4324fdc2012-06-29 05:32:481573}
1574
[email protected]01ba15f72012-06-09 00:41:051575// static
[email protected]fb371812012-08-22 16:05:231576FilePath DriveCache::GetCacheRootPath(Profile* profile) {
[email protected]01ba15f72012-06-09 00:41:051577 FilePath cache_base_path;
1578 chrome::GetUserCacheDirectory(profile->GetPath(), &cache_base_path);
1579 FilePath cache_root_path =
[email protected]fb371812012-08-22 16:05:231580 cache_base_path.Append(chrome::kDriveCacheDirname);
1581 return cache_root_path.Append(kDriveCacheVersionDir);
[email protected]01ba15f72012-06-09 00:41:051582}
1583
[email protected]30d9dda2012-06-30 05:56:281584// static
[email protected]fb371812012-08-22 16:05:231585std::vector<FilePath> DriveCache::GetCachePaths(
[email protected]30d9dda2012-06-30 05:56:281586 const FilePath& cache_root_path) {
1587 std::vector<FilePath> cache_paths;
[email protected]fb371812012-08-22 16:05:231588 // The order should match DriveCache::CacheSubDirectoryType enum.
1589 cache_paths.push_back(cache_root_path.Append(kDriveCacheMetaDir));
1590 cache_paths.push_back(cache_root_path.Append(kDriveCachePinnedDir));
1591 cache_paths.push_back(cache_root_path.Append(kDriveCacheOutgoingDir));
1592 cache_paths.push_back(cache_root_path.Append(kDriveCachePersistentDir));
1593 cache_paths.push_back(cache_root_path.Append(kDriveCacheTmpDir));
1594 cache_paths.push_back(cache_root_path.Append(kDriveCacheTmpDownloadsDir));
1595 cache_paths.push_back(cache_root_path.Append(kDriveCacheTmpDocumentsDir));
[email protected]30d9dda2012-06-30 05:56:281596 return cache_paths;
1597}
1598
1599// static
[email protected]fb371812012-08-22 16:05:231600bool DriveCache::CreateCacheDirectories(
[email protected]30d9dda2012-06-30 05:56:281601 const std::vector<FilePath>& paths_to_create) {
1602 bool success = true;
1603
1604 for (size_t i = 0; i < paths_to_create.size(); ++i) {
1605 if (file_util::DirectoryExists(paths_to_create[i]))
1606 continue;
1607
1608 if (!file_util::CreateDirectory(paths_to_create[i])) {
1609 // Error creating this directory, record error and proceed with next one.
1610 success = false;
1611 PLOG(ERROR) << "Error creating directory " << paths_to_create[i].value();
1612 } else {
1613 DVLOG(1) << "Created directory " << paths_to_create[i].value();
1614 }
1615 }
1616 return success;
1617}
1618
[email protected]fae353a2012-07-11 23:30:271619// static
[email protected]fb371812012-08-22 16:05:231620DriveCache::CacheSubDirectoryType DriveCache::GetSubDirectoryType(
[email protected]28a64092012-08-21 10:01:121621 const DriveCacheEntry& cache_entry) {
[email protected]02821102012-07-12 20:19:171622 return cache_entry.is_persistent() ? CACHE_TYPE_PERSISTENT : CACHE_TYPE_TMP;
[email protected]fae353a2012-07-11 23:30:271623}
1624
[email protected]a321b9632012-06-14 03:29:171625void SetFreeDiskSpaceGetterForTesting(FreeDiskSpaceGetterInterface* getter) {
1626 delete global_free_disk_getter_for_testing; // Safe to delete NULL;
1627 global_free_disk_getter_for_testing = getter;
1628}
1629
[email protected]d9d04df2012-10-12 07:06:351630} // namespace drive