blob: 3b34ff4ccc063463e9a0539c91c49f5a58005877 [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/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]28a64092012-08-21 10:01:1215#include "chrome/browser/chromeos/gdata/drive.pb.h"
[email protected]fb371812012-08-22 16:05:2316#include "chrome/browser/chromeos/gdata/drive_cache_metadata.h"
[email protected]361c2012012-09-05 16:31:1317#include "chrome/browser/chromeos/gdata/drive_file_system_util.h"
[email protected]01ba15f72012-06-09 00:41:0518#include "chrome/browser/profiles/profile.h"
19#include "chrome/common/chrome_constants.h"
20#include "chrome/common/chrome_paths_internal.h"
[email protected]7986b8d2012-06-14 15:05:1421#include "content/public/browser/browser_thread.h"
22
23using content::BrowserThread;
[email protected]3653146a2012-05-29 13:41:4724
25namespace gdata {
26namespace {
27
[email protected]fb371812012-08-22 16:05:2328const FilePath::CharType kDriveCacheVersionDir[] = FILE_PATH_LITERAL("v1");
29const FilePath::CharType kDriveCacheMetaDir[] = FILE_PATH_LITERAL("meta");
30const FilePath::CharType kDriveCachePinnedDir[] = FILE_PATH_LITERAL("pinned");
31const FilePath::CharType kDriveCacheOutgoingDir[] =
[email protected]32a7fc852012-06-08 17:25:5032 FILE_PATH_LITERAL("outgoing");
[email protected]fb371812012-08-22 16:05:2333const FilePath::CharType kDriveCachePersistentDir[] =
[email protected]32a7fc852012-06-08 17:25:5034 FILE_PATH_LITERAL("persistent");
[email protected]fb371812012-08-22 16:05:2335const FilePath::CharType kDriveCacheTmpDir[] = FILE_PATH_LITERAL("tmp");
36const FilePath::CharType kDriveCacheTmpDownloadsDir[] =
[email protected]32a7fc852012-06-08 17:25:5037 FILE_PATH_LITERAL("tmp/downloads");
[email protected]fb371812012-08-22 16:05:2338const FilePath::CharType kDriveCacheTmpDocumentsDir[] =
[email protected]32a7fc852012-06-08 17:25:5039 FILE_PATH_LITERAL("tmp/documents");
40
[email protected]a321b9632012-06-14 03:29:1741// Used to tweak GetAmountOfFreeDiskSpace() behavior for testing.
42FreeDiskSpaceGetterInterface* global_free_disk_getter_for_testing = NULL;
43
44// Gets the amount of free disk space. Use
45// |global_free_disk_getter_for_testing| if set.
46int64 GetAmountOfFreeDiskSpace() {
47 if (global_free_disk_getter_for_testing)
48 return global_free_disk_getter_for_testing->AmountOfFreeDiskSpace();
49
[email protected]774727282012-08-06 09:14:4450 FilePath path;
51 if (!PathService::Get(base::DIR_HOME, &path)) {
52 LOG(ERROR) << "Home directory not found";
53 return -1;
54 }
55 return base::SysInfo::AmountOfFreeDiskSpace(path);
[email protected]a321b9632012-06-14 03:29:1756}
57
58// Returns true if we have sufficient space to store the given number of
59// bytes, while keeping kMinFreeSpace bytes on the disk.
60bool HasEnoughSpaceFor(int64 num_bytes) {
61 int64 free_space = GetAmountOfFreeDiskSpace();
[email protected]d7754f52012-08-01 08:45:3362 // Subtract this as if this portion does not exist.
[email protected]a321b9632012-06-14 03:29:1763 free_space -= kMinFreeSpace;
64 return (free_space >= num_bytes);
65}
66
[email protected]79c3752d2012-07-17 12:10:0867// Create cache directory paths and set permissions.
[email protected]322e0032012-10-07 01:55:5368bool InitCachePaths(const std::vector<FilePath>& cache_paths) {
[email protected]fb371812012-08-22 16:05:2369 if (cache_paths.size() < DriveCache::NUM_CACHE_TYPES) {
[email protected]79c3752d2012-07-17 12:10:0870 NOTREACHED();
71 LOG(ERROR) << "Size of cache_paths is invalid.";
[email protected]322e0032012-10-07 01:55:5372 return false;
[email protected]79c3752d2012-07-17 12:10:0873 }
74
[email protected]fb371812012-08-22 16:05:2375 if (!DriveCache::CreateCacheDirectories(cache_paths))
[email protected]322e0032012-10-07 01:55:5376 return false;
[email protected]79c3752d2012-07-17 12:10:0877
78 // Change permissions of cache persistent directory to u+rwx,og+x (711) in
79 // order to allow archive files in that directory to be mounted by cros-disks.
80 file_util::SetPosixFilePermissions(
[email protected]fb371812012-08-22 16:05:2381 cache_paths[DriveCache::CACHE_TYPE_PERSISTENT],
[email protected]79c3752d2012-07-17 12:10:0882 file_util::FILE_PERMISSION_USER_MASK |
83 file_util::FILE_PERMISSION_EXECUTE_BY_GROUP |
84 file_util::FILE_PERMISSION_EXECUTE_BY_OTHERS);
[email protected]322e0032012-10-07 01:55:5385
86 return true;
[email protected]79c3752d2012-07-17 12:10:0887}
88
[email protected]a321b9632012-06-14 03:29:1789// Remove all files under the given directory, non-recursively.
[email protected]d7754f52012-08-01 08:45:3390// Do not remove recursively as we don't want to touch <gcache>/tmp/downloads,
[email protected]a321b9632012-06-14 03:29:1791// which is used for user initiated downloads like "Save As"
92void RemoveAllFiles(const FilePath& directory) {
93 using file_util::FileEnumerator;
94
95 FileEnumerator enumerator(directory, false /* recursive */,
96 FileEnumerator::FILES);
97 for (FilePath file_path = enumerator.Next(); !file_path.empty();
98 file_path = enumerator.Next()) {
99 DVLOG(1) << "Removing " << file_path.value();
100 if (!file_util::Delete(file_path, false /* recursive */))
101 LOG(WARNING) << "Failed to delete " << file_path.value();
102 }
103}
104
[email protected]a321b9632012-06-14 03:29:17105// Modifies cache state of file on blocking pool, which involves:
106// - moving or copying file (per |file_operation_type|) from |source_path| to
107// |dest_path| if they're different
108// - deleting symlink if |symlink_path| is not empty
109// - creating symlink if |symlink_path| is not empty and |create_symlink| is
110// true.
[email protected]11f60db2012-08-23 16:28:15111DriveFileError ModifyCacheState(
[email protected]a321b9632012-06-14 03:29:17112 const FilePath& source_path,
113 const FilePath& dest_path,
[email protected]fb371812012-08-22 16:05:23114 DriveCache::FileOperationType file_operation_type,
[email protected]a321b9632012-06-14 03:29:17115 const FilePath& symlink_path,
116 bool create_symlink) {
117 // Move or copy |source_path| to |dest_path| if they are different.
118 if (source_path != dest_path) {
119 bool success = false;
[email protected]fb371812012-08-22 16:05:23120 if (file_operation_type == DriveCache::FILE_OPERATION_MOVE)
[email protected]a321b9632012-06-14 03:29:17121 success = file_util::Move(source_path, dest_path);
[email protected]fb371812012-08-22 16:05:23122 else if (file_operation_type == DriveCache::FILE_OPERATION_COPY)
[email protected]a321b9632012-06-14 03:29:17123 success = file_util::CopyFile(source_path, dest_path);
124 if (!success) {
[email protected]750af1d2012-07-13 14:32:43125 LOG(ERROR) << "Failed to "
[email protected]fb371812012-08-22 16:05:23126 << (file_operation_type == DriveCache::FILE_OPERATION_MOVE ?
[email protected]750af1d2012-07-13 14:32:43127 "move " : "copy ")
128 << source_path.value()
129 << " to " << dest_path.value();
[email protected]11f60db2012-08-23 16:28:15130 return DRIVE_FILE_ERROR_FAILED;
[email protected]a321b9632012-06-14 03:29:17131 } else {
[email protected]fb371812012-08-22 16:05:23132 DVLOG(1) << (file_operation_type == DriveCache::FILE_OPERATION_MOVE ?
[email protected]a321b9632012-06-14 03:29:17133 "Moved " : "Copied ")
134 << source_path.value()
135 << " to " << dest_path.value();
136 }
137 } else {
138 DVLOG(1) << "No need to move file: source = destination";
139 }
140
141 if (symlink_path.empty())
[email protected]11f60db2012-08-23 16:28:15142 return DRIVE_FILE_OK;
[email protected]a321b9632012-06-14 03:29:17143
144 // Remove symlink regardless of |create_symlink| because creating a link will
145 // not overwrite an existing one.
[email protected]a321b9632012-06-14 03:29:17146 // We try to save one file operation by not checking if link exists before
147 // deleting it, so unlink may return error if link doesn't exist, but it
148 // doesn't really matter to us.
[email protected]750af1d2012-07-13 14:32:43149 file_util::Delete(symlink_path, false);
[email protected]a321b9632012-06-14 03:29:17150
151 if (!create_symlink)
[email protected]11f60db2012-08-23 16:28:15152 return DRIVE_FILE_OK;
[email protected]a321b9632012-06-14 03:29:17153
154 // Create new symlink to |dest_path|.
155 if (!file_util::CreateSymbolicLink(dest_path, symlink_path)) {
[email protected]750af1d2012-07-13 14:32:43156 LOG(ERROR) << "Failed to create a symlink from " << symlink_path.value()
157 << " to " << dest_path.value();
[email protected]11f60db2012-08-23 16:28:15158 return DRIVE_FILE_ERROR_FAILED;
[email protected]a321b9632012-06-14 03:29:17159 }
160
[email protected]11f60db2012-08-23 16:28:15161 return DRIVE_FILE_OK;
[email protected]a321b9632012-06-14 03:29:17162}
163
164// Deletes all files that match |path_to_delete_pattern| except for
165// |path_to_keep| on blocking pool.
166// If |path_to_keep| is empty, all files in |path_to_delete_pattern| are
167// deleted.
168void DeleteFilesSelectively(const FilePath& path_to_delete_pattern,
169 const FilePath& path_to_keep) {
170 // Enumerate all files in directory of |path_to_delete_pattern| that match
171 // base name of |path_to_delete_pattern|.
172 // If a file is not |path_to_keep|, delete it.
173 bool success = true;
[email protected]84c3f162012-08-12 01:57:23174 file_util::FileEnumerator enumerator(path_to_delete_pattern.DirName(),
[email protected]a321b9632012-06-14 03:29:17175 false, // not recursive
[email protected]84c3f162012-08-12 01:57:23176 file_util::FileEnumerator::FILES |
177 file_util::FileEnumerator::SHOW_SYM_LINKS,
[email protected]a321b9632012-06-14 03:29:17178 path_to_delete_pattern.BaseName().value());
179 for (FilePath current = enumerator.Next(); !current.empty();
180 current = enumerator.Next()) {
181 // If |path_to_keep| is not empty and same as current, don't delete it.
182 if (!path_to_keep.empty() && current == path_to_keep)
183 continue;
184
[email protected]0b8d4cee2012-07-02 20:46:26185 success = file_util::Delete(current, false);
[email protected]a321b9632012-06-14 03:29:17186 if (!success)
187 DVLOG(1) << "Error deleting " << current.value();
188 else
189 DVLOG(1) << "Deleted " << current.value();
190 }
191}
192
[email protected]b83e5202012-06-27 07:50:24193// Appends |resource_id| ID to |to_fetch| if the file is pinned but not
194// fetched (not present locally), or to |to_upload| if the file is dirty
195// but not uploaded.
196void CollectBacklog(std::vector<std::string>* to_fetch,
197 std::vector<std::string>* to_upload,
198 const std::string& resource_id,
[email protected]28a64092012-08-21 10:01:12199 const DriveCacheEntry& cache_entry) {
[email protected]b83e5202012-06-27 07:50:24200 DCHECK(to_fetch);
201 DCHECK(to_upload);
[email protected]8764a392012-06-20 06:43:08202
[email protected]02821102012-07-12 20:19:17203 if (cache_entry.is_pinned() && !cache_entry.is_present())
[email protected]b83e5202012-06-27 07:50:24204 to_fetch->push_back(resource_id);
205
[email protected]02821102012-07-12 20:19:17206 if (cache_entry.is_dirty())
[email protected]b83e5202012-06-27 07:50:24207 to_upload->push_back(resource_id);
[email protected]8764a392012-06-20 06:43:08208}
209
[email protected]85b62192012-06-29 19:56:38210// Appends |resource_id| ID to |resource_ids| if the file is pinned and
211// present (cached locally).
212void CollectExistingPinnedFile(std::vector<std::string>* resource_ids,
213 const std::string& resource_id,
[email protected]28a64092012-08-21 10:01:12214 const DriveCacheEntry& cache_entry) {
[email protected]85b62192012-06-29 19:56:38215 DCHECK(resource_ids);
216
[email protected]02821102012-07-12 20:19:17217 if (cache_entry.is_pinned() && cache_entry.is_present())
[email protected]85b62192012-06-29 19:56:38218 resource_ids->push_back(resource_id);
219}
[email protected]8764a392012-06-20 06:43:08220
[email protected]cd236432012-07-27 18:03:30221// Appends |resource_id| ID to |resource_ids| unconditionally.
222void CollectAnyFile(std::vector<std::string>* resource_ids,
223 const std::string& resource_id,
[email protected]28a64092012-08-21 10:01:12224 const DriveCacheEntry& /* cache_entry */) {
[email protected]cd236432012-07-27 18:03:30225 DCHECK(resource_ids);
226
227 resource_ids->push_back(resource_id);
228}
229
[email protected]7986b8d2012-06-14 15:05:14230// Runs callback with pointers dereferenced.
[email protected]f861b392012-08-03 20:41:12231// Used to implement SetMountedStateOnUIThread and ClearAllOnUIThread.
232void RunChangeCacheStateCallback(const ChangeCacheStateCallback& callback,
[email protected]11f60db2012-08-23 16:28:15233 const DriveFileError* error,
[email protected]f861b392012-08-03 20:41:12234 const FilePath* cache_file_path) {
[email protected]7986b8d2012-06-14 15:05:14235 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
236 DCHECK(error);
237 DCHECK(cache_file_path);
238
239 if (!callback.is_null())
240 callback.Run(*error, *cache_file_path);
241}
242
[email protected]73f9c742012-06-15 07:37:13243// Runs callback with pointers dereferenced.
244// Used to implement *OnUIThread methods.
245void RunCacheOperationCallback(const CacheOperationCallback& callback,
[email protected]11f60db2012-08-23 16:28:15246 DriveFileError* error,
[email protected]73f9c742012-06-15 07:37:13247 const std::string& resource_id,
248 const std::string& md5) {
249 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
250 DCHECK(error);
251
252 if (!callback.is_null())
253 callback.Run(*error, resource_id, md5);
254}
255
[email protected]c960d222012-06-15 10:03:50256// Runs callback with pointers dereferenced.
257// Used to implement *OnUIThread methods.
258void RunGetFileFromCacheCallback(const GetFileFromCacheCallback& callback,
[email protected]11f60db2012-08-23 16:28:15259 DriveFileError* error,
[email protected]c960d222012-06-15 10:03:50260 FilePath* cache_file_path) {
261 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
262 DCHECK(error);
263 DCHECK(cache_file_path);
264
265 if (!callback.is_null())
[email protected]3cacd172e22012-09-06 22:52:45266 callback.Run(*error, *cache_file_path);
[email protected]c960d222012-06-15 10:03:50267}
268
[email protected]8764a392012-06-20 06:43:08269// Runs callback with pointers dereferenced.
[email protected]4324fdc2012-06-29 05:32:48270// Used to implement GetResourceIdsOfBacklogOnUIThread().
[email protected]85b62192012-06-29 19:56:38271void RunGetResourceIdsOfBacklogCallback(
272 const GetResourceIdsOfBacklogCallback& callback,
273 std::vector<std::string>* to_fetch,
274 std::vector<std::string>* to_upload) {
[email protected]8764a392012-06-20 06:43:08275 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]b83e5202012-06-27 07:50:24276 DCHECK(to_fetch);
277 DCHECK(to_upload);
[email protected]8764a392012-06-20 06:43:08278
279 if (!callback.is_null())
[email protected]b83e5202012-06-27 07:50:24280 callback.Run(*to_fetch, *to_upload);
[email protected]8764a392012-06-20 06:43:08281}
282
[email protected]4324fdc2012-06-29 05:32:48283// Runs callback with pointers dereferenced.
[email protected]85b62192012-06-29 19:56:38284// Used to implement GetResourceIdsOfExistingPinnedFilesOnUIThread().
285void RunGetResourceIdsCallback(
286 const GetResourceIdsCallback& callback,
287 std::vector<std::string>* resource_ids) {
288 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
289 DCHECK(resource_ids);
290
291 if (!callback.is_null())
292 callback.Run(*resource_ids);
293}
294
295// Runs callback with pointers dereferenced.
[email protected]4324fdc2012-06-29 05:32:48296// Used to implement GetCacheEntryOnUIThread().
297void RunGetCacheEntryCallback(
[email protected]fae353a2012-07-11 23:30:27298 const GetCacheEntryCallback& callback,
[email protected]4324fdc2012-06-29 05:32:48299 bool* success,
[email protected]28a64092012-08-21 10:01:12300 DriveCacheEntry* cache_entry) {
[email protected]4324fdc2012-06-29 05:32:48301 DCHECK(success);
302 DCHECK(cache_entry);
303
304 if (!callback.is_null())
305 callback.Run(*success, *cache_entry);
306}
307
[email protected]322e0032012-10-07 01:55:53308// Runs InitializeCacheCallback with a pointer dereferenced.
309void RunInitializeCacheCallback(const InitializeCacheCallback& callback,
310 bool* success) {
311 DCHECK(success);
312
313 if (!callback.is_null())
314 callback.Run(*success);
315}
316
[email protected]a321b9632012-06-14 03:29:17317} // namespace
[email protected]32a7fc852012-06-08 17:25:50318
[email protected]fb371812012-08-22 16:05:23319DriveCache::DriveCache(const FilePath& cache_root_path,
[email protected]ddbf2052012-07-13 15:07:02320 base::SequencedTaskRunner* blocking_task_runner)
[email protected]01ba15f72012-06-09 00:41:05321 : cache_root_path_(cache_root_path),
[email protected]6b70c7b2012-06-14 03:10:43322 cache_paths_(GetCachePaths(cache_root_path_)),
[email protected]ddbf2052012-07-13 15:07:02323 blocking_task_runner_(blocking_task_runner),
[email protected]dc2e8f7b2012-08-30 20:22:44324 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
[email protected]73f9c742012-06-15 07:37:13325 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]3653146a2012-05-29 13:41:47326}
327
[email protected]fb371812012-08-22 16:05:23328DriveCache::~DriveCache() {
[email protected]73f9c742012-06-15 07:37:13329 AssertOnSequencedWorkerPool();
[email protected]3653146a2012-05-29 13:41:47330}
331
[email protected]fb371812012-08-22 16:05:23332FilePath DriveCache::GetCacheDirectoryPath(
[email protected]32a7fc852012-06-08 17:25:50333 CacheSubDirectoryType sub_dir_type) const {
334 DCHECK_LE(0, sub_dir_type);
335 DCHECK_GT(NUM_CACHE_TYPES, sub_dir_type);
336 return cache_paths_[sub_dir_type];
337}
338
[email protected]fb371812012-08-22 16:05:23339FilePath DriveCache::GetCacheFilePath(const std::string& resource_id,
[email protected]32a7fc852012-06-08 17:25:50340 const std::string& md5,
341 CacheSubDirectoryType sub_dir_type,
342 CachedFileOrigin file_origin) const {
343 DCHECK(sub_dir_type != CACHE_TYPE_META);
344
345 // Runs on any thread.
346 // Filename is formatted as resource_id.md5, i.e. resource_id is the base
347 // name and md5 is the extension.
348 std::string base_name = util::EscapeCacheFileName(resource_id);
349 if (file_origin == CACHED_FILE_LOCALLY_MODIFIED) {
350 DCHECK(sub_dir_type == CACHE_TYPE_PERSISTENT);
351 base_name += FilePath::kExtensionSeparator;
[email protected]b83e5202012-06-27 07:50:24352 base_name += util::kLocallyModifiedFileExtension;
[email protected]32a7fc852012-06-08 17:25:50353 } else if (!md5.empty()) {
354 base_name += FilePath::kExtensionSeparator;
355 base_name += util::EscapeCacheFileName(md5);
356 }
357 // For mounted archives the filename is formatted as resource_id.md5.mounted,
358 // i.e. resource_id.md5 is the base name and ".mounted" is the extension
359 if (file_origin == CACHED_FILE_MOUNTED) {
[email protected]a321b9632012-06-14 03:29:17360 DCHECK(sub_dir_type == CACHE_TYPE_PERSISTENT);
361 base_name += FilePath::kExtensionSeparator;
[email protected]ca5f6da2012-06-18 12:54:59362 base_name += util::kMountedArchiveFileExtension;
[email protected]32a7fc852012-06-08 17:25:50363 }
364 return GetCacheDirectoryPath(sub_dir_type).Append(base_name);
365}
366
[email protected]fb371812012-08-22 16:05:23367void DriveCache::AssertOnSequencedWorkerPool() {
[email protected]ddbf2052012-07-13 15:07:02368 DCHECK(!blocking_task_runner_ ||
369 blocking_task_runner_->RunsTasksOnCurrentThread());
[email protected]fcc92a52012-06-08 22:54:16370}
371
[email protected]fb371812012-08-22 16:05:23372bool DriveCache::IsUnderDriveCacheDirectory(const FilePath& path) const {
[email protected]01ba15f72012-06-09 00:41:05373 return cache_root_path_ == path || cache_root_path_.IsParent(path);
374}
375
[email protected]fb371812012-08-22 16:05:23376void DriveCache::AddObserver(Observer* observer) {
[email protected]73f9c742012-06-15 07:37:13377 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
378 observers_.AddObserver(observer);
379}
380
[email protected]fb371812012-08-22 16:05:23381void DriveCache::RemoveObserver(Observer* observer) {
[email protected]73f9c742012-06-15 07:37:13382 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
383 observers_.RemoveObserver(observer);
384}
385
[email protected]fb371812012-08-22 16:05:23386void DriveCache::GetCacheEntryOnUIThread(
[email protected]4324fdc2012-06-29 05:32:48387 const std::string& resource_id,
388 const std::string& md5,
389 const GetCacheEntryCallback& callback) {
390 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
391
392 bool* success = new bool(false);
[email protected]28a64092012-08-21 10:01:12393 DriveCacheEntry* cache_entry = new DriveCacheEntry;
[email protected]ddbf2052012-07-13 15:07:02394 blocking_task_runner_->PostTaskAndReply(
[email protected]4324fdc2012-06-29 05:32:48395 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23396 base::Bind(&DriveCache::GetCacheEntryHelper,
[email protected]4324fdc2012-06-29 05:32:48397 base::Unretained(this),
398 resource_id,
399 md5,
400 success,
401 cache_entry),
402 base::Bind(&RunGetCacheEntryCallback,
403 callback,
404 base::Owned(success),
405 base::Owned(cache_entry)));
406}
407
[email protected]fb371812012-08-22 16:05:23408void DriveCache::GetResourceIdsOfBacklogOnUIThread(
[email protected]85b62192012-06-29 19:56:38409 const GetResourceIdsOfBacklogCallback& callback) {
[email protected]8764a392012-06-20 06:43:08410 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
411
[email protected]b83e5202012-06-27 07:50:24412 std::vector<std::string>* to_fetch = new std::vector<std::string>;
413 std::vector<std::string>* to_upload = new std::vector<std::string>;
[email protected]ddbf2052012-07-13 15:07:02414 blocking_task_runner_->PostTaskAndReply(
[email protected]8764a392012-06-20 06:43:08415 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23416 base::Bind(&DriveCache::GetResourceIdsOfBacklog,
[email protected]8764a392012-06-20 06:43:08417 base::Unretained(this),
[email protected]b83e5202012-06-27 07:50:24418 to_fetch,
419 to_upload),
[email protected]85b62192012-06-29 19:56:38420 base::Bind(&RunGetResourceIdsOfBacklogCallback,
[email protected]8764a392012-06-20 06:43:08421 callback,
[email protected]b83e5202012-06-27 07:50:24422 base::Owned(to_fetch),
423 base::Owned(to_upload)));
[email protected]8764a392012-06-20 06:43:08424}
425
[email protected]fb371812012-08-22 16:05:23426void DriveCache::GetResourceIdsOfExistingPinnedFilesOnUIThread(
[email protected]85b62192012-06-29 19:56:38427 const GetResourceIdsCallback& callback) {
428 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
429
430 std::vector<std::string>* resource_ids = new std::vector<std::string>;
[email protected]ddbf2052012-07-13 15:07:02431 blocking_task_runner_->PostTaskAndReply(
[email protected]85b62192012-06-29 19:56:38432 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23433 base::Bind(&DriveCache::GetResourceIdsOfExistingPinnedFiles,
[email protected]85b62192012-06-29 19:56:38434 base::Unretained(this),
435 resource_ids),
436 base::Bind(&RunGetResourceIdsCallback,
437 callback,
438 base::Owned(resource_ids)));
439}
440
[email protected]fb371812012-08-22 16:05:23441void DriveCache::GetResourceIdsOfAllFilesOnUIThread(
[email protected]cd236432012-07-27 18:03:30442 const GetResourceIdsCallback& callback) {
443 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
444
445 std::vector<std::string>* resource_ids = new std::vector<std::string>;
446 blocking_task_runner_->PostTaskAndReply(
447 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23448 base::Bind(&DriveCache::GetResourceIdsOfAllFiles,
[email protected]cd236432012-07-27 18:03:30449 base::Unretained(this),
450 resource_ids),
451 base::Bind(&RunGetResourceIdsCallback,
452 callback,
453 base::Owned(resource_ids)));
454}
455
[email protected]fb371812012-08-22 16:05:23456void DriveCache::FreeDiskSpaceIfNeededFor(int64 num_bytes,
[email protected]a321b9632012-06-14 03:29:17457 bool* has_enough_space) {
458 AssertOnSequencedWorkerPool();
459
460 // Do nothing and return if we have enough space.
461 *has_enough_space = HasEnoughSpaceFor(num_bytes);
462 if (*has_enough_space)
463 return;
464
465 // Otherwise, try to free up the disk space.
466 DVLOG(1) << "Freeing up disk space for " << num_bytes;
467 // First remove temporary files from the cache map.
[email protected]ca5f6da2012-06-18 12:54:59468 metadata_->RemoveTemporaryFiles();
[email protected]a321b9632012-06-14 03:29:17469 // Then remove all files under "tmp" directory.
[email protected]fb371812012-08-22 16:05:23470 RemoveAllFiles(GetCacheDirectoryPath(DriveCache::CACHE_TYPE_TMP));
[email protected]a321b9632012-06-14 03:29:17471
472 // Check the disk space again.
473 *has_enough_space = HasEnoughSpaceFor(num_bytes);
474}
475
[email protected]fb371812012-08-22 16:05:23476void DriveCache::GetFileOnUIThread(const std::string& resource_id,
[email protected]c960d222012-06-15 10:03:50477 const std::string& md5,
478 const GetFileFromCacheCallback& callback) {
479 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]a321b9632012-06-14 03:29:17480
[email protected]11f60db2012-08-23 16:28:15481 DriveFileError* error = new DriveFileError(DRIVE_FILE_OK);
[email protected]c960d222012-06-15 10:03:50482 FilePath* cache_file_path = new FilePath;
[email protected]ddbf2052012-07-13 15:07:02483 blocking_task_runner_->PostTaskAndReply(
[email protected]c960d222012-06-15 10:03:50484 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23485 base::Bind(&DriveCache::GetFile,
[email protected]c960d222012-06-15 10:03:50486 base::Unretained(this),
487 resource_id,
488 md5,
489 error,
490 cache_file_path),
491 base::Bind(&RunGetFileFromCacheCallback,
492 callback,
493 base::Owned(error),
[email protected]c960d222012-06-15 10:03:50494 base::Owned(cache_file_path)));
[email protected]a321b9632012-06-14 03:29:17495}
496
[email protected]fb371812012-08-22 16:05:23497void DriveCache::StoreOnUIThread(const std::string& resource_id,
[email protected]73f9c742012-06-15 07:37:13498 const std::string& md5,
499 const FilePath& source_path,
500 FileOperationType file_operation_type,
501 const CacheOperationCallback& callback) {
502 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
503
[email protected]11f60db2012-08-23 16:28:15504 DriveFileError* error = new DriveFileError(DRIVE_FILE_OK);
[email protected]ddbf2052012-07-13 15:07:02505 blocking_task_runner_->PostTaskAndReply(
[email protected]73f9c742012-06-15 07:37:13506 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23507 base::Bind(&DriveCache::Store,
[email protected]73f9c742012-06-15 07:37:13508 base::Unretained(this),
509 resource_id,
510 md5,
511 source_path,
512 file_operation_type,
513 error),
514 base::Bind(&RunCacheOperationCallback,
515 callback,
516 base::Owned(error),
517 resource_id,
518 md5));
519}
520
[email protected]fb371812012-08-22 16:05:23521void DriveCache::PinOnUIThread(const std::string& resource_id,
[email protected]44c0584e2012-06-15 23:55:41522 const std::string& md5,
523 const CacheOperationCallback& callback) {
[email protected]73f9c742012-06-15 07:37:13524 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
525
[email protected]11f60db2012-08-23 16:28:15526 DriveFileError* error = new DriveFileError(DRIVE_FILE_OK);
[email protected]ddbf2052012-07-13 15:07:02527 blocking_task_runner_->PostTaskAndReply(
[email protected]73f9c742012-06-15 07:37:13528 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23529 base::Bind(&DriveCache::Pin,
[email protected]73f9c742012-06-15 07:37:13530 base::Unretained(this),
531 resource_id,
532 md5,
[email protected]fb371812012-08-22 16:05:23533 DriveCache::FILE_OPERATION_MOVE,
[email protected]73f9c742012-06-15 07:37:13534 error),
[email protected]fb371812012-08-22 16:05:23535 base::Bind(&DriveCache::OnPinned,
[email protected]e53ac8f2012-08-02 07:05:00536 weak_ptr_factory_.GetWeakPtr(),
[email protected]73f9c742012-06-15 07:37:13537 base::Owned(error),
538 resource_id,
539 md5,
540 callback));
541}
542
[email protected]fb371812012-08-22 16:05:23543void DriveCache::UnpinOnUIThread(const std::string& resource_id,
[email protected]73f9c742012-06-15 07:37:13544 const std::string& md5,
545 const CacheOperationCallback& callback) {
546 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]11f60db2012-08-23 16:28:15547 DriveFileError* error = new DriveFileError(DRIVE_FILE_OK);
[email protected]ddbf2052012-07-13 15:07:02548 blocking_task_runner_->PostTaskAndReply(
[email protected]73f9c742012-06-15 07:37:13549 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23550 base::Bind(&DriveCache::Unpin,
[email protected]73f9c742012-06-15 07:37:13551 base::Unretained(this),
552 resource_id,
553 md5,
[email protected]fb371812012-08-22 16:05:23554 DriveCache::FILE_OPERATION_MOVE,
[email protected]73f9c742012-06-15 07:37:13555 error),
[email protected]fb371812012-08-22 16:05:23556 base::Bind(&DriveCache::OnUnpinned,
[email protected]e53ac8f2012-08-02 07:05:00557 weak_ptr_factory_.GetWeakPtr(),
[email protected]73f9c742012-06-15 07:37:13558 base::Owned(error),
559 resource_id,
560 md5,
561 callback));
562}
563
[email protected]fb371812012-08-22 16:05:23564void DriveCache::SetMountedStateOnUIThread(
[email protected]73f9c742012-06-15 07:37:13565 const FilePath& file_path,
566 bool to_mount,
[email protected]f861b392012-08-03 20:41:12567 const ChangeCacheStateCallback& callback) {
[email protected]73f9c742012-06-15 07:37:13568 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
569
[email protected]11f60db2012-08-23 16:28:15570 DriveFileError* error = new DriveFileError(DRIVE_FILE_OK);
[email protected]73f9c742012-06-15 07:37:13571 FilePath* cache_file_path = new FilePath;
[email protected]ddbf2052012-07-13 15:07:02572 blocking_task_runner_->PostTaskAndReply(
[email protected]73f9c742012-06-15 07:37:13573 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23574 base::Bind(&DriveCache::SetMountedState,
[email protected]73f9c742012-06-15 07:37:13575 base::Unretained(this),
576 file_path,
577 to_mount,
578 error,
579 cache_file_path),
[email protected]f861b392012-08-03 20:41:12580 base::Bind(&RunChangeCacheStateCallback,
[email protected]73f9c742012-06-15 07:37:13581 callback,
582 base::Owned(error),
583 base::Owned(cache_file_path)));
584}
585
[email protected]fb371812012-08-22 16:05:23586void DriveCache::MarkDirtyOnUIThread(const std::string& resource_id,
[email protected]c960d222012-06-15 10:03:50587 const std::string& md5,
588 const GetFileFromCacheCallback& callback) {
589 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]73f9c742012-06-15 07:37:13590
[email protected]11f60db2012-08-23 16:28:15591 DriveFileError* error = new DriveFileError(DRIVE_FILE_OK);
[email protected]c960d222012-06-15 10:03:50592 FilePath* cache_file_path = new FilePath;
[email protected]ddbf2052012-07-13 15:07:02593 blocking_task_runner_->PostTaskAndReply(
[email protected]c960d222012-06-15 10:03:50594 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23595 base::Bind(&DriveCache::MarkDirty,
[email protected]c960d222012-06-15 10:03:50596 base::Unretained(this),
597 resource_id,
598 md5,
[email protected]fb371812012-08-22 16:05:23599 DriveCache::FILE_OPERATION_MOVE,
[email protected]c960d222012-06-15 10:03:50600 error,
601 cache_file_path),
602 base::Bind(&RunGetFileFromCacheCallback,
603 callback,
604 base::Owned(error),
[email protected]c960d222012-06-15 10:03:50605 base::Owned(cache_file_path)));
[email protected]73f9c742012-06-15 07:37:13606}
607
[email protected]fb371812012-08-22 16:05:23608void DriveCache::CommitDirtyOnUIThread(const std::string& resource_id,
[email protected]73f9c742012-06-15 07:37:13609 const std::string& md5,
610 const CacheOperationCallback& callback) {
611 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
612
[email protected]11f60db2012-08-23 16:28:15613 DriveFileError* error = new DriveFileError(DRIVE_FILE_OK);
[email protected]ddbf2052012-07-13 15:07:02614 blocking_task_runner_->PostTaskAndReply(
[email protected]73f9c742012-06-15 07:37:13615 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23616 base::Bind(&DriveCache::CommitDirty,
[email protected]73f9c742012-06-15 07:37:13617 base::Unretained(this),
618 resource_id,
619 md5,
[email protected]fb371812012-08-22 16:05:23620 DriveCache::FILE_OPERATION_MOVE,
[email protected]73f9c742012-06-15 07:37:13621 error),
[email protected]fb371812012-08-22 16:05:23622 base::Bind(&DriveCache::OnCommitDirty,
[email protected]e53ac8f2012-08-02 07:05:00623 weak_ptr_factory_.GetWeakPtr(),
[email protected]73f9c742012-06-15 07:37:13624 base::Owned(error),
625 resource_id,
[email protected]d7664c22012-06-18 19:35:49626 md5,
627 callback));
[email protected]73f9c742012-06-15 07:37:13628}
629
[email protected]fb371812012-08-22 16:05:23630void DriveCache::ClearDirtyOnUIThread(const std::string& resource_id,
[email protected]73f9c742012-06-15 07:37:13631 const std::string& md5,
632 const CacheOperationCallback& callback) {
633 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
634
[email protected]11f60db2012-08-23 16:28:15635 DriveFileError* error = new DriveFileError(DRIVE_FILE_OK);
[email protected]ddbf2052012-07-13 15:07:02636 blocking_task_runner_->PostTaskAndReply(
[email protected]73f9c742012-06-15 07:37:13637 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23638 base::Bind(&DriveCache::ClearDirty,
[email protected]73f9c742012-06-15 07:37:13639 base::Unretained(this),
640 resource_id,
641 md5,
[email protected]fb371812012-08-22 16:05:23642 DriveCache::FILE_OPERATION_MOVE,
[email protected]73f9c742012-06-15 07:37:13643 error),
644 base::Bind(&RunCacheOperationCallback,
645 callback,
646 base::Owned(error),
647 resource_id,
648 md5));
649}
650
[email protected]fb371812012-08-22 16:05:23651void DriveCache::RemoveOnUIThread(const std::string& resource_id,
[email protected]73f9c742012-06-15 07:37:13652 const CacheOperationCallback& callback) {
653 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
654
[email protected]11f60db2012-08-23 16:28:15655 DriveFileError* error = new DriveFileError(DRIVE_FILE_OK);
[email protected]ddbf2052012-07-13 15:07:02656 blocking_task_runner_->PostTaskAndReply(
[email protected]73f9c742012-06-15 07:37:13657 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23658 base::Bind(&DriveCache::Remove,
[email protected]73f9c742012-06-15 07:37:13659 base::Unretained(this),
660 resource_id,
661 error),
662 base::Bind(&RunCacheOperationCallback,
663 callback,
664 base::Owned(error),
665 resource_id,
666 "" /* md5 */));
667}
668
[email protected]fb371812012-08-22 16:05:23669void DriveCache::ClearAllOnUIThread(const ChangeCacheStateCallback& callback) {
[email protected]f861b392012-08-03 20:41:12670 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
671
[email protected]11f60db2012-08-23 16:28:15672 DriveFileError* error = new DriveFileError(DRIVE_FILE_OK);
[email protected]f861b392012-08-03 20:41:12673 blocking_task_runner_->PostTaskAndReply(
674 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23675 base::Bind(&DriveCache::ClearAll,
[email protected]f861b392012-08-03 20:41:12676 base::Unretained(this),
677 error),
678 base::Bind(&RunChangeCacheStateCallback,
679 callback,
680 base::Owned(error),
681 &cache_root_path_));
682}
683
[email protected]322e0032012-10-07 01:55:53684void DriveCache::RequestInitializeOnUIThread(
685 const InitializeCacheCallback& callback) {
[email protected]73f9c742012-06-15 07:37:13686 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]322e0032012-10-07 01:55:53687 DCHECK(!callback.is_null());
[email protected]73f9c742012-06-15 07:37:13688
[email protected]322e0032012-10-07 01:55:53689 bool* success = new bool(false);
690 blocking_task_runner_->PostTaskAndReply(
[email protected]73f9c742012-06-15 07:37:13691 FROM_HERE,
[email protected]322e0032012-10-07 01:55:53692 base::Bind(&DriveCache::Initialize,
693 base::Unretained(this),
694 success),
695 base::Bind(&RunInitializeCacheCallback,
696 callback,
697 base::Owned(success)));
[email protected]73f9c742012-06-15 07:37:13698}
699
[email protected]fb371812012-08-22 16:05:23700void DriveCache::RequestInitializeOnUIThreadForTesting() {
[email protected]d310bfc2012-08-10 09:41:28701 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
702
703 blocking_task_runner_->PostTask(
704 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23705 base::Bind(&DriveCache::InitializeForTesting, base::Unretained(this)));
[email protected]d310bfc2012-08-10 09:41:28706}
707
[email protected]fb371812012-08-22 16:05:23708void DriveCache::ForceRescanOnUIThreadForTesting() {
[email protected]79c3752d2012-07-17 12:10:08709 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
710
711 blocking_task_runner_->PostTask(
712 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23713 base::Bind(&DriveCache::ForceRescanForTesting, base::Unretained(this)));
[email protected]79c3752d2012-07-17 12:10:08714}
715
[email protected]fb371812012-08-22 16:05:23716bool DriveCache::GetCacheEntry(const std::string& resource_id,
[email protected]b22f87f2012-07-12 10:53:17717 const std::string& md5,
[email protected]28a64092012-08-21 10:01:12718 DriveCacheEntry* entry) {
[email protected]b22f87f2012-07-12 10:53:17719 DCHECK(entry);
[email protected]73f9c742012-06-15 07:37:13720 AssertOnSequencedWorkerPool();
[email protected]b22f87f2012-07-12 10:53:17721 return metadata_->GetCacheEntry(resource_id, md5, entry);
[email protected]73f9c742012-06-15 07:37:13722}
723
724// static
[email protected]fb371812012-08-22 16:05:23725DriveCache* DriveCache::CreateDriveCacheOnUIThread(
[email protected]73f9c742012-06-15 07:37:13726 const FilePath& cache_root_path,
[email protected]ddbf2052012-07-13 15:07:02727 base::SequencedTaskRunner* blocking_task_runner) {
[email protected]73f9c742012-06-15 07:37:13728 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]fb371812012-08-22 16:05:23729 return new DriveCache(cache_root_path, blocking_task_runner);
[email protected]73f9c742012-06-15 07:37:13730}
731
[email protected]fb371812012-08-22 16:05:23732void DriveCache::DestroyOnUIThread() {
[email protected]73f9c742012-06-15 07:37:13733 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
734
735 // Invalidate the weak pointer.
[email protected]e53ac8f2012-08-02 07:05:00736 weak_ptr_factory_.InvalidateWeakPtrs();
[email protected]73f9c742012-06-15 07:37:13737
738 // Destroy myself on the blocking pool.
[email protected]ddbf2052012-07-13 15:07:02739 blocking_task_runner_->PostTask(
[email protected]73f9c742012-06-15 07:37:13740 FROM_HERE,
[email protected]fb371812012-08-22 16:05:23741 base::Bind(&DriveCache::Destroy,
[email protected]73f9c742012-06-15 07:37:13742 base::Unretained(this)));
743}
744
[email protected]322e0032012-10-07 01:55:53745void DriveCache::Initialize(bool* success) {
[email protected]ca5f6da2012-06-18 12:54:59746 AssertOnSequencedWorkerPool();
[email protected]322e0032012-10-07 01:55:53747 DCHECK(success);
[email protected]ca5f6da2012-06-18 12:54:59748
[email protected]322e0032012-10-07 01:55:53749 if (!InitCachePaths(cache_paths_)) {
750 *success = false;
751 return;
752 }
753
[email protected]fb371812012-08-22 16:05:23754 metadata_ = DriveCacheMetadata::CreateDriveCacheMetadata(
[email protected]f9e5cc02012-07-13 20:08:56755 blocking_task_runner_).Pass();
[email protected]322e0032012-10-07 01:55:53756 *success = metadata_->Initialize(cache_paths_);
[email protected]ca5f6da2012-06-18 12:54:59757}
758
[email protected]fb371812012-08-22 16:05:23759void DriveCache::InitializeForTesting() {
[email protected]d310bfc2012-08-10 09:41:28760 AssertOnSequencedWorkerPool();
761
762 InitCachePaths(cache_paths_);
[email protected]fb371812012-08-22 16:05:23763 metadata_ = DriveCacheMetadata::CreateDriveCacheMetadataForTesting(
[email protected]d310bfc2012-08-10 09:41:28764 blocking_task_runner_).Pass();
765 metadata_->Initialize(cache_paths_);
766}
767
[email protected]fb371812012-08-22 16:05:23768void DriveCache::Destroy() {
[email protected]73f9c742012-06-15 07:37:13769 AssertOnSequencedWorkerPool();
770 delete this;
771}
772
[email protected]fb371812012-08-22 16:05:23773void DriveCache::ForceRescanForTesting() {
[email protected]79c3752d2012-07-17 12:10:08774 AssertOnSequencedWorkerPool();
775 metadata_->ForceRescanForTesting(cache_paths_);
776}
777
[email protected]fb371812012-08-22 16:05:23778void DriveCache::GetResourceIdsOfBacklog(
[email protected]b83e5202012-06-27 07:50:24779 std::vector<std::string>* to_fetch,
780 std::vector<std::string>* to_upload) {
[email protected]8764a392012-06-20 06:43:08781 AssertOnSequencedWorkerPool();
[email protected]b83e5202012-06-27 07:50:24782 DCHECK(to_fetch);
783 DCHECK(to_upload);
[email protected]8764a392012-06-20 06:43:08784
[email protected]b83e5202012-06-27 07:50:24785 metadata_->Iterate(base::Bind(&CollectBacklog, to_fetch, to_upload));
[email protected]8764a392012-06-20 06:43:08786}
787
[email protected]fb371812012-08-22 16:05:23788void DriveCache::GetResourceIdsOfExistingPinnedFiles(
[email protected]85b62192012-06-29 19:56:38789 std::vector<std::string>* resource_ids) {
790 AssertOnSequencedWorkerPool();
791 DCHECK(resource_ids);
792
793 metadata_->Iterate(base::Bind(&CollectExistingPinnedFile, resource_ids));
794}
795
[email protected]fb371812012-08-22 16:05:23796void DriveCache::GetResourceIdsOfAllFiles(
[email protected]cd236432012-07-27 18:03:30797 std::vector<std::string>* resource_ids) {
798 AssertOnSequencedWorkerPool();
799 DCHECK(resource_ids);
800
801 metadata_->Iterate(base::Bind(&CollectAnyFile, resource_ids));
802}
803
[email protected]fb371812012-08-22 16:05:23804void DriveCache::GetFile(const std::string& resource_id,
[email protected]c960d222012-06-15 10:03:50805 const std::string& md5,
[email protected]11f60db2012-08-23 16:28:15806 DriveFileError* error,
[email protected]c960d222012-06-15 10:03:50807 FilePath* cache_file_path) {
808 AssertOnSequencedWorkerPool();
809 DCHECK(error);
810 DCHECK(cache_file_path);
811
[email protected]28a64092012-08-21 10:01:12812 DriveCacheEntry cache_entry;
[email protected]b22f87f2012-07-12 10:53:17813 if (GetCacheEntry(resource_id, md5, &cache_entry) &&
[email protected]02821102012-07-12 20:19:17814 cache_entry.is_present()) {
[email protected]c960d222012-06-15 10:03:50815 CachedFileOrigin file_origin;
[email protected]02821102012-07-12 20:19:17816 if (cache_entry.is_mounted()) {
[email protected]c960d222012-06-15 10:03:50817 file_origin = CACHED_FILE_MOUNTED;
[email protected]02821102012-07-12 20:19:17818 } else if (cache_entry.is_dirty()) {
[email protected]c960d222012-06-15 10:03:50819 file_origin = CACHED_FILE_LOCALLY_MODIFIED;
820 } else {
821 file_origin = CACHED_FILE_FROM_SERVER;
822 }
823 *cache_file_path = GetCacheFilePath(
824 resource_id,
825 md5,
[email protected]b22f87f2012-07-12 10:53:17826 GetSubDirectoryType(cache_entry),
[email protected]c960d222012-06-15 10:03:50827 file_origin);
[email protected]11f60db2012-08-23 16:28:15828 *error = DRIVE_FILE_OK;
[email protected]c960d222012-06-15 10:03:50829 } else {
[email protected]11f60db2012-08-23 16:28:15830 *error = DRIVE_FILE_ERROR_NOT_FOUND;
[email protected]c960d222012-06-15 10:03:50831 }
832}
833
[email protected]fb371812012-08-22 16:05:23834void DriveCache::Store(const std::string& resource_id,
[email protected]a321b9632012-06-14 03:29:17835 const std::string& md5,
836 const FilePath& source_path,
837 FileOperationType file_operation_type,
[email protected]11f60db2012-08-23 16:28:15838 DriveFileError* error) {
[email protected]a321b9632012-06-14 03:29:17839 AssertOnSequencedWorkerPool();
840 DCHECK(error);
841
[email protected]f0c67002012-08-15 04:10:38842 if (file_operation_type == FILE_OPERATION_COPY) {
843 int64 file_size;
844 if (!file_util::GetFileSize(source_path, &file_size)) {
845 LOG(WARNING) << "Couldn't get file size for: " << source_path.value();
[email protected]11f60db2012-08-23 16:28:15846 *error = DRIVE_FILE_ERROR_FAILED;
[email protected]f0c67002012-08-15 04:10:38847 return;
848 }
849
850 bool enough_space = false;
851 FreeDiskSpaceIfNeededFor(file_size, &enough_space);
852 if (!enough_space) {
[email protected]11f60db2012-08-23 16:28:15853 *error = DRIVE_FILE_ERROR_NO_SPACE;
[email protected]f0c67002012-08-15 04:10:38854 return;
855 }
856 }
857
[email protected]a321b9632012-06-14 03:29:17858 FilePath dest_path;
859 FilePath symlink_path;
[email protected]a321b9632012-06-14 03:29:17860 CacheSubDirectoryType sub_dir_type = CACHE_TYPE_TMP;
861
[email protected]a321b9632012-06-14 03:29:17862 // If file was previously pinned, store it in persistent dir and create
863 // symlink in pinned dir.
[email protected]28a64092012-08-21 10:01:12864 DriveCacheEntry cache_entry;
[email protected]b22f87f2012-07-12 10:53:17865 if (GetCacheEntry(resource_id, md5, &cache_entry)) { // File exists in cache.
[email protected]a321b9632012-06-14 03:29:17866 // If file is dirty or mounted, return error.
[email protected]02821102012-07-12 20:19:17867 if (cache_entry.is_dirty() || cache_entry.is_mounted()) {
[email protected]a321b9632012-06-14 03:29:17868 LOG(WARNING) << "Can't store a file to replace a "
[email protected]02821102012-07-12 20:19:17869 << (cache_entry.is_dirty() ? "dirty" : "mounted")
[email protected]a321b9632012-06-14 03:29:17870 << " file: res_id=" << resource_id
871 << ", md5=" << md5;
[email protected]11f60db2012-08-23 16:28:15872 *error = DRIVE_FILE_ERROR_IN_USE;
[email protected]a321b9632012-06-14 03:29:17873 return;
874 }
875
[email protected]a321b9632012-06-14 03:29:17876 // If file is pinned, determines destination path.
[email protected]02821102012-07-12 20:19:17877 if (cache_entry.is_pinned()) {
[email protected]a321b9632012-06-14 03:29:17878 sub_dir_type = CACHE_TYPE_PERSISTENT;
879 dest_path = GetCacheFilePath(resource_id, md5, sub_dir_type,
880 CACHED_FILE_FROM_SERVER);
881 symlink_path = GetCacheFilePath(
882 resource_id, std::string(), CACHE_TYPE_PINNED,
883 CACHED_FILE_FROM_SERVER);
884 }
885 }
886
887 // File wasn't pinned or doesn't exist in cache, store in tmp dir.
888 if (dest_path.empty()) {
889 DCHECK_EQ(CACHE_TYPE_TMP, sub_dir_type);
890 dest_path = GetCacheFilePath(resource_id, md5, sub_dir_type,
891 CACHED_FILE_FROM_SERVER);
892 }
893
894 *error = ModifyCacheState(
895 source_path,
896 dest_path,
897 file_operation_type,
898 symlink_path,
899 !symlink_path.empty()); // create symlink
900
[email protected]f60c670b2012-09-13 06:19:25901 // Determine search pattern for stale filenames corresponding to resource_id,
[email protected]a321b9632012-06-14 03:29:17902 // either "<resource_id>*" or "<resource_id>.*".
903 FilePath stale_filenames_pattern;
904 if (md5.empty()) {
905 // No md5 means no extension, append '*' after base name, i.e.
906 // "<resource_id>*".
907 // Cannot call |dest_path|.ReplaceExtension when there's no md5 extension:
908 // if base name of |dest_path| (i.e. escaped resource_id) contains the
909 // extension separator '.', ReplaceExtension will remove it and everything
910 // after it. The result will be nothing like the escaped resource_id.
[email protected]ca5f6da2012-06-18 12:54:59911 stale_filenames_pattern = FilePath(dest_path.value() + util::kWildCard);
[email protected]a321b9632012-06-14 03:29:17912 } else {
913 // Replace md5 extension with '*' i.e. "<resource_id>.*".
914 // Note that ReplaceExtension automatically prefixes the extension with the
915 // extension separator '.'.
[email protected]ca5f6da2012-06-18 12:54:59916 stale_filenames_pattern = dest_path.ReplaceExtension(util::kWildCard);
[email protected]a321b9632012-06-14 03:29:17917 }
918
919 // Delete files that match |stale_filenames_pattern| except for |dest_path|.
920 DeleteFilesSelectively(stale_filenames_pattern, dest_path);
921
[email protected]11f60db2012-08-23 16:28:15922 if (*error == DRIVE_FILE_OK) {
[email protected]a321b9632012-06-14 03:29:17923 // Now that file operations have completed, update cache map.
[email protected]b22f87f2012-07-12 10:53:17924 cache_entry.set_md5(md5);
[email protected]02821102012-07-12 20:19:17925 cache_entry.set_is_present(true);
926 cache_entry.set_is_persistent(sub_dir_type == CACHE_TYPE_PERSISTENT);
[email protected]b22f87f2012-07-12 10:53:17927 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry);
[email protected]a321b9632012-06-14 03:29:17928 }
929}
930
[email protected]fb371812012-08-22 16:05:23931void DriveCache::Pin(const std::string& resource_id,
[email protected]a321b9632012-06-14 03:29:17932 const std::string& md5,
933 FileOperationType file_operation_type,
[email protected]11f60db2012-08-23 16:28:15934 DriveFileError* error) {
[email protected]a321b9632012-06-14 03:29:17935 AssertOnSequencedWorkerPool();
936 DCHECK(error);
937
938 FilePath source_path;
939 FilePath dest_path;
940 FilePath symlink_path;
941 bool create_symlink = true;
[email protected]a321b9632012-06-14 03:29:17942 CacheSubDirectoryType sub_dir_type = CACHE_TYPE_PERSISTENT;
943
[email protected]28a64092012-08-21 10:01:12944 DriveCacheEntry cache_entry;
[email protected]b22f87f2012-07-12 10:53:17945 if (!GetCacheEntry(resource_id, md5, &cache_entry)) {
946 // Entry does not exist in cache.
[email protected]a321b9632012-06-14 03:29:17947 // Set both |dest_path| and |source_path| to /dev/null, so that:
948 // 1) ModifyCacheState won't move files when |source_path| and |dest_path|
949 // are the same.
[email protected]9935913b2012-09-06 14:09:57950 // 2) symlinks to /dev/null will be picked up by DriveSyncClient to download
[email protected]a321b9632012-06-14 03:29:17951 // pinned files that don't exist in cache.
[email protected]30d9dda2012-06-30 05:56:28952 dest_path = FilePath::FromUTF8Unsafe(util::kSymLinkToDevNull);
[email protected]a321b9632012-06-14 03:29:17953 source_path = dest_path;
954
[email protected]2a6fe6e2012-07-10 06:01:04955 // Set sub_dir_type to TMP. The file will be first downloaded in 'tmp',
956 // then moved to 'persistent'.
957 sub_dir_type = CACHE_TYPE_TMP;
[email protected]109eb5c2012-07-12 03:20:05958 } else { // File exists in cache, determines destination path.
[email protected]a321b9632012-06-14 03:29:17959 // Determine source and destination paths.
960
961 // If file is dirty or mounted, don't move it, so determine |dest_path| and
962 // set |source_path| the same, because ModifyCacheState only moves files if
963 // source and destination are different.
[email protected]02821102012-07-12 20:19:17964 if (cache_entry.is_dirty() || cache_entry.is_mounted()) {
965 DCHECK(cache_entry.is_persistent());
[email protected]a321b9632012-06-14 03:29:17966 dest_path = GetCacheFilePath(resource_id,
967 md5,
[email protected]b22f87f2012-07-12 10:53:17968 GetSubDirectoryType(cache_entry),
[email protected]a321b9632012-06-14 03:29:17969 CACHED_FILE_LOCALLY_MODIFIED);
970 source_path = dest_path;
971 } else {
972 // Gets the current path of the file in cache.
973 source_path = GetCacheFilePath(resource_id,
974 md5,
[email protected]b22f87f2012-07-12 10:53:17975 GetSubDirectoryType(cache_entry),
[email protected]a321b9632012-06-14 03:29:17976 CACHED_FILE_FROM_SERVER);
977
978 // If file was pinned before but actual file blob doesn't exist in cache:
979 // - don't need to move the file, so set |dest_path| to |source_path|,
980 // because ModifyCacheState only moves files if source and destination
981 // are different
982 // - don't create symlink since it already exists.
[email protected]02821102012-07-12 20:19:17983 if (!cache_entry.is_present()) {
[email protected]a321b9632012-06-14 03:29:17984 dest_path = source_path;
985 create_symlink = false;
986 } else { // File exists, move it to persistent dir.
987 dest_path = GetCacheFilePath(resource_id,
988 md5,
989 CACHE_TYPE_PERSISTENT,
990 CACHED_FILE_FROM_SERVER);
991 }
992 }
993 }
994
995 // Create symlink in pinned dir.
996 if (create_symlink) {
997 symlink_path = GetCacheFilePath(resource_id,
998 std::string(),
999 CACHE_TYPE_PINNED,
1000 CACHED_FILE_FROM_SERVER);
1001 }
1002
1003 *error = ModifyCacheState(source_path,
1004 dest_path,
1005 file_operation_type,
1006 symlink_path,
1007 create_symlink);
1008
[email protected]11f60db2012-08-23 16:28:151009 if (*error == DRIVE_FILE_OK) {
[email protected]a321b9632012-06-14 03:29:171010 // Now that file operations have completed, update cache map.
[email protected]b22f87f2012-07-12 10:53:171011 cache_entry.set_md5(md5);
[email protected]02821102012-07-12 20:19:171012 cache_entry.set_is_pinned(true);
1013 cache_entry.set_is_persistent(sub_dir_type == CACHE_TYPE_PERSISTENT);
[email protected]b22f87f2012-07-12 10:53:171014 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry);
[email protected]a321b9632012-06-14 03:29:171015 }
1016}
1017
[email protected]fb371812012-08-22 16:05:231018void DriveCache::Unpin(const std::string& resource_id,
[email protected]a321b9632012-06-14 03:29:171019 const std::string& md5,
1020 FileOperationType file_operation_type,
[email protected]11f60db2012-08-23 16:28:151021 DriveFileError* error) {
[email protected]a321b9632012-06-14 03:29:171022 AssertOnSequencedWorkerPool();
1023 DCHECK(error);
1024
[email protected]a321b9632012-06-14 03:29:171025 // Unpinning a file means its entry must exist in cache.
[email protected]28a64092012-08-21 10:01:121026 DriveCacheEntry cache_entry;
[email protected]b22f87f2012-07-12 10:53:171027 if (!GetCacheEntry(resource_id, md5, &cache_entry)) {
[email protected]a321b9632012-06-14 03:29:171028 LOG(WARNING) << "Can't unpin a file that wasn't pinned or cached: res_id="
1029 << resource_id
1030 << ", md5=" << md5;
[email protected]11f60db2012-08-23 16:28:151031 *error = DRIVE_FILE_ERROR_NOT_FOUND;
[email protected]a321b9632012-06-14 03:29:171032 return;
1033 }
1034
1035 // Entry exists in cache, determines source and destination paths.
1036
1037 FilePath source_path;
1038 FilePath dest_path;
1039 CacheSubDirectoryType sub_dir_type = CACHE_TYPE_TMP;
1040
1041 // If file is dirty or mounted, don't move it, so determine |dest_path| and
1042 // set |source_path| the same, because ModifyCacheState moves files if source
1043 // and destination are different.
[email protected]02821102012-07-12 20:19:171044 if (cache_entry.is_dirty() || cache_entry.is_mounted()) {
[email protected]a321b9632012-06-14 03:29:171045 sub_dir_type = CACHE_TYPE_PERSISTENT;
[email protected]02821102012-07-12 20:19:171046 DCHECK(cache_entry.is_persistent());
[email protected]a321b9632012-06-14 03:29:171047 dest_path = GetCacheFilePath(resource_id,
1048 md5,
[email protected]b22f87f2012-07-12 10:53:171049 GetSubDirectoryType(cache_entry),
[email protected]a321b9632012-06-14 03:29:171050 CACHED_FILE_LOCALLY_MODIFIED);
1051 source_path = dest_path;
1052 } else {
1053 // Gets the current path of the file in cache.
1054 source_path = GetCacheFilePath(resource_id,
1055 md5,
[email protected]b22f87f2012-07-12 10:53:171056 GetSubDirectoryType(cache_entry),
[email protected]a321b9632012-06-14 03:29:171057 CACHED_FILE_FROM_SERVER);
1058
1059 // If file was pinned but actual file blob still doesn't exist in cache,
1060 // don't need to move the file, so set |dest_path| to |source_path|, because
1061 // ModifyCacheState only moves files if source and destination are
1062 // different.
[email protected]02821102012-07-12 20:19:171063 if (!cache_entry.is_present()) {
[email protected]a321b9632012-06-14 03:29:171064 dest_path = source_path;
1065 } else { // File exists, move it to tmp dir.
1066 dest_path = GetCacheFilePath(resource_id, md5,
1067 CACHE_TYPE_TMP,
1068 CACHED_FILE_FROM_SERVER);
1069 }
1070 }
1071
1072 // If file was pinned, get absolute path of symlink in pinned dir so as to
1073 // remove it.
1074 FilePath symlink_path;
[email protected]02821102012-07-12 20:19:171075 if (cache_entry.is_pinned()) {
[email protected]a321b9632012-06-14 03:29:171076 symlink_path = GetCacheFilePath(resource_id,
1077 std::string(),
1078 CACHE_TYPE_PINNED,
1079 CACHED_FILE_FROM_SERVER);
1080 }
1081
1082 *error = ModifyCacheState(
1083 source_path,
1084 dest_path,
1085 file_operation_type,
1086 symlink_path, // This will be deleted if it exists.
1087 false /* don't create symlink*/);
1088
[email protected]11f60db2012-08-23 16:28:151089 if (*error == DRIVE_FILE_OK) {
[email protected]a321b9632012-06-14 03:29:171090 // Now that file operations have completed, update cache map.
[email protected]02821102012-07-12 20:19:171091 if (cache_entry.is_present()) {
[email protected]48477fe2012-07-12 17:45:081092 cache_entry.set_md5(md5);
[email protected]02821102012-07-12 20:19:171093 cache_entry.set_is_pinned(false);
1094 cache_entry.set_is_persistent(sub_dir_type == CACHE_TYPE_PERSISTENT);
[email protected]48477fe2012-07-12 17:45:081095 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry);
[email protected]3423871a2012-07-12 00:41:271096 } else {
1097 // Remove the existing entry if we are unpinning a non-present file.
1098 metadata_->RemoveCacheEntry(resource_id);
1099 }
[email protected]a321b9632012-06-14 03:29:171100 }
1101}
1102
[email protected]fb371812012-08-22 16:05:231103void DriveCache::SetMountedState(const FilePath& file_path,
[email protected]a321b9632012-06-14 03:29:171104 bool to_mount,
[email protected]11f60db2012-08-23 16:28:151105 DriveFileError *error,
[email protected]a321b9632012-06-14 03:29:171106 FilePath* cache_file_path) {
1107 AssertOnSequencedWorkerPool();
1108 DCHECK(error);
1109 DCHECK(cache_file_path);
1110
1111 // Parse file path to obtain resource_id, md5 and extra_extension.
1112 std::string resource_id;
1113 std::string md5;
1114 std::string extra_extension;
1115 util::ParseCacheFilePath(file_path, &resource_id, &md5, &extra_extension);
1116 // The extra_extension shall be ".mounted" iff we're unmounting.
[email protected]ca5f6da2012-06-18 12:54:591117 DCHECK(!to_mount == (extra_extension == util::kMountedArchiveFileExtension));
[email protected]a321b9632012-06-14 03:29:171118
1119 // Get cache entry associated with the resource_id and md5
[email protected]28a64092012-08-21 10:01:121120 DriveCacheEntry cache_entry;
[email protected]b22f87f2012-07-12 10:53:171121 if (!GetCacheEntry(resource_id, md5, &cache_entry)) {
[email protected]11f60db2012-08-23 16:28:151122 *error = DRIVE_FILE_ERROR_NOT_FOUND;
[email protected]a321b9632012-06-14 03:29:171123 return;
1124 }
[email protected]02821102012-07-12 20:19:171125 if (to_mount == cache_entry.is_mounted()) {
[email protected]11f60db2012-08-23 16:28:151126 *error = DRIVE_FILE_ERROR_INVALID_OPERATION;
[email protected]a321b9632012-06-14 03:29:171127 return;
1128 }
1129
1130 // Get the subdir type and path for the unmounted state.
1131 CacheSubDirectoryType unmounted_subdir =
[email protected]02821102012-07-12 20:19:171132 cache_entry.is_pinned() ? CACHE_TYPE_PERSISTENT : CACHE_TYPE_TMP;
[email protected]a321b9632012-06-14 03:29:171133 FilePath unmounted_path = GetCacheFilePath(
1134 resource_id, md5, unmounted_subdir, CACHED_FILE_FROM_SERVER);
1135
1136 // Get the subdir type and path for the mounted state.
1137 CacheSubDirectoryType mounted_subdir = CACHE_TYPE_PERSISTENT;
1138 FilePath mounted_path = GetCacheFilePath(
1139 resource_id, md5, mounted_subdir, CACHED_FILE_MOUNTED);
1140
1141 // Determine the source and destination paths for moving the cache blob.
1142 FilePath source_path;
1143 CacheSubDirectoryType dest_subdir;
[email protected]a321b9632012-06-14 03:29:171144 if (to_mount) {
1145 source_path = unmounted_path;
1146 *cache_file_path = mounted_path;
1147 dest_subdir = mounted_subdir;
[email protected]02821102012-07-12 20:19:171148 cache_entry.set_is_mounted(true);
[email protected]a321b9632012-06-14 03:29:171149 } else {
1150 source_path = mounted_path;
1151 *cache_file_path = unmounted_path;
1152 dest_subdir = unmounted_subdir;
[email protected]02821102012-07-12 20:19:171153 cache_entry.set_is_mounted(false);
[email protected]a321b9632012-06-14 03:29:171154 }
1155
1156 // Move cache blob from source path to destination path.
1157 *error = ModifyCacheState(source_path, *cache_file_path,
1158 FILE_OPERATION_MOVE, FilePath(), false);
[email protected]11f60db2012-08-23 16:28:151159 if (*error == DRIVE_FILE_OK) {
[email protected]a321b9632012-06-14 03:29:171160 // Now that cache operation is complete, update cache map
[email protected]48477fe2012-07-12 17:45:081161 cache_entry.set_md5(md5);
[email protected]02821102012-07-12 20:19:171162 cache_entry.set_is_persistent(dest_subdir == CACHE_TYPE_PERSISTENT);
[email protected]48477fe2012-07-12 17:45:081163 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry);
[email protected]a321b9632012-06-14 03:29:171164 }
1165}
1166
[email protected]fb371812012-08-22 16:05:231167void DriveCache::MarkDirty(const std::string& resource_id,
[email protected]c960d222012-06-15 10:03:501168 const std::string& md5,
1169 FileOperationType file_operation_type,
[email protected]11f60db2012-08-23 16:28:151170 DriveFileError* error,
[email protected]c960d222012-06-15 10:03:501171 FilePath* cache_file_path) {
1172 AssertOnSequencedWorkerPool();
1173 DCHECK(error);
1174 DCHECK(cache_file_path);
1175
1176 // If file has already been marked dirty in previous instance of chrome, we
1177 // would have lost the md5 info during cache initialization, because the file
1178 // would have been renamed to .local extension.
1179 // So, search for entry in cache without comparing md5.
[email protected]c960d222012-06-15 10:03:501180
1181 // Marking a file dirty means its entry and actual file blob must exist in
1182 // cache.
[email protected]28a64092012-08-21 10:01:121183 DriveCacheEntry cache_entry;
[email protected]b22f87f2012-07-12 10:53:171184 if (!GetCacheEntry(resource_id, std::string(), &cache_entry) ||
[email protected]02821102012-07-12 20:19:171185 !cache_entry.is_present()) {
[email protected]c960d222012-06-15 10:03:501186 LOG(WARNING) << "Can't mark dirty a file that wasn't cached: res_id="
1187 << resource_id
1188 << ", md5=" << md5;
[email protected]11f60db2012-08-23 16:28:151189 *error = DRIVE_FILE_ERROR_NOT_FOUND;
[email protected]c960d222012-06-15 10:03:501190 return;
1191 }
1192
1193 // If a file is already dirty (i.e. MarkDirtyInCache was called before),
1194 // delete outgoing symlink if it exists.
1195 // TODO(benchan): We should only delete outgoing symlink if file is currently
1196 // not being uploaded. However, for now, cache doesn't know if uploading of a
1197 // file is in progress. Per zel, the upload process should be canceled before
1198 // MarkDirtyInCache is called again.
[email protected]02821102012-07-12 20:19:171199 if (cache_entry.is_dirty()) {
[email protected]c960d222012-06-15 10:03:501200 // The file must be in persistent dir.
[email protected]02821102012-07-12 20:19:171201 DCHECK(cache_entry.is_persistent());
[email protected]c960d222012-06-15 10:03:501202
1203 // Determine symlink path in outgoing dir, so as to remove it.
1204 FilePath symlink_path = GetCacheFilePath(
1205 resource_id,
1206 std::string(),
1207 CACHE_TYPE_OUTGOING,
1208 CACHED_FILE_FROM_SERVER);
1209
1210 // We're not moving files here, so simply use empty FilePath for both
1211 // |source_path| and |dest_path| because ModifyCacheState only move files
1212 // if source and destination are different.
1213 *error = ModifyCacheState(
1214 FilePath(), // non-applicable source path
1215 FilePath(), // non-applicable dest path
1216 file_operation_type,
1217 symlink_path,
1218 false /* don't create symlink */);
1219
1220 // Determine current path of dirty file.
[email protected]11f60db2012-08-23 16:28:151221 if (*error == DRIVE_FILE_OK) {
[email protected]c960d222012-06-15 10:03:501222 *cache_file_path = GetCacheFilePath(
1223 resource_id,
1224 md5,
1225 CACHE_TYPE_PERSISTENT,
1226 CACHED_FILE_LOCALLY_MODIFIED);
1227 }
1228 return;
1229 }
1230
1231 // Move file to persistent dir with new .local extension.
1232
1233 // Get the current path of the file in cache.
1234 FilePath source_path = GetCacheFilePath(
1235 resource_id,
1236 md5,
[email protected]b22f87f2012-07-12 10:53:171237 GetSubDirectoryType(cache_entry),
[email protected]c960d222012-06-15 10:03:501238 CACHED_FILE_FROM_SERVER);
1239
1240 // Determine destination path.
[email protected]3dc88ee2012-07-11 21:04:111241 const CacheSubDirectoryType sub_dir_type = CACHE_TYPE_PERSISTENT;
[email protected]c960d222012-06-15 10:03:501242 *cache_file_path = GetCacheFilePath(resource_id,
1243 md5,
1244 sub_dir_type,
1245 CACHED_FILE_LOCALLY_MODIFIED);
1246
1247 // If file is pinned, update symlink in pinned dir.
1248 FilePath symlink_path;
[email protected]02821102012-07-12 20:19:171249 if (cache_entry.is_pinned()) {
[email protected]c960d222012-06-15 10:03:501250 symlink_path = GetCacheFilePath(resource_id,
1251 std::string(),
1252 CACHE_TYPE_PINNED,
1253 CACHED_FILE_FROM_SERVER);
1254 }
1255
1256 *error = ModifyCacheState(
1257 source_path,
1258 *cache_file_path,
1259 file_operation_type,
1260 symlink_path,
1261 !symlink_path.empty() /* create symlink */);
1262
[email protected]11f60db2012-08-23 16:28:151263 if (*error == DRIVE_FILE_OK) {
[email protected]c960d222012-06-15 10:03:501264 // Now that file operations have completed, update cache map.
[email protected]48477fe2012-07-12 17:45:081265 cache_entry.set_md5(md5);
[email protected]02821102012-07-12 20:19:171266 cache_entry.set_is_dirty(true);
1267 cache_entry.set_is_persistent(sub_dir_type == CACHE_TYPE_PERSISTENT);
[email protected]48477fe2012-07-12 17:45:081268 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry);
[email protected]c960d222012-06-15 10:03:501269 }
1270}
1271
[email protected]fb371812012-08-22 16:05:231272void DriveCache::CommitDirty(const std::string& resource_id,
[email protected]a321b9632012-06-14 03:29:171273 const std::string& md5,
1274 FileOperationType file_operation_type,
[email protected]11f60db2012-08-23 16:28:151275 DriveFileError* error) {
[email protected]a321b9632012-06-14 03:29:171276 AssertOnSequencedWorkerPool();
1277 DCHECK(error);
1278
1279 // If file has already been marked dirty in previous instance of chrome, we
1280 // would have lost the md5 info during cache initialization, because the file
1281 // would have been renamed to .local extension.
1282 // So, search for entry in cache without comparing md5.
[email protected]a321b9632012-06-14 03:29:171283
1284 // Committing a file dirty means its entry and actual file blob must exist in
1285 // cache.
[email protected]28a64092012-08-21 10:01:121286 DriveCacheEntry cache_entry;
[email protected]b22f87f2012-07-12 10:53:171287 if (!GetCacheEntry(resource_id, std::string(), &cache_entry) ||
[email protected]02821102012-07-12 20:19:171288 !cache_entry.is_present()) {
[email protected]a321b9632012-06-14 03:29:171289 LOG(WARNING) << "Can't commit dirty a file that wasn't cached: res_id="
1290 << resource_id
1291 << ", md5=" << md5;
[email protected]11f60db2012-08-23 16:28:151292 *error = DRIVE_FILE_ERROR_NOT_FOUND;
[email protected]a321b9632012-06-14 03:29:171293 return;
1294 }
1295
1296 // If a file is not dirty (it should have been marked dirty via
1297 // MarkDirtyInCache), committing it dirty is an invalid operation.
[email protected]02821102012-07-12 20:19:171298 if (!cache_entry.is_dirty()) {
[email protected]a321b9632012-06-14 03:29:171299 LOG(WARNING) << "Can't commit a non-dirty file: res_id="
1300 << resource_id
1301 << ", md5=" << md5;
[email protected]11f60db2012-08-23 16:28:151302 *error = DRIVE_FILE_ERROR_INVALID_OPERATION;
[email protected]a321b9632012-06-14 03:29:171303 return;
1304 }
1305
1306 // Dirty files must be in persistent dir.
[email protected]02821102012-07-12 20:19:171307 DCHECK(cache_entry.is_persistent());
[email protected]a321b9632012-06-14 03:29:171308
1309 // Create symlink in outgoing dir.
1310 FilePath symlink_path = GetCacheFilePath(resource_id,
1311 std::string(),
1312 CACHE_TYPE_OUTGOING,
1313 CACHED_FILE_FROM_SERVER);
1314
1315 // Get target path of symlink i.e. current path of the file in cache.
1316 FilePath target_path = GetCacheFilePath(resource_id,
1317 md5,
[email protected]b22f87f2012-07-12 10:53:171318 GetSubDirectoryType(cache_entry),
[email protected]a321b9632012-06-14 03:29:171319 CACHED_FILE_LOCALLY_MODIFIED);
1320
1321 // Since there's no need to move files, use |target_path| for both
1322 // |source_path| and |dest_path|, because ModifyCacheState only moves files
1323 // if source and destination are different.
1324 *error = ModifyCacheState(target_path, // source
1325 target_path, // destination
1326 file_operation_type,
1327 symlink_path,
1328 true /* create symlink */);
1329}
1330
[email protected]fb371812012-08-22 16:05:231331void DriveCache::ClearDirty(const std::string& resource_id,
[email protected]a321b9632012-06-14 03:29:171332 const std::string& md5,
1333 FileOperationType file_operation_type,
[email protected]11f60db2012-08-23 16:28:151334 DriveFileError* error) {
[email protected]a321b9632012-06-14 03:29:171335 AssertOnSequencedWorkerPool();
1336 DCHECK(error);
1337
1338 // |md5| is the new .<md5> extension to rename the file to.
1339 // So, search for entry in cache without comparing md5.
[email protected]28a64092012-08-21 10:01:121340 DriveCacheEntry cache_entry;
[email protected]a321b9632012-06-14 03:29:171341
1342 // Clearing a dirty file means its entry and actual file blob must exist in
1343 // cache.
[email protected]b22f87f2012-07-12 10:53:171344 if (!GetCacheEntry(resource_id, std::string(), &cache_entry) ||
[email protected]02821102012-07-12 20:19:171345 !cache_entry.is_present()) {
[email protected]a321b9632012-06-14 03:29:171346 LOG(WARNING) << "Can't clear dirty state of a file that wasn't cached: "
1347 << "res_id=" << resource_id
1348 << ", md5=" << md5;
[email protected]11f60db2012-08-23 16:28:151349 *error = DRIVE_FILE_ERROR_NOT_FOUND;
[email protected]a321b9632012-06-14 03:29:171350 return;
1351 }
1352
1353 // If a file is not dirty (it should have been marked dirty via
1354 // MarkDirtyInCache), clearing its dirty state is an invalid operation.
[email protected]02821102012-07-12 20:19:171355 if (!cache_entry.is_dirty()) {
[email protected]a321b9632012-06-14 03:29:171356 LOG(WARNING) << "Can't clear dirty state of a non-dirty file: res_id="
1357 << resource_id
1358 << ", md5=" << md5;
[email protected]11f60db2012-08-23 16:28:151359 *error = DRIVE_FILE_ERROR_INVALID_OPERATION;
[email protected]a321b9632012-06-14 03:29:171360 return;
1361 }
1362
1363 // File must be dirty and hence in persistent dir.
[email protected]02821102012-07-12 20:19:171364 DCHECK(cache_entry.is_persistent());
[email protected]a321b9632012-06-14 03:29:171365
1366 // Get the current path of the file in cache.
1367 FilePath source_path = GetCacheFilePath(resource_id,
1368 md5,
[email protected]b22f87f2012-07-12 10:53:171369 GetSubDirectoryType(cache_entry),
[email protected]a321b9632012-06-14 03:29:171370 CACHED_FILE_LOCALLY_MODIFIED);
1371
1372 // Determine destination path.
1373 // If file is pinned, move it to persistent dir with .md5 extension;
1374 // otherwise, move it to tmp dir with .md5 extension.
[email protected]3dc88ee2012-07-11 21:04:111375 const CacheSubDirectoryType sub_dir_type =
[email protected]02821102012-07-12 20:19:171376 cache_entry.is_pinned() ? CACHE_TYPE_PERSISTENT : CACHE_TYPE_TMP;
[email protected]a321b9632012-06-14 03:29:171377 FilePath dest_path = GetCacheFilePath(resource_id,
1378 md5,
1379 sub_dir_type,
1380 CACHED_FILE_FROM_SERVER);
1381
1382 // Delete symlink in outgoing dir.
1383 FilePath symlink_path = GetCacheFilePath(resource_id,
1384 std::string(),
1385 CACHE_TYPE_OUTGOING,
1386 CACHED_FILE_FROM_SERVER);
1387
1388 *error = ModifyCacheState(source_path,
1389 dest_path,
1390 file_operation_type,
1391 symlink_path,
1392 false /* don't create symlink */);
1393
1394 // If file is pinned, update symlink in pinned dir.
[email protected]11f60db2012-08-23 16:28:151395 if (*error == DRIVE_FILE_OK && cache_entry.is_pinned()) {
[email protected]a321b9632012-06-14 03:29:171396 symlink_path = GetCacheFilePath(resource_id,
1397 std::string(),
1398 CACHE_TYPE_PINNED,
1399 CACHED_FILE_FROM_SERVER);
1400
1401 // Since there's no moving of files here, use |dest_path| for both
1402 // |source_path| and |dest_path|, because ModifyCacheState only moves files
1403 // if source and destination are different.
1404 *error = ModifyCacheState(dest_path, // source path
1405 dest_path, // destination path
1406 file_operation_type,
1407 symlink_path,
1408 true /* create symlink */);
1409 }
1410
[email protected]11f60db2012-08-23 16:28:151411 if (*error == DRIVE_FILE_OK) {
[email protected]a321b9632012-06-14 03:29:171412 // Now that file operations have completed, update cache map.
[email protected]48477fe2012-07-12 17:45:081413 cache_entry.set_md5(md5);
[email protected]02821102012-07-12 20:19:171414 cache_entry.set_is_dirty(false);
1415 cache_entry.set_is_persistent(sub_dir_type == CACHE_TYPE_PERSISTENT);
[email protected]48477fe2012-07-12 17:45:081416 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry);
[email protected]a321b9632012-06-14 03:29:171417 }
1418}
1419
[email protected]fb371812012-08-22 16:05:231420void DriveCache::Remove(const std::string& resource_id,
[email protected]11f60db2012-08-23 16:28:151421 DriveFileError* error) {
[email protected]a321b9632012-06-14 03:29:171422 AssertOnSequencedWorkerPool();
1423 DCHECK(error);
1424
[email protected]3423871a2012-07-12 00:41:271425 // MD5 is not passed into RemoveCacheEntry because we would delete all
1426 // cache files corresponding to <resource_id> regardless of the md5.
[email protected]a321b9632012-06-14 03:29:171427 // So, search for entry in cache without taking md5 into account.
[email protected]28a64092012-08-21 10:01:121428 DriveCacheEntry cache_entry;
[email protected]a321b9632012-06-14 03:29:171429
1430 // If entry doesn't exist or is dirty or mounted in cache, nothing to do.
[email protected]b22f87f2012-07-12 10:53:171431 const bool entry_found =
1432 GetCacheEntry(resource_id, std::string(), &cache_entry);
[email protected]02821102012-07-12 20:19:171433 if (!entry_found || cache_entry.is_dirty() || cache_entry.is_mounted()) {
[email protected]a321b9632012-06-14 03:29:171434 DVLOG(1) << "Entry is "
[email protected]b22f87f2012-07-12 10:53:171435 << (entry_found ?
[email protected]02821102012-07-12 20:19:171436 (cache_entry.is_dirty() ? "dirty" : "mounted") :
[email protected]a321b9632012-06-14 03:29:171437 "non-existent")
1438 << " in cache, not removing";
[email protected]11f60db2012-08-23 16:28:151439 *error = DRIVE_FILE_OK;
[email protected]a321b9632012-06-14 03:29:171440 return;
1441 }
1442
1443 // Determine paths to delete all cache versions of |resource_id| in
1444 // persistent, tmp and pinned directories.
1445 std::vector<FilePath> paths_to_delete;
1446
1447 // For files in persistent and tmp dirs, delete files that match
1448 // "<resource_id>.*".
1449 paths_to_delete.push_back(GetCacheFilePath(resource_id,
[email protected]ca5f6da2012-06-18 12:54:591450 util::kWildCard,
[email protected]a321b9632012-06-14 03:29:171451 CACHE_TYPE_PERSISTENT,
1452 CACHED_FILE_FROM_SERVER));
1453 paths_to_delete.push_back(GetCacheFilePath(resource_id,
[email protected]ca5f6da2012-06-18 12:54:591454 util::kWildCard,
[email protected]a321b9632012-06-14 03:29:171455 CACHE_TYPE_TMP,
1456 CACHED_FILE_FROM_SERVER));
1457
1458 // For pinned files, filename is "<resource_id>" with no extension, so delete
1459 // "<resource_id>".
1460 paths_to_delete.push_back(GetCacheFilePath(resource_id,
1461 std::string(),
1462 CACHE_TYPE_PINNED,
1463 CACHED_FILE_FROM_SERVER));
1464
1465 // Don't delete locally modified (i.e. dirty and possibly outgoing) files.
1466 // Since we're not deleting outgoing symlinks, we don't need to append
1467 // outgoing path to |paths_to_delete|.
1468 FilePath path_to_keep = GetCacheFilePath(resource_id,
1469 std::string(),
1470 CACHE_TYPE_PERSISTENT,
1471 CACHED_FILE_LOCALLY_MODIFIED);
1472
1473 for (size_t i = 0; i < paths_to_delete.size(); ++i) {
1474 DeleteFilesSelectively(paths_to_delete[i], path_to_keep);
1475 }
1476
1477 // Now that all file operations have completed, remove from cache map.
[email protected]3423871a2012-07-12 00:41:271478 metadata_->RemoveCacheEntry(resource_id);
[email protected]a321b9632012-06-14 03:29:171479
[email protected]11f60db2012-08-23 16:28:151480 *error = DRIVE_FILE_OK;
[email protected]a321b9632012-06-14 03:29:171481}
1482
[email protected]11f60db2012-08-23 16:28:151483void DriveCache::ClearAll(DriveFileError* error) {
[email protected]f861b392012-08-03 20:41:121484 AssertOnSequencedWorkerPool();
1485 DCHECK(error);
1486
1487 bool success = file_util::Delete(cache_root_path_, true);
[email protected]322e0032012-10-07 01:55:531488 if (!success) {
1489 LOG(WARNING) << "Failed to delete the cache directory";
1490 *error = DRIVE_FILE_ERROR_FAILED;
1491 return;
1492 }
[email protected]f861b392012-08-03 20:41:121493
[email protected]322e0032012-10-07 01:55:531494 Initialize(&success);
1495 if (!success) {
1496 LOG(WARNING) << "Failed to initialize the cache";
1497 *error = DRIVE_FILE_ERROR_FAILED;
1498 return;
1499 }
1500
1501 *error = DRIVE_FILE_OK;
1502 return;
[email protected]f861b392012-08-03 20:41:121503}
1504
[email protected]11f60db2012-08-23 16:28:151505void DriveCache::OnPinned(DriveFileError* error,
[email protected]73f9c742012-06-15 07:37:131506 const std::string& resource_id,
1507 const std::string& md5,
1508 const CacheOperationCallback& callback) {
1509 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1510 DCHECK(error);
1511
1512 if (!callback.is_null())
1513 callback.Run(*error, resource_id, md5);
1514
[email protected]11f60db2012-08-23 16:28:151515 if (*error == DRIVE_FILE_OK)
[email protected]73f9c742012-06-15 07:37:131516 FOR_EACH_OBSERVER(Observer, observers_, OnCachePinned(resource_id, md5));
[email protected]3653146a2012-05-29 13:41:471517}
1518
[email protected]11f60db2012-08-23 16:28:151519void DriveCache::OnUnpinned(DriveFileError* error,
[email protected]73f9c742012-06-15 07:37:131520 const std::string& resource_id,
1521 const std::string& md5,
1522 const CacheOperationCallback& callback) {
1523 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1524 DCHECK(error);
[email protected]a321b9632012-06-14 03:29:171525
[email protected]73f9c742012-06-15 07:37:131526 if (!callback.is_null())
1527 callback.Run(*error, resource_id, md5);
[email protected]a321b9632012-06-14 03:29:171528
[email protected]11f60db2012-08-23 16:28:151529 if (*error == DRIVE_FILE_OK)
[email protected]73f9c742012-06-15 07:37:131530 FOR_EACH_OBSERVER(Observer, observers_, OnCacheUnpinned(resource_id, md5));
[email protected]a321b9632012-06-14 03:29:171531
[email protected]73f9c742012-06-15 07:37:131532 // Now the file is moved from "persistent" to "tmp" directory.
1533 // It's a chance to free up space if needed.
1534 bool* has_enough_space = new bool(false);
[email protected]ddbf2052012-07-13 15:07:021535 blocking_task_runner_->PostTask(
[email protected]73f9c742012-06-15 07:37:131536 FROM_HERE,
[email protected]fb371812012-08-22 16:05:231537 base::Bind(&DriveCache::FreeDiskSpaceIfNeededFor,
[email protected]73f9c742012-06-15 07:37:131538 base::Unretained(this),
1539 0,
1540 base::Owned(has_enough_space)));
[email protected]3653146a2012-05-29 13:41:471541}
1542
[email protected]11f60db2012-08-23 16:28:151543void DriveCache::OnCommitDirty(DriveFileError* error,
[email protected]d7664c22012-06-18 19:35:491544 const std::string& resource_id,
1545 const std::string& md5,
1546 const CacheOperationCallback& callback) {
1547 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1548 DCHECK(error);
1549
1550 if (!callback.is_null())
1551 callback.Run(*error, resource_id, md5);
1552
[email protected]11f60db2012-08-23 16:28:151553 if (*error == DRIVE_FILE_OK)
[email protected]d7664c22012-06-18 19:35:491554 FOR_EACH_OBSERVER(Observer, observers_, OnCacheCommitted(resource_id));
1555}
1556
[email protected]fb371812012-08-22 16:05:231557void DriveCache::GetCacheEntryHelper(const std::string& resource_id,
[email protected]4324fdc2012-06-29 05:32:481558 const std::string& md5,
1559 bool* success,
[email protected]28a64092012-08-21 10:01:121560 DriveCacheEntry* cache_entry) {
[email protected]4324fdc2012-06-29 05:32:481561 AssertOnSequencedWorkerPool();
1562 DCHECK(success);
1563 DCHECK(cache_entry);
1564
[email protected]b22f87f2012-07-12 10:53:171565 *success = GetCacheEntry(resource_id, md5, cache_entry);
[email protected]4324fdc2012-06-29 05:32:481566}
1567
[email protected]01ba15f72012-06-09 00:41:051568// static
[email protected]fb371812012-08-22 16:05:231569FilePath DriveCache::GetCacheRootPath(Profile* profile) {
[email protected]01ba15f72012-06-09 00:41:051570 FilePath cache_base_path;
1571 chrome::GetUserCacheDirectory(profile->GetPath(), &cache_base_path);
1572 FilePath cache_root_path =
[email protected]fb371812012-08-22 16:05:231573 cache_base_path.Append(chrome::kDriveCacheDirname);
1574 return cache_root_path.Append(kDriveCacheVersionDir);
[email protected]01ba15f72012-06-09 00:41:051575}
1576
[email protected]30d9dda2012-06-30 05:56:281577// static
[email protected]fb371812012-08-22 16:05:231578std::vector<FilePath> DriveCache::GetCachePaths(
[email protected]30d9dda2012-06-30 05:56:281579 const FilePath& cache_root_path) {
1580 std::vector<FilePath> cache_paths;
[email protected]fb371812012-08-22 16:05:231581 // The order should match DriveCache::CacheSubDirectoryType enum.
1582 cache_paths.push_back(cache_root_path.Append(kDriveCacheMetaDir));
1583 cache_paths.push_back(cache_root_path.Append(kDriveCachePinnedDir));
1584 cache_paths.push_back(cache_root_path.Append(kDriveCacheOutgoingDir));
1585 cache_paths.push_back(cache_root_path.Append(kDriveCachePersistentDir));
1586 cache_paths.push_back(cache_root_path.Append(kDriveCacheTmpDir));
1587 cache_paths.push_back(cache_root_path.Append(kDriveCacheTmpDownloadsDir));
1588 cache_paths.push_back(cache_root_path.Append(kDriveCacheTmpDocumentsDir));
[email protected]30d9dda2012-06-30 05:56:281589 return cache_paths;
1590}
1591
1592// static
[email protected]fb371812012-08-22 16:05:231593bool DriveCache::CreateCacheDirectories(
[email protected]30d9dda2012-06-30 05:56:281594 const std::vector<FilePath>& paths_to_create) {
1595 bool success = true;
1596
1597 for (size_t i = 0; i < paths_to_create.size(); ++i) {
1598 if (file_util::DirectoryExists(paths_to_create[i]))
1599 continue;
1600
1601 if (!file_util::CreateDirectory(paths_to_create[i])) {
1602 // Error creating this directory, record error and proceed with next one.
1603 success = false;
1604 PLOG(ERROR) << "Error creating directory " << paths_to_create[i].value();
1605 } else {
1606 DVLOG(1) << "Created directory " << paths_to_create[i].value();
1607 }
1608 }
1609 return success;
1610}
1611
[email protected]fae353a2012-07-11 23:30:271612// static
[email protected]fb371812012-08-22 16:05:231613DriveCache::CacheSubDirectoryType DriveCache::GetSubDirectoryType(
[email protected]28a64092012-08-21 10:01:121614 const DriveCacheEntry& cache_entry) {
[email protected]02821102012-07-12 20:19:171615 return cache_entry.is_persistent() ? CACHE_TYPE_PERSISTENT : CACHE_TYPE_TMP;
[email protected]fae353a2012-07-11 23:30:271616}
1617
[email protected]a321b9632012-06-14 03:29:171618void SetFreeDiskSpaceGetterForTesting(FreeDiskSpaceGetterInterface* getter) {
1619 delete global_free_disk_getter_for_testing; // Safe to delete NULL;
1620 global_free_disk_getter_for_testing = getter;
1621}
1622
[email protected]3653146a2012-05-29 13:41:471623} // namespace gdata