blob: a9597cfcc90fe50d852f0a043fd9d25a704e0a30 [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
yawano3513e142016-04-20 00:42:425#include "components/drive/chromeos/file_cache.h"
[email protected]3653146a2012-05-29 13:41:476
okac6aac502016-05-23 12:16:587#include <linux/fs.h>
8#include <sys/ioctl.h>
9#include <sys/xattr.h>
yawano1c325bf2016-04-20 06:37:0310
yawano4c36b9a02015-10-23 06:17:2311#include <queue>
[email protected]3653146a2012-05-29 13:41:4712#include <vector>
13
lukasza037c10b12015-06-12 04:21:2514#include "base/bind.h"
15#include "base/bind_helpers.h"
[email protected]8b03ab3a2014-01-15 17:52:4516#include "base/callback_helpers.h"
okac6aac502016-05-23 12:16:5817#include "base/files/file.h"
[email protected]25a4c1c2013-06-08 04:53:3618#include "base/files/file_enumerator.h"
thestig18dfb7a52014-08-26 10:44:0419#include "base/files/file_util.h"
lukasza037c10b12015-06-12 04:21:2520#include "base/location.h"
[email protected]3653146a2012-05-29 13:41:4721#include "base/logging.h"
asvitkine776f9db2017-01-25 21:39:2922#include "base/metrics/histogram_macros.h"
okac6aac502016-05-23 12:16:5823#include "base/stl_util.h"
[email protected]5c073322013-06-11 08:03:3024#include "base/strings/string_util.h"
25#include "base/strings/stringprintf.h"
[email protected]a321b9632012-06-14 03:29:1726#include "base/sys_info.h"
avibc5337b2015-12-25 23:16:3327#include "build/build_config.h"
lukasza01b9d55a2015-07-21 15:19:2528#include "components/drive/drive.pb.h"
lukasza8acc4eb2015-07-20 20:57:2029#include "components/drive/drive_api_util.h"
lukasza6364a022015-08-21 01:13:2430#include "components/drive/file_system_core_util.h"
31#include "components/drive/resource_metadata_storage.h"
[email protected]8b03ab3a2014-01-15 17:52:4532#include "google_apis/drive/task_util.h"
[email protected]d96cf752014-04-09 04:05:2833#include "net/base/filename_util.h"
[email protected]b7af4f12013-10-31 06:57:4534#include "net/base/mime_sniffer.h"
35#include "net/base/mime_util.h"
[email protected]7986b8d2012-06-14 15:05:1436
[email protected]d9d04df2012-10-12 07:06:3537namespace drive {
[email protected]59c7cdec2013-05-07 04:17:1338namespace internal {
[email protected]3653146a2012-05-29 13:41:4739namespace {
40
okac6aac502016-05-23 12:16:5841typedef std::pair<base::File::Info, ResourceEntry> CacheInfo;
42typedef long FileAttributes; // NOLINT(runtime/int)
43
[email protected]c9e4738d2013-08-26 03:04:0744// Returns ID extracted from the path.
45std::string GetIdFromPath(const base::FilePath& path) {
[email protected]91a464e62013-07-10 09:30:0646 return util::UnescapeCacheFileName(path.BaseName().AsUTF8Unsafe());
47}
48
yawano9fd1e632016-02-04 09:00:0649base::FilePath GetPathForId(const base::FilePath& cache_directory,
50 const std::string& id) {
51 return cache_directory.Append(
52 base::FilePath::FromUTF8Unsafe(util::EscapeCacheFileName(id)));
53}
54
oka7bd26bbf2016-10-14 06:59:0655// Returns if the filesystem backing |path| supports file attributes.
56// This will return false if the filesystem is for example tmpfs, which is used
57// for ephemeral mode.
58bool IsFileAttributesSupported(const base::FilePath& path) {
59 if (getxattr(path.value().c_str(), "user.foo", nullptr, 0) >= 0) {
60 return true;
61 }
62 return errno != ENOTSUP;
63}
64
okac6aac502016-05-23 12:16:5865// Sets extended file attribute as |name| |value| pair.
66bool SetExtendedFileAttributes(const base::FilePath& path,
67 const std::string& name, const std::string& value) {
68 return setxattr(path.value().c_str(), name.c_str(), value.c_str(),
69 value.size() + 1, 0) == 0;
70}
71
72// Changes attributes of the file with |flags|, e.g. FS_NODUMP_FL (cryptohome
73// will remove Drive caches with this attribute).
74// See linux/fs.h for available flags, and chattr(1) which does similar thing.
75// Returns whether operation succeeded.
76bool SetFileAttributes(const base::FilePath& path, FileAttributes flags) {
77 base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
78 if (!file.IsValid()) {
79 PLOG(ERROR) << "Failed to open file: " << path.value();
80 return false;
81 }
82 if (ioctl(file.GetPlatformFile(), FS_IOC_SETFLAGS, &flags) < 0) {
83 PLOG(ERROR) << "ioctl: " << path.value();
84 return false;
85 }
86 return true;
87}
88
89// Gets file attributes similarly to lsattr(1). Returns flags or -1 on error.
90// See linux/fs.h for the definition of the returned flags e.g. FS_NODUMP_FL.
91FileAttributes GetFileAttributes(const base::FilePath& path) {
92 base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
93 if (!file.IsValid()) {
94 PLOG(ERROR) << "Failed to open file: " << path.value();
95 return -1;
96 }
97 FileAttributes flags = 0;
98 if (ioctl(file.GetPlatformFile(), FS_IOC_GETFLAGS, &flags) < 0) {
99 PLOG(ERROR) << "ioctl: " << path.value();
100 return -1;
101 }
102 return flags;
103}
104
oka7bd26bbf2016-10-14 06:59:06105// Marks the cache file to be removable by cryptohome, or do nothing if
106// underlying filesystem doesn't support file attributes, as tmpfs for ephemeral
107// mode.
okac6aac502016-05-23 12:16:58108bool SetRemovable(const base::FilePath& path) {
oka7bd26bbf2016-10-14 06:59:06109 // For ephemeral mode.
110 if (!IsFileAttributesSupported(path)) {
111 return true;
112 }
okac6aac502016-05-23 12:16:58113 FileAttributes flags = GetFileAttributes(path);
114 if (flags < 0) return false;
115 if ((flags & FS_NODUMP_FL) == FS_NODUMP_FL) return true;
116
117 return SetFileAttributes(path, flags | FS_NODUMP_FL);
118}
119
oka7bd26bbf2016-10-14 06:59:06120// Marks the cache file to be unremovable by cryptohome, or do nothing if
121// underlying filesystem doesn't support file attributes, as tmpfs for ephemeral
122// mode.
okac6aac502016-05-23 12:16:58123bool UnsetRemovable(const base::FilePath& path) {
oka7bd26bbf2016-10-14 06:59:06124 // For ephemeral mode.
125 if (!IsFileAttributesSupported(path)) {
126 return true;
127 }
okac6aac502016-05-23 12:16:58128 FileAttributes flags = GetFileAttributes(path);
129 if (flags < 0) return false;
130 if ((flags & FS_NODUMP_FL) == 0) return true;
131
132 return SetFileAttributes(path, flags & ~FS_NODUMP_FL);
133}
134
oka7bd26bbf2016-10-14 06:59:06135// Marks |path| as drive cache dir, or do nothing if underlying filesystem
136// doesn't support file attributes, as tmpfs for ephemeral mode. Returns if the
137// operation succeeded.
okac6aac502016-05-23 12:16:58138bool MarkAsDriveCacheDir(const base::FilePath& path) {
oka7bd26bbf2016-10-14 06:59:06139 // For ephemeral mode.
140 if (!IsFileAttributesSupported(path)) {
141 return true;
142 }
okac6aac502016-05-23 12:16:58143 return SetRemovable(path)
144 && SetExtendedFileAttributes(path, FileCache::kGCacheFilesAttribute, "");
145}
yawano4c36b9a02015-10-23 06:17:23146
147class CacheInfoLatestCompare {
148 public:
149 bool operator()(const CacheInfo& info_a, const CacheInfo& info_b) {
150 return info_a.first.last_accessed < info_b.first.last_accessed;
151 }
152};
153
fukino6380c07c2016-06-09 07:28:29154// Returns true if the cache file is present.
155bool IsPresent(const ResourceEntry& entry) {
156 return entry.has_file_specific_info() &&
157 entry.file_specific_info().has_cache_state() &&
158 entry.file_specific_info().cache_state().is_present();
159}
160
yawano4c36b9a02015-10-23 06:17:23161const size_t kMaxNumOfEvictedCacheFiles = 30000;
162
[email protected]a321b9632012-06-14 03:29:17163} // namespace
[email protected]32a7fc852012-06-08 17:25:50164
okac6aac502016-05-23 12:16:58165// static
166const char FileCache::kGCacheFilesAttribute[] = "user.GCacheFiles";
167
[email protected]2df61e12013-06-21 16:00:09168FileCache::FileCache(ResourceMetadataStorage* storage,
[email protected]e07f7b7b2013-06-19 03:43:12169 const base::FilePath& cache_file_directory,
[email protected]eca3fc92013-05-01 03:53:40170 base::SequencedTaskRunner* blocking_task_runner,
171 FreeDiskSpaceGetterInterface* free_disk_space_getter)
[email protected]2df61e12013-06-21 16:00:09172 : cache_file_directory_(cache_file_directory),
[email protected]ddbf2052012-07-13 15:07:02173 blocking_task_runner_(blocking_task_runner),
[email protected]2df61e12013-06-21 16:00:09174 storage_(storage),
[email protected]f6fd98a2012-12-14 00:04:02175 free_disk_space_getter_(free_disk_space_getter),
yawano4c36b9a02015-10-23 06:17:23176 max_num_of_evicted_cache_files_(kMaxNumOfEvictedCacheFiles),
[email protected]9c009092013-05-01 03:14:09177 weak_ptr_factory_(this) {
[email protected]144b6c42013-06-14 07:30:38178 DCHECK(blocking_task_runner_.get());
[email protected]3653146a2012-05-29 13:41:47179}
180
[email protected]eca3fc92013-05-01 03:53:40181FileCache::~FileCache() {
[email protected]17196ee2012-12-13 06:23:51182 // Must be on the sequenced worker pool, as |metadata_| must be deleted on
183 // the sequenced worker pool.
[email protected]73f9c742012-06-15 07:37:13184 AssertOnSequencedWorkerPool();
[email protected]3653146a2012-05-29 13:41:47185}
186
yawano4c36b9a02015-10-23 06:17:23187void FileCache::SetMaxNumOfEvictedCacheFilesForTest(
188 size_t max_num_of_evicted_cache_files) {
189 max_num_of_evicted_cache_files_ = max_num_of_evicted_cache_files;
190}
191
[email protected]c9e4738d2013-08-26 03:04:07192base::FilePath FileCache::GetCacheFilePath(const std::string& id) const {
yawano9fd1e632016-02-04 09:00:06193 return GetPathForId(cache_file_directory_, id);
[email protected]32a7fc852012-06-08 17:25:50194}
195
[email protected]eca3fc92013-05-01 03:53:40196void FileCache::AssertOnSequencedWorkerPool() {
[email protected]8e37b9b2013-12-11 09:06:02197 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
[email protected]fcc92a52012-06-08 22:54:16198}
199
[email protected]eca3fc92013-05-01 03:53:40200bool FileCache::IsUnderFileCacheDirectory(const base::FilePath& path) const {
[email protected]e07f7b7b2013-06-19 03:43:12201 return cache_file_directory_.IsParent(path);
[email protected]01ba15f72012-06-09 00:41:05202}
203
avibc5337b2015-12-25 23:16:33204bool FileCache::FreeDiskSpaceIfNeededFor(int64_t num_bytes) {
[email protected]ec514362013-05-27 17:52:22205 AssertOnSequencedWorkerPool();
206
207 // Do nothing and return if we have enough space.
yawano4c36b9a02015-10-23 06:17:23208 if (GetAvailableSpace() >= num_bytes)
[email protected]ec514362013-05-27 17:52:22209 return true;
210
211 // Otherwise, try to free up the disk space.
212 DVLOG(1) << "Freeing up disk space for " << num_bytes;
[email protected]f8b1a532013-06-06 08:35:08213
[email protected]9d147582013-06-14 06:25:45214 // Remove all files which have no corresponding cache entries.
[email protected]e07f7b7b2013-06-19 03:43:12215 base::FileEnumerator enumerator(cache_file_directory_,
[email protected]9d147582013-06-14 06:25:45216 false, // not recursive
217 base::FileEnumerator::FILES);
[email protected]cd8fd37f2014-05-20 15:45:21218 ResourceEntry entry;
[email protected]9d147582013-06-14 06:25:45219 for (base::FilePath current = enumerator.Next(); !current.empty();
220 current = enumerator.Next()) {
yawano4c36b9a02015-10-23 06:17:23221 const std::string id = GetIdFromPath(current);
222 const FileError error = storage_->GetEntry(id, &entry);
223
224 if (error == FILE_ERROR_NOT_FOUND)
[email protected]dd3aa792013-07-16 19:10:23225 base::DeleteFile(current, false /* recursive */);
[email protected]996139412014-05-10 06:19:50226 else if (error != FILE_ERROR_OK)
227 return false;
[email protected]9d147582013-06-14 06:25:45228 }
[email protected]ec514362013-05-27 17:52:22229
yawano4c36b9a02015-10-23 06:17:23230 // Check available space again. If we have enough space here, do nothing.
avibc5337b2015-12-25 23:16:33231 const int64_t available_space = GetAvailableSpace();
yawano4c36b9a02015-10-23 06:17:23232 if (available_space >= num_bytes)
233 return true;
234
avibc5337b2015-12-25 23:16:33235 const int64_t requested_space = num_bytes - available_space;
yawano4c36b9a02015-10-23 06:17:23236
237 // Put all entries in priority queue where latest entry becomes top.
238 std::priority_queue<CacheInfo, std::vector<CacheInfo>, CacheInfoLatestCompare>
239 cache_info_queue;
dchengf42750232016-04-12 04:12:27240 std::unique_ptr<ResourceMetadataStorage::Iterator> it =
241 storage_->GetIterator();
yawano4c36b9a02015-10-23 06:17:23242 for (; !it->IsAtEnd(); it->Advance()) {
243 if (IsEvictable(it->GetID(), it->GetValue())) {
244 const ResourceEntry& entry = it->GetValue();
245
246 const base::FilePath& cache_path = GetCacheFilePath(entry.local_id());
247 base::File::Info info;
248 // If it fails to get file info of |cache_path|, use default value as its
249 // file info. i.e. the file becomes least recently used one.
250 base::GetFileInfo(cache_path, &info);
251
252 CacheInfo cache_info = std::make_pair(info, entry);
253
254 if (cache_info_queue.size() < max_num_of_evicted_cache_files_) {
255 cache_info_queue.push(cache_info);
256 } else if (cache_info_queue.size() >= max_num_of_evicted_cache_files_ &&
257 cache_info.first.last_accessed <
258 cache_info_queue.top().first.last_accessed) {
259 // Do not enqueue more than max_num_of_evicted_cache_files_ not to use
260 // up memory with this queue.
261 cache_info_queue.pop();
262 cache_info_queue.push(cache_info);
263 }
264 }
265 }
266 if (it->HasError())
267 return false;
268
269 // Copy entries to the vector. This becomes last-accessed desc order.
270 std::vector<CacheInfo> cache_info_list;
271 while (!cache_info_queue.empty()) {
272 cache_info_list.push_back(cache_info_queue.top());
273 cache_info_queue.pop();
274 }
275
276 // Update DB and delete files with accessing to the vector in ascending order.
avibc5337b2015-12-25 23:16:33277 int64_t evicted_cache_size = 0;
yawano4c36b9a02015-10-23 06:17:23278 auto iter = cache_info_list.rbegin();
279 while (evicted_cache_size < requested_space &&
280 iter != cache_info_list.rend()) {
281 const CacheInfo& cache_info = *iter;
282
283 // Update DB.
284 ResourceEntry entry = cache_info.second;
285 entry.mutable_file_specific_info()->clear_cache_state();
286 storage_->PutEntry(entry);
287
288 // Delete cache file.
289 const base::FilePath& path = GetCacheFilePath(entry.local_id());
290
291 if (base::DeleteFile(path, false /* recursive */))
292 evicted_cache_size += cache_info.first.size;
293
294 ++iter;
295 }
296
[email protected]ec514362013-05-27 17:52:22297 // Check the disk space again.
yawano4c36b9a02015-10-23 06:17:23298 return GetAvailableSpace() >= num_bytes;
[email protected]ec514362013-05-27 17:52:22299}
300
fukino6380c07c2016-06-09 07:28:29301int64_t FileCache::CalculateCacheSize() {
yawano8578abf2015-08-26 09:15:50302 AssertOnSequencedWorkerPool();
303
fukino6380c07c2016-06-09 07:28:29304 int64_t total_cache_size = 0;
305 int64_t cache_size = 0;
306
307 std::unique_ptr<ResourceMetadataStorage::Iterator> it =
308 storage_->GetIterator();
309 for (; !it->IsAtEnd(); it->Advance()) {
310 if (IsPresent(it->GetValue()) &&
311 base::GetFileSize(GetCacheFilePath(it->GetID()), &cache_size)) {
312 DCHECK_GE(cache_size, 0);
313 total_cache_size += cache_size;
314 }
315 }
316
317 if (it->HasError())
318 return 0;
319
320 return total_cache_size;
321}
322
323int64_t FileCache::CalculateEvictableCacheSize() {
324 AssertOnSequencedWorkerPool();
325
326 int64_t evictable_cache_size = 0;
battrea5f64bd2015-08-26 10:47:41327 int64_t cache_size = 0;
yawano8578abf2015-08-26 09:15:50328
dchengf42750232016-04-12 04:12:27329 std::unique_ptr<ResourceMetadataStorage::Iterator> it =
330 storage_->GetIterator();
yawano8578abf2015-08-26 09:15:50331 for (; !it->IsAtEnd(); it->Advance()) {
332 if (IsEvictable(it->GetID(), it->GetValue()) &&
333 base::GetFileSize(GetCacheFilePath(it->GetID()), &cache_size)) {
334 DCHECK_GE(cache_size, 0);
335 evictable_cache_size += cache_size;
336 }
337 }
338
339 if (it->HasError())
340 return 0;
341
342 return evictable_cache_size;
343}
344
[email protected]c9e4738d2013-08-26 03:04:07345FileError FileCache::GetFile(const std::string& id,
[email protected]ec514362013-05-27 17:52:22346 base::FilePath* cache_file_path) {
347 AssertOnSequencedWorkerPool();
348 DCHECK(cache_file_path);
349
[email protected]cd8fd37f2014-05-20 15:45:21350 ResourceEntry entry;
351 FileError error = storage_->GetEntry(id, &entry);
[email protected]996139412014-05-10 06:19:50352 if (error != FILE_ERROR_OK)
353 return error;
[email protected]cd8fd37f2014-05-20 15:45:21354 if (!entry.file_specific_info().cache_state().is_present())
[email protected]ec514362013-05-27 17:52:22355 return FILE_ERROR_NOT_FOUND;
356
[email protected]c9e4738d2013-08-26 03:04:07357 *cache_file_path = GetCacheFilePath(id);
[email protected]ec514362013-05-27 17:52:22358 return FILE_ERROR_OK;
359}
360
[email protected]c9e4738d2013-08-26 03:04:07361FileError FileCache::Store(const std::string& id,
[email protected]82c4eb92013-05-21 11:25:23362 const std::string& md5,
363 const base::FilePath& source_path,
364 FileOperationType file_operation_type) {
365 AssertOnSequencedWorkerPool();
[email protected]d8546c92013-05-02 05:09:59366
[email protected]cd8fd37f2014-05-20 15:45:21367 ResourceEntry entry;
368 FileError error = storage_->GetEntry(id, &entry);
369 if (error != FILE_ERROR_OK)
370 return error;
371
avibc5337b2015-12-25 23:16:33372 int64_t file_size = 0;
[email protected]8e37b9b2013-12-11 09:06:02373 if (file_operation_type == FILE_OPERATION_COPY) {
374 if (!base::GetFileSize(source_path, &file_size)) {
375 LOG(WARNING) << "Couldn't get file size for: " << source_path.value();
376 return FILE_ERROR_FAILED;
377 }
378 }
379 if (!FreeDiskSpaceIfNeededFor(file_size))
380 return FILE_ERROR_NO_LOCAL_SPACE;
[email protected]73f9c742012-06-15 07:37:13381
[email protected]1d0786a2014-02-06 12:37:08382 // If file is mounted, return error.
383 if (mounted_files_.count(id))
[email protected]8e37b9b2013-12-11 09:06:02384 return FILE_ERROR_IN_USE;
385
386 base::FilePath dest_path = GetCacheFilePath(id);
387 bool success = false;
388 switch (file_operation_type) {
389 case FILE_OPERATION_MOVE:
390 success = base::Move(source_path, dest_path);
391 break;
392 case FILE_OPERATION_COPY:
393 success = base::CopyFile(source_path, dest_path);
394 break;
395 default:
396 NOTREACHED();
397 }
398
399 if (!success) {
400 LOG(ERROR) << "Failed to store: "
401 << "source_path = " << source_path.value() << ", "
402 << "dest_path = " << dest_path.value() << ", "
403 << "file_operation_type = " << file_operation_type;
404 return FILE_ERROR_FAILED;
405 }
406
407 // Now that file operations have completed, update metadata.
[email protected]cd8fd37f2014-05-20 15:45:21408 FileCacheEntry* cache_state =
409 entry.mutable_file_specific_info()->mutable_cache_state();
410 cache_state->set_md5(md5);
411 cache_state->set_is_present(true);
[email protected]bae99ae52014-01-29 01:13:14412 if (md5.empty())
[email protected]cd8fd37f2014-05-20 15:45:21413 cache_state->set_is_dirty(true);
okac6aac502016-05-23 12:16:58414
415 if (!cache_state->is_pinned() && !cache_state->is_dirty()) {
416 if (!SetRemovable(dest_path))
417 return FILE_ERROR_FAILED;
418 } else {
419 if (!UnsetRemovable(dest_path))
420 return FILE_ERROR_FAILED;
421 }
422
[email protected]cd8fd37f2014-05-20 15:45:21423 return storage_->PutEntry(entry);
[email protected]73f9c742012-06-15 07:37:13424}
425
[email protected]c9e4738d2013-08-26 03:04:07426FileError FileCache::Pin(const std::string& id) {
[email protected]f8b1a532013-06-06 08:35:08427 AssertOnSequencedWorkerPool();
428
[email protected]cd8fd37f2014-05-20 15:45:21429 ResourceEntry entry;
430 FileError error = storage_->GetEntry(id, &entry);
431 if (error != FILE_ERROR_OK)
[email protected]996139412014-05-10 06:19:50432 return error;
okac6aac502016-05-23 12:16:58433
[email protected]cd8fd37f2014-05-20 15:45:21434 entry.mutable_file_specific_info()->mutable_cache_state()->set_is_pinned(
435 true);
okac6aac502016-05-23 12:16:58436
437 base::FilePath file_path = GetCacheFilePath(entry.local_id());
438 // Cache file can be created later.
439 if (entry.file_specific_info().cache_state().is_present()) {
440 if (!UnsetRemovable(file_path))
441 return FILE_ERROR_FAILED;
442 }
443
[email protected]cd8fd37f2014-05-20 15:45:21444 return storage_->PutEntry(entry);
[email protected]f8b1a532013-06-06 08:35:08445}
446
[email protected]c9e4738d2013-08-26 03:04:07447FileError FileCache::Unpin(const std::string& id) {
[email protected]ec514362013-05-27 17:52:22448 AssertOnSequencedWorkerPool();
449
450 // Unpinning a file means its entry must exist in cache.
[email protected]cd8fd37f2014-05-20 15:45:21451 ResourceEntry entry;
452 FileError error = storage_->GetEntry(id, &entry);
[email protected]996139412014-05-10 06:19:50453 if (error != FILE_ERROR_OK)
454 return error;
[email protected]ec514362013-05-27 17:52:22455
[email protected]ec514362013-05-27 17:52:22456 // Now that file operations have completed, update metadata.
[email protected]cd8fd37f2014-05-20 15:45:21457 if (entry.file_specific_info().cache_state().is_present()) {
458 entry.mutable_file_specific_info()->mutable_cache_state()->set_is_pinned(
459 false);
okac6aac502016-05-23 12:16:58460 if (!entry.file_specific_info().cache_state().is_dirty()) {
461 if (!SetRemovable(GetCacheFilePath(entry.local_id())))
462 return FILE_ERROR_FAILED;
463 }
[email protected]ec514362013-05-27 17:52:22464 } else {
465 // Remove the existing entry if we are unpinning a non-present file.
[email protected]cd8fd37f2014-05-20 15:45:21466 entry.mutable_file_specific_info()->clear_cache_state();
[email protected]ec514362013-05-27 17:52:22467 }
[email protected]cd8fd37f2014-05-20 15:45:21468 error = storage_->PutEntry(entry);
469 if (error != FILE_ERROR_OK)
470 return error;
[email protected]bd2254d2013-06-12 16:00:47471
[email protected]9d147582013-06-14 06:25:45472 // Now it's a chance to free up space if needed.
[email protected]bd2254d2013-06-12 16:00:47473 FreeDiskSpaceIfNeededFor(0);
474
[email protected]ec514362013-05-27 17:52:22475 return FILE_ERROR_OK;
476}
477
[email protected]c3f65642013-08-28 02:04:33478FileError FileCache::MarkAsMounted(const std::string& id,
479 base::FilePath* cache_file_path) {
480 AssertOnSequencedWorkerPool();
481 DCHECK(cache_file_path);
482
483 // Get cache entry associated with the id and md5
[email protected]cd8fd37f2014-05-20 15:45:21484 ResourceEntry entry;
485 FileError error = storage_->GetEntry(id, &entry);
[email protected]996139412014-05-10 06:19:50486 if (error != FILE_ERROR_OK)
487 return error;
[email protected]cd8fd37f2014-05-20 15:45:21488 if (!entry.file_specific_info().cache_state().is_present())
489 return FILE_ERROR_NOT_FOUND;
[email protected]c3f65642013-08-28 02:04:33490
491 if (mounted_files_.count(id))
492 return FILE_ERROR_INVALID_OPERATION;
493
[email protected]c3f65642013-08-28 02:04:33494 base::FilePath path = GetCacheFilePath(id);
lukasza6364a022015-08-21 01:13:24495
496#if defined(OS_CHROMEOS)
497 // Ensure the file is readable to cros_disks. See crbug.com/236994.
[email protected]b264eab2013-11-27 23:22:08498 if (!base::SetPosixFilePermissions(
[email protected]c3f65642013-08-28 02:04:33499 path,
[email protected]b264eab2013-11-27 23:22:08500 base::FILE_PERMISSION_READ_BY_USER |
501 base::FILE_PERMISSION_WRITE_BY_USER |
502 base::FILE_PERMISSION_READ_BY_GROUP |
503 base::FILE_PERMISSION_READ_BY_OTHERS))
[email protected]c3f65642013-08-28 02:04:33504 return FILE_ERROR_FAILED;
lukasza6364a022015-08-21 01:13:24505#endif
[email protected]c3f65642013-08-28 02:04:33506
507 mounted_files_.insert(id);
508
509 *cache_file_path = path;
510 return FILE_ERROR_OK;
511}
512
[email protected]8b03ab3a2014-01-15 17:52:45513FileError FileCache::OpenForWrite(
514 const std::string& id,
dchengf42750232016-04-12 04:12:27515 std::unique_ptr<base::ScopedClosureRunner>* file_closer) {
[email protected]b568b882013-06-10 04:38:07516 AssertOnSequencedWorkerPool();
517
[email protected]b568b882013-06-10 04:38:07518 // Marking a file dirty means its entry and actual file blob must exist in
519 // cache.
[email protected]cd8fd37f2014-05-20 15:45:21520 ResourceEntry entry;
521 FileError error = storage_->GetEntry(id, &entry);
[email protected]996139412014-05-10 06:19:50522 if (error != FILE_ERROR_OK)
523 return error;
[email protected]cd8fd37f2014-05-20 15:45:21524 if (!entry.file_specific_info().cache_state().is_present()) {
[email protected]c9e4738d2013-08-26 03:04:07525 LOG(WARNING) << "Can't mark dirty a file that wasn't cached: " << id;
[email protected]b568b882013-06-10 04:38:07526 return FILE_ERROR_NOT_FOUND;
527 }
528
[email protected]cd8fd37f2014-05-20 15:45:21529 entry.mutable_file_specific_info()->mutable_cache_state()->set_is_dirty(true);
okac6aac502016-05-23 12:16:58530 if (!UnsetRemovable(GetCacheFilePath(entry.local_id())))
531 return FILE_ERROR_FAILED;
532
[email protected]cd8fd37f2014-05-20 15:45:21533 entry.mutable_file_specific_info()->mutable_cache_state()->clear_md5();
534 error = storage_->PutEntry(entry);
[email protected]996139412014-05-10 06:19:50535 if (error != FILE_ERROR_OK)
536 return error;
[email protected]b568b882013-06-10 04:38:07537
[email protected]8b03ab3a2014-01-15 17:52:45538 write_opened_files_[id]++;
539 file_closer->reset(new base::ScopedClosureRunner(
[email protected]c929c932014-07-23 06:06:05540 base::Bind(&google_apis::RunTaskWithTaskRunner,
[email protected]8b03ab3a2014-01-15 17:52:45541 blocking_task_runner_,
542 base::Bind(&FileCache::CloseForWrite,
543 weak_ptr_factory_.GetWeakPtr(),
544 id))));
545 return FILE_ERROR_OK;
546}
547
548bool FileCache::IsOpenedForWrite(const std::string& id) {
549 AssertOnSequencedWorkerPool();
lukasza81be9752015-06-17 00:14:35550 return write_opened_files_.count(id) != 0;
[email protected]b568b882013-06-10 04:38:07551}
552
[email protected]b1bf19a2014-01-21 04:45:19553FileError FileCache::UpdateMd5(const std::string& id) {
[email protected]fcf8eafe02013-05-28 11:15:39554 AssertOnSequencedWorkerPool();
[email protected]eca3fc92013-05-01 03:53:40555
[email protected]b1bf19a2014-01-21 04:45:19556 if (IsOpenedForWrite(id))
557 return FILE_ERROR_IN_USE;
558
[email protected]cd8fd37f2014-05-20 15:45:21559 ResourceEntry entry;
560 FileError error = storage_->GetEntry(id, &entry);
[email protected]996139412014-05-10 06:19:50561 if (error != FILE_ERROR_OK)
562 return error;
[email protected]cd8fd37f2014-05-20 15:45:21563 if (!entry.file_specific_info().cache_state().is_present())
[email protected]b1bf19a2014-01-21 04:45:19564 return FILE_ERROR_NOT_FOUND;
565
hashimoto246e4a82015-04-17 07:44:49566 const std::string& md5 =
567 util::GetMd5Digest(GetCacheFilePath(id), &in_shutdown_);
568 if (in_shutdown_.IsSet())
569 return FILE_ERROR_ABORT;
[email protected]b1bf19a2014-01-21 04:45:19570 if (md5.empty())
571 return FILE_ERROR_NOT_FOUND;
572
[email protected]cd8fd37f2014-05-20 15:45:21573 entry.mutable_file_specific_info()->mutable_cache_state()->set_md5(md5);
574 return storage_->PutEntry(entry);
[email protected]b1bf19a2014-01-21 04:45:19575}
576
577FileError FileCache::ClearDirty(const std::string& id) {
578 AssertOnSequencedWorkerPool();
579
580 if (IsOpenedForWrite(id))
581 return FILE_ERROR_IN_USE;
582
[email protected]fcf8eafe02013-05-28 11:15:39583 // Clearing a dirty file means its entry and actual file blob must exist in
584 // cache.
[email protected]cd8fd37f2014-05-20 15:45:21585 ResourceEntry entry;
586 FileError error = storage_->GetEntry(id, &entry);
[email protected]996139412014-05-10 06:19:50587 if (error != FILE_ERROR_OK)
588 return error;
[email protected]cd8fd37f2014-05-20 15:45:21589 if (!entry.file_specific_info().cache_state().is_present()) {
[email protected]fcf8eafe02013-05-28 11:15:39590 LOG(WARNING) << "Can't clear dirty state of a file that wasn't cached: "
[email protected]c9e4738d2013-08-26 03:04:07591 << id;
[email protected]fcf8eafe02013-05-28 11:15:39592 return FILE_ERROR_NOT_FOUND;
593 }
594
[email protected]8b03ab3a2014-01-15 17:52:45595 // If a file is not dirty (it should have been marked dirty via OpenForWrite),
596 // clearing its dirty state is an invalid operation.
[email protected]cd8fd37f2014-05-20 15:45:21597 if (!entry.file_specific_info().cache_state().is_dirty()) {
[email protected]c9e4738d2013-08-26 03:04:07598 LOG(WARNING) << "Can't clear dirty state of a non-dirty file: " << id;
[email protected]fcf8eafe02013-05-28 11:15:39599 return FILE_ERROR_INVALID_OPERATION;
600 }
601
[email protected]cd8fd37f2014-05-20 15:45:21602 entry.mutable_file_specific_info()->mutable_cache_state()->set_is_dirty(
603 false);
okac6aac502016-05-23 12:16:58604 if (!entry.file_specific_info().cache_state().is_pinned()) {
605 if (!SetRemovable(GetCacheFilePath(entry.local_id())))
606 return FILE_ERROR_FAILED;
607 }
608
[email protected]cd8fd37f2014-05-20 15:45:21609 return storage_->PutEntry(entry);
[email protected]73f9c742012-06-15 07:37:13610}
611
[email protected]c9e4738d2013-08-26 03:04:07612FileError FileCache::Remove(const std::string& id) {
[email protected]3361a542013-05-22 17:38:27613 AssertOnSequencedWorkerPool();
614
[email protected]cd8fd37f2014-05-20 15:45:21615 ResourceEntry entry;
[email protected]3361a542013-05-22 17:38:27616
[email protected]4b60a25f2013-06-17 09:43:11617 // If entry doesn't exist, nothing to do.
[email protected]cd8fd37f2014-05-20 15:45:21618 FileError error = storage_->GetEntry(id, &entry);
[email protected]996139412014-05-10 06:19:50619 if (error == FILE_ERROR_NOT_FOUND)
[email protected]3361a542013-05-22 17:38:27620 return FILE_ERROR_OK;
[email protected]996139412014-05-10 06:19:50621 if (error != FILE_ERROR_OK)
622 return error;
[email protected]cd8fd37f2014-05-20 15:45:21623 if (!entry.file_specific_info().has_cache_state())
624 return FILE_ERROR_OK;
[email protected]3361a542013-05-22 17:38:27625
[email protected]d1ad8fa2013-07-11 13:23:20626 // Cannot delete a mounted file.
[email protected]c9e4738d2013-08-26 03:04:07627 if (mounted_files_.count(id))
[email protected]4b60a25f2013-06-17 09:43:11628 return FILE_ERROR_IN_USE;
629
[email protected]91a464e62013-07-10 09:30:06630 // Delete the file.
[email protected]c9e4738d2013-08-26 03:04:07631 base::FilePath path = GetCacheFilePath(id);
[email protected]dd3aa792013-07-16 19:10:23632 if (!base::DeleteFile(path, false /* recursive */))
[email protected]91a464e62013-07-10 09:30:06633 return FILE_ERROR_FAILED;
[email protected]3361a542013-05-22 17:38:27634
635 // Now that all file operations have completed, remove from metadata.
[email protected]cd8fd37f2014-05-20 15:45:21636 entry.mutable_file_specific_info()->clear_cache_state();
637 return storage_->PutEntry(entry);
[email protected]3361a542013-05-22 17:38:27638}
639
[email protected]823ca9712013-09-13 10:09:09640bool FileCache::ClearAll() {
641 AssertOnSequencedWorkerPool();
[email protected]f861b392012-08-03 20:41:12642
[email protected]823ca9712013-09-13 10:09:09643 // Remove files.
644 base::FileEnumerator enumerator(cache_file_directory_,
645 false, // not recursive
646 base::FileEnumerator::FILES);
647 for (base::FilePath file = enumerator.Next(); !file.empty();
648 file = enumerator.Next())
649 base::DeleteFile(file, false /* recursive */);
650
651 return true;
[email protected]f861b392012-08-03 20:41:12652}
653
[email protected]34a1bbf32013-06-17 07:24:02654bool FileCache::Initialize() {
[email protected]ca5f6da2012-06-18 12:54:59655 AssertOnSequencedWorkerPool();
656
[email protected]b1bf19a2014-01-21 04:45:19657 // Older versions do not clear MD5 when marking entries dirty.
658 // Clear MD5 of all dirty entries to deal with old data.
dchengf42750232016-04-12 04:12:27659 std::unique_ptr<ResourceMetadataStorage::Iterator> it =
660 storage_->GetIterator();
[email protected]b1bf19a2014-01-21 04:45:19661 for (; !it->IsAtEnd(); it->Advance()) {
[email protected]cd8fd37f2014-05-20 15:45:21662 if (it->GetValue().file_specific_info().cache_state().is_dirty()) {
663 ResourceEntry new_entry(it->GetValue());
664 new_entry.mutable_file_specific_info()->mutable_cache_state()->
665 clear_md5();
666 if (storage_->PutEntry(new_entry) != FILE_ERROR_OK)
[email protected]b1bf19a2014-01-21 04:45:19667 return false;
668 }
669 }
[email protected]996139412014-05-10 06:19:50670 if (it->HasError())
671 return false;
[email protected]b1bf19a2014-01-21 04:45:19672
[email protected]f2731d12013-10-22 03:23:15673 if (!RenameCacheFilesToNewFormat())
674 return false;
okac6aac502016-05-23 12:16:58675
676 // Run this every time to resolve inconsistency between metadata
677 // and file attributes which possibly occurs on abrupt power failure.
678 if (!FixMetadataAndFileAttributes()) {
679 return false;
680 }
681
[email protected]e8842b192013-06-11 04:05:14682 return true;
[email protected]ca5f6da2012-06-18 12:54:59683}
684
[email protected]34a1bbf32013-06-17 07:24:02685void FileCache::Destroy() {
lukasza037c10b12015-06-12 04:21:25686 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]34a1bbf32013-06-17 07:24:02687
hashimoto246e4a82015-04-17 07:44:49688 in_shutdown_.Set();
689
[email protected]34a1bbf32013-06-17 07:24:02690 // Destroy myself on the blocking pool.
691 // Note that base::DeletePointer<> cannot be used as the destructor of this
692 // class is private.
693 blocking_task_runner_->PostTask(
694 FROM_HERE,
695 base::Bind(&FileCache::DestroyOnBlockingPool, base::Unretained(this)));
696}
697
[email protected]eca3fc92013-05-01 03:53:40698void FileCache::DestroyOnBlockingPool() {
[email protected]73f9c742012-06-15 07:37:13699 AssertOnSequencedWorkerPool();
700 delete this;
701}
702
[email protected]b7af4f12013-10-31 06:57:45703bool FileCache::RecoverFilesFromCacheDirectory(
[email protected]760abc32013-11-01 05:13:01704 const base::FilePath& dest_directory,
[email protected]026d4a522013-11-05 14:22:18705 const ResourceMetadataStorage::RecoveredCacheInfoMap&
706 recovered_cache_info) {
[email protected]b7af4f12013-10-31 06:57:45707 int file_number = 1;
708
709 base::FileEnumerator enumerator(cache_file_directory_,
710 false, // not recursive
711 base::FileEnumerator::FILES);
712 for (base::FilePath current = enumerator.Next(); !current.empty();
713 current = enumerator.Next()) {
714 const std::string& id = GetIdFromPath(current);
[email protected]cd8fd37f2014-05-20 15:45:21715 ResourceEntry entry;
716 FileError error = storage_->GetEntry(id, &entry);
717 if (error != FILE_ERROR_OK && error != FILE_ERROR_NOT_FOUND)
718 return false;
719 if (error == FILE_ERROR_OK &&
720 entry.file_specific_info().cache_state().is_present()) {
[email protected]b7af4f12013-10-31 06:57:45721 // This file is managed by FileCache, no need to recover it.
722 continue;
723 }
724
[email protected]760abc32013-11-01 05:13:01725 // If a cache entry which is non-dirty and has matching MD5 is found in
726 // |recovered_cache_entries|, it means the current file is already uploaded
727 // to the server. Just delete it instead of recovering it.
[email protected]026d4a522013-11-05 14:22:18728 ResourceMetadataStorage::RecoveredCacheInfoMap::const_iterator it =
729 recovered_cache_info.find(id);
730 if (it != recovered_cache_info.end()) {
731 // Due to the DB corruption, cache info might be recovered from old
732 // revision. Perform MD5 check even when is_dirty is false just in case.
733 if (!it->second.is_dirty &&
hashimoto246e4a82015-04-17 07:44:49734 it->second.md5 == util::GetMd5Digest(current, &in_shutdown_)) {
[email protected]760abc32013-11-01 05:13:01735 base::DeleteFile(current, false /* recursive */);
736 continue;
737 }
738 }
739
[email protected]b7af4f12013-10-31 06:57:45740 // Read file contents to sniff mime type.
741 std::vector<char> content(net::kMaxBytesToSniff);
742 const int read_result =
[email protected]7600d0b2013-12-08 21:43:30743 base::ReadFile(current, &content[0], content.size());
[email protected]b7af4f12013-10-31 06:57:45744 if (read_result < 0) {
745 LOG(WARNING) << "Cannot read: " << current.value();
746 return false;
747 }
748 if (read_result == 0) // Skip empty files.
749 continue;
750
[email protected]026d4a522013-11-05 14:22:18751 // Use recovered file name if available, otherwise decide file name with
752 // sniffed mime type.
[email protected]b7af4f12013-10-31 06:57:45753 base::FilePath dest_base_name(FILE_PATH_LITERAL("file"));
754 std::string mime_type;
[email protected]026d4a522013-11-05 14:22:18755 if (it != recovered_cache_info.end() && !it->second.title.empty()) {
756 // We can use a file name recovered from the trashed DB.
757 dest_base_name = base::FilePath::FromUTF8Unsafe(it->second.title);
758 } else if (net::SniffMimeType(&content[0], read_result,
759 net::FilePathToFileURL(current),
760 std::string(), &mime_type) ||
761 net::SniffMimeTypeFromLocalData(&content[0], read_result,
762 &mime_type)) {
[email protected]b7af4f12013-10-31 06:57:45763 // Change base name for common mime types.
764 if (net::MatchesMimeType("image/*", mime_type)) {
765 dest_base_name = base::FilePath(FILE_PATH_LITERAL("image"));
766 } else if (net::MatchesMimeType("video/*", mime_type)) {
767 dest_base_name = base::FilePath(FILE_PATH_LITERAL("video"));
768 } else if (net::MatchesMimeType("audio/*", mime_type)) {
769 dest_base_name = base::FilePath(FILE_PATH_LITERAL("audio"));
770 }
771
772 // Estimate extension from mime type.
773 std::vector<base::FilePath::StringType> extensions;
774 base::FilePath::StringType extension;
775 if (net::GetPreferredExtensionForMimeType(mime_type, &extension))
776 extensions.push_back(extension);
777 else
778 net::GetExtensionsForMimeType(mime_type, &extensions);
779
780 // Add extension if possible.
781 if (!extensions.empty())
782 dest_base_name = dest_base_name.AddExtension(extensions[0]);
783 }
784
785 // Add file number to the file name and move.
786 const base::FilePath& dest_path = dest_directory.Append(dest_base_name)
787 .InsertBeforeExtensionASCII(base::StringPrintf("%08d", file_number++));
[email protected]426d1c92013-12-03 20:08:54788 if (!base::CreateDirectory(dest_directory) ||
[email protected]b7af4f12013-10-31 06:57:45789 !base::Move(current, dest_path)) {
790 LOG(WARNING) << "Failed to move: " << current.value()
791 << " to " << dest_path.value();
792 return false;
793 }
794 }
[email protected]d105b3ad2013-11-01 05:33:13795 UMA_HISTOGRAM_COUNTS("Drive.NumberOfCacheFilesRecoveredAfterDBCorruption",
796 file_number - 1);
[email protected]b7af4f12013-10-31 06:57:45797 return true;
798}
799
[email protected]54ba37502013-05-09 08:43:40800FileError FileCache::MarkAsUnmounted(const base::FilePath& file_path) {
[email protected]9564c1502012-11-28 12:12:16801 AssertOnSequencedWorkerPool();
[email protected]eca3fc92013-05-01 03:53:40802 DCHECK(IsUnderFileCacheDirectory(file_path));
[email protected]9564c1502012-11-28 12:12:16803
[email protected]c9e4738d2013-08-26 03:04:07804 std::string id = GetIdFromPath(file_path);
[email protected]9564c1502012-11-28 12:12:16805
[email protected]cd8fd37f2014-05-20 15:45:21806 // Get the entry associated with the id.
807 ResourceEntry entry;
808 FileError error = storage_->GetEntry(id, &entry);
[email protected]996139412014-05-10 06:19:50809 if (error != FILE_ERROR_OK)
810 return error;
[email protected]9564c1502012-11-28 12:12:16811
[email protected]c9e4738d2013-08-26 03:04:07812 std::set<std::string>::iterator it = mounted_files_.find(id);
[email protected]4b60a25f2013-06-17 09:43:11813 if (it == mounted_files_.end())
[email protected]78a158b2013-04-23 06:57:49814 return FILE_ERROR_INVALID_OPERATION;
[email protected]9564c1502012-11-28 12:12:16815
[email protected]4b60a25f2013-06-17 09:43:11816 mounted_files_.erase(it);
[email protected]78a158b2013-04-23 06:57:49817 return FILE_ERROR_OK;
[email protected]9564c1502012-11-28 12:12:16818}
819
avibc5337b2015-12-25 23:16:33820int64_t FileCache::GetAvailableSpace() {
821 int64_t free_space = 0;
[email protected]f6fd98a2012-12-14 00:04:02822 if (free_disk_space_getter_)
823 free_space = free_disk_space_getter_->AmountOfFreeDiskSpace();
824 else
yawano4c36b9a02015-10-23 06:17:23825 free_space = base::SysInfo::AmountOfFreeDiskSpace(cache_file_directory_);
[email protected]f6fd98a2012-12-14 00:04:02826
827 // Subtract this as if this portion does not exist.
lukasza3fb22622015-08-27 21:04:34828 free_space -= drive::internal::kMinFreeSpaceInBytes;
yawano4c36b9a02015-10-23 06:17:23829 return free_space;
[email protected]f6fd98a2012-12-14 00:04:02830}
831
[email protected]f2731d12013-10-22 03:23:15832bool FileCache::RenameCacheFilesToNewFormat() {
833 base::FileEnumerator enumerator(cache_file_directory_,
834 false, // not recursive
835 base::FileEnumerator::FILES);
836 for (base::FilePath current = enumerator.Next(); !current.empty();
837 current = enumerator.Next()) {
838 base::FilePath new_path = current.RemoveExtension();
839 if (!new_path.Extension().empty()) {
840 // Delete files with multiple extensions.
841 if (!base::DeleteFile(current, false /* recursive */))
842 return false;
843 continue;
844 }
845 const std::string& id = GetIdFromPath(new_path);
846 new_path = GetCacheFilePath(util::CanonicalizeResourceId(id));
847 if (new_path != current && !base::Move(current, new_path))
848 return false;
[email protected]91a464e62013-07-10 09:30:06849 }
[email protected]f2731d12013-10-22 03:23:15850 return true;
[email protected]91a464e62013-07-10 09:30:06851}
852
okac6aac502016-05-23 12:16:58853bool FileCache::FixMetadataAndFileAttributes() {
dchengf42750232016-04-12 04:12:27854 std::unique_ptr<ResourceMetadataStorage::Iterator> it =
okac6aac502016-05-23 12:16:58855 storage_->GetIterator();
856
yawano9fd1e632016-02-04 09:00:06857 for (; !it->IsAtEnd(); it->Advance()) {
okac6aac502016-05-23 12:16:58858 ResourceEntry entry = it->GetValue();
859 FileCacheEntry* file_cache_entry =
860 entry.mutable_file_specific_info()->mutable_cache_state();
yawano9fd1e632016-02-04 09:00:06861
okac6aac502016-05-23 12:16:58862 const base::FilePath filepath = GetPathForId(cache_file_directory_,
863 entry.local_id());
yawano9fd1e632016-02-04 09:00:06864
okac6aac502016-05-23 12:16:58865 if (base::PathExists(filepath)) {
866 if (file_cache_entry->is_present()) {
867 // Update file attribues for cryptohome.
868 if (file_cache_entry->is_pinned() || file_cache_entry->is_dirty()) {
869 if (!UnsetRemovable(filepath)) return false;
870 } else {
871 if (!SetRemovable(filepath)) return false;
872 }
873 } else {
874 // Delete file if the file is present but metadata says not.
875 // It happens only on abrupt shutdown.
876 LOG(WARNING)
877 << "File is present but metadata's state was inconsistent.";
878
879 if (!base::DeleteFile(filepath, false /* recursive */))
880 return false;
yawano1c325bf2016-04-20 06:37:03881 }
okac6aac502016-05-23 12:16:58882 } else {
883 // Update metatadata if there is no file but metadata says there is.
884 // It happens when cryptohome removed the file.
885 // We don't clear is_pinned here, so that file download is restarted on
886 // the following scenario:
887 // 1. The file was pinned but not present.
888 // 2. Then the file was downloaded and became present.
889 // 3. Unclean shutdown happens, metadata update was saved to the disk,
890 // but the file move was not.
891 if (file_cache_entry->is_present()) {
892 file_cache_entry->set_is_present(false);
893 file_cache_entry->set_is_dirty(false);
894 file_cache_entry->clear_md5();
895 if (storage_->PutEntry(entry) != FILE_ERROR_OK)
896 return false;
897 }
yawano9fd1e632016-02-04 09:00:06898 }
yawano9fd1e632016-02-04 09:00:06899 }
900
okac6aac502016-05-23 12:16:58901 return MarkAsDriveCacheDir(cache_file_directory_);
yawano9fd1e632016-02-04 09:00:06902}
903
[email protected]8b03ab3a2014-01-15 17:52:45904void FileCache::CloseForWrite(const std::string& id) {
905 AssertOnSequencedWorkerPool();
906
907 std::map<std::string, int>::iterator it = write_opened_files_.find(id);
908 if (it == write_opened_files_.end())
909 return;
910
911 DCHECK_LT(0, it->second);
912 --it->second;
913 if (it->second == 0)
914 write_opened_files_.erase(it);
[email protected]f92367ae2014-06-02 07:35:43915
916 // Update last modified date.
917 ResourceEntry entry;
918 FileError error = storage_->GetEntry(id, &entry);
919 if (error != FILE_ERROR_OK) {
920 LOG(ERROR) << "Failed to get entry: " << id << ", "
921 << FileErrorToString(error);
922 return;
923 }
924 entry.mutable_file_info()->set_last_modified(
925 base::Time::Now().ToInternalValue());
926 error = storage_->PutEntry(entry);
927 if (error != FILE_ERROR_OK) {
928 LOG(ERROR) << "Failed to put entry: " << id << ", "
929 << FileErrorToString(error);
930 }
[email protected]8b03ab3a2014-01-15 17:52:45931}
932
yawano8578abf2015-08-26 09:15:50933bool FileCache::IsEvictable(const std::string& id, const ResourceEntry& entry) {
fukino6380c07c2016-06-09 07:28:29934 return IsPresent(entry) &&
yawano8578abf2015-08-26 09:15:50935 !entry.file_specific_info().cache_state().is_pinned() &&
936 !entry.file_specific_info().cache_state().is_dirty() &&
937 !mounted_files_.count(id);
938}
939
[email protected]59c7cdec2013-05-07 04:17:13940} // namespace internal
[email protected]d9d04df2012-10-12 07:06:35941} // namespace drive