15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/chromeos/drive/file_cache.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/callback_helpers.h"
10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/files/file_enumerator.h"
111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
130f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "base/metrics/histogram.h"
145e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string_util.h"
155e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/stringprintf.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/sys_info.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/chromeos/drive/drive.pb.h"
18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/chromeos/drive/file_system_util.h"
19eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/chromeos/drive/resource_metadata_storage.h"
208bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "chrome/browser/drive/drive_api_util.h"
21a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "chromeos/chromeos_constants.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "google_apis/drive/task_util.h"
24c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "net/base/filename_util.h"
250f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "net/base/mime_sniffer.h"
260f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "net/base/mime_util.h"
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "third_party/cros_system_api/constants/cryptohome.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace drive {
32b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)namespace internal {
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
35424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// Returns ID extracted from the path.
36424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)std::string GetIdFromPath(const base::FilePath& path) {
377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return util::UnescapeCacheFileName(path.BaseName().AsUTF8Unsafe());
387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochFileCache::FileCache(ResourceMetadataStorage* storage,
437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                     const base::FilePath& cache_file_directory,
44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                     base::SequencedTaskRunner* blocking_task_runner,
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                     FreeDiskSpaceGetterInterface* free_disk_space_getter)
46eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    : cache_file_directory_(cache_file_directory),
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      blocking_task_runner_(blocking_task_runner),
48eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      storage_(storage),
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      free_disk_space_getter_(free_disk_space_getter),
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      weak_ptr_factory_(this) {
517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  DCHECK(blocking_task_runner_.get());
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)FileCache::~FileCache() {
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Must be on the sequenced worker pool, as |metadata_| must be deleted on
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // the sequenced worker pool.
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AssertOnSequencedWorkerPool();
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
61424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)base::FilePath FileCache::GetCacheFilePath(const std::string& id) const {
627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return cache_file_directory_.Append(
63424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      base::FilePath::FromUTF8Unsafe(util::EscapeCacheFileName(id)));
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void FileCache::AssertOnSequencedWorkerPool() {
67a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool FileCache::IsUnderFileCacheDirectory(const base::FilePath& path) const {
717d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return cache_file_directory_.IsParent(path);
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool FileCache::FreeDiskSpaceIfNeededFor(int64 num_bytes) {
7590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  AssertOnSequencedWorkerPool();
7690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
7790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Do nothing and return if we have enough space.
787d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (HasEnoughSpaceFor(num_bytes, cache_file_directory_))
7990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return true;
8090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
8190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Otherwise, try to free up the disk space.
8290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DVLOG(1) << "Freeing up disk space for " << num_bytes;
83868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
847d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Remove all entries unless specially marked.
85cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<ResourceMetadataStorage::Iterator> it = storage_->GetIterator();
86868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  for (; !it->IsAtEnd(); it->Advance()) {
87cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (it->GetValue().file_specific_info().has_cache_state() &&
88cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        !it->GetValue().file_specific_info().cache_state().is_pinned() &&
89cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        !it->GetValue().file_specific_info().cache_state().is_dirty() &&
90cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        !mounted_files_.count(it->GetID())) {
91cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      ResourceEntry entry(it->GetValue());
92cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      entry.mutable_file_specific_info()->clear_cache_state();
93cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      storage_->PutEntry(entry);
94cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
95868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
96cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (it->HasError())
97cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return false;
98868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Remove all files which have no corresponding cache entries.
1007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  base::FileEnumerator enumerator(cache_file_directory_,
1017d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                  false,  // not recursive
1027d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                  base::FileEnumerator::FILES);
103cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ResourceEntry entry;
1047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  for (base::FilePath current = enumerator.Next(); !current.empty();
1057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)       current = enumerator.Next()) {
106424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    std::string id = GetIdFromPath(current);
107cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    FileError error = storage_->GetEntry(id, &entry);
108cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (error == FILE_ERROR_NOT_FOUND ||
109cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        (error == FILE_ERROR_OK &&
110cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)         !entry.file_specific_info().cache_state().is_present()))
1117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      base::DeleteFile(current, false /* recursive */);
112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    else if (error != FILE_ERROR_OK)
113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      return false;
1147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
11590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
11690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Check the disk space again.
1177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return HasEnoughSpaceFor(num_bytes, cache_file_directory_);
11890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
11990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
120424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)FileError FileCache::GetFile(const std::string& id,
12190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                             base::FilePath* cache_file_path) {
12290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  AssertOnSequencedWorkerPool();
12390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(cache_file_path);
12490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
125cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ResourceEntry entry;
126cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  FileError error = storage_->GetEntry(id, &entry);
127cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (error != FILE_ERROR_OK)
128cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return error;
129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!entry.file_specific_info().cache_state().is_present())
13090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return FILE_ERROR_NOT_FOUND;
13190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
132424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  *cache_file_path = GetCacheFilePath(id);
13390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return FILE_ERROR_OK;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
136424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)FileError FileCache::Store(const std::string& id,
13790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                           const std::string& md5,
13890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                           const base::FilePath& source_path,
13990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                           FileOperationType file_operation_type) {
14090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  AssertOnSequencedWorkerPool();
141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
142cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ResourceEntry entry;
143cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  FileError error = storage_->GetEntry(id, &entry);
144cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (error != FILE_ERROR_OK)
145cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return error;
146cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
147a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  int64 file_size = 0;
148a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (file_operation_type == FILE_OPERATION_COPY) {
149a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (!base::GetFileSize(source_path, &file_size)) {
150a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      LOG(WARNING) << "Couldn't get file size for: " << source_path.value();
151a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      return FILE_ERROR_FAILED;
152a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
153a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
154a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (!FreeDiskSpaceIfNeededFor(file_size))
155a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return FILE_ERROR_NO_LOCAL_SPACE;
156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // If file is mounted, return error.
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (mounted_files_.count(id))
159a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return FILE_ERROR_IN_USE;
160a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
161a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::FilePath dest_path = GetCacheFilePath(id);
162a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  bool success = false;
163a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  switch (file_operation_type) {
164a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    case FILE_OPERATION_MOVE:
165a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      success = base::Move(source_path, dest_path);
166a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      break;
167a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    case FILE_OPERATION_COPY:
168a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      success = base::CopyFile(source_path, dest_path);
169a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      break;
170a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    default:
171a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      NOTREACHED();
172a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
173a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
174a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (!success) {
175a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    LOG(ERROR) << "Failed to store: "
176a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)               << "source_path = " << source_path.value() << ", "
177a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)               << "dest_path = " << dest_path.value() << ", "
178a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)               << "file_operation_type = " << file_operation_type;
179a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return FILE_ERROR_FAILED;
180a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
181a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
182a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Now that file operations have completed, update metadata.
183cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  FileCacheEntry* cache_state =
184cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      entry.mutable_file_specific_info()->mutable_cache_state();
185cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  cache_state->set_md5(md5);
186cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  cache_state->set_is_present(true);
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (md5.empty())
188cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    cache_state->set_is_dirty(true);
189cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return storage_->PutEntry(entry);
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
192424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)FileError FileCache::Pin(const std::string& id) {
193868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  AssertOnSequencedWorkerPool();
194868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
195cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ResourceEntry entry;
196cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  FileError error = storage_->GetEntry(id, &entry);
197cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (error != FILE_ERROR_OK)
198cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return error;
199cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  entry.mutable_file_specific_info()->mutable_cache_state()->set_is_pinned(
200cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      true);
201cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return storage_->PutEntry(entry);
202868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
203868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
204424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)FileError FileCache::Unpin(const std::string& id) {
20590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  AssertOnSequencedWorkerPool();
20690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
20790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Unpinning a file means its entry must exist in cache.
208cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ResourceEntry entry;
209cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  FileError error = storage_->GetEntry(id, &entry);
210cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (error != FILE_ERROR_OK)
211cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return error;
21290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
21390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Now that file operations have completed, update metadata.
214cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (entry.file_specific_info().cache_state().is_present()) {
215cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    entry.mutable_file_specific_info()->mutable_cache_state()->set_is_pinned(
216cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        false);
21790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  } else {
21890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Remove the existing entry if we are unpinning a non-present file.
219cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    entry.mutable_file_specific_info()->clear_cache_state();
22090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
221cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  error = storage_->PutEntry(entry);
222cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (error != FILE_ERROR_OK)
223cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return error;
2247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
2257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Now it's a chance to free up space if needed.
2267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  FreeDiskSpaceIfNeededFor(0);
2277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
22890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return FILE_ERROR_OK;
22990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
23090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
231424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)FileError FileCache::MarkAsMounted(const std::string& id,
232424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                                   base::FilePath* cache_file_path) {
233424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  AssertOnSequencedWorkerPool();
234424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(cache_file_path);
235424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
236424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Get cache entry associated with the id and md5
237cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ResourceEntry entry;
238cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  FileError error = storage_->GetEntry(id, &entry);
239cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (error != FILE_ERROR_OK)
240cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return error;
241cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!entry.file_specific_info().cache_state().is_present())
242424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return FILE_ERROR_NOT_FOUND;
243424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
244424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (mounted_files_.count(id))
245424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return FILE_ERROR_INVALID_OPERATION;
246424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
247424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Ensure the file is readable to cros_disks. See crbug.com/236994.
248424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  base::FilePath path = GetCacheFilePath(id);
249f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!base::SetPosixFilePermissions(
250424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)          path,
251f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          base::FILE_PERMISSION_READ_BY_USER |
252f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          base::FILE_PERMISSION_WRITE_BY_USER |
253f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          base::FILE_PERMISSION_READ_BY_GROUP |
254f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          base::FILE_PERMISSION_READ_BY_OTHERS))
255424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return FILE_ERROR_FAILED;
256424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
257424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  mounted_files_.insert(id);
258424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
259424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  *cache_file_path = path;
260424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return FILE_ERROR_OK;
261424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
262424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)FileError FileCache::OpenForWrite(
2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& id,
2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<base::ScopedClosureRunner>* file_closer) {
266868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  AssertOnSequencedWorkerPool();
267868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
268868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Marking a file dirty means its entry and actual file blob must exist in
269868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // cache.
270cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ResourceEntry entry;
271cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  FileError error = storage_->GetEntry(id, &entry);
272cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (error != FILE_ERROR_OK)
273cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return error;
274cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!entry.file_specific_info().cache_state().is_present()) {
275424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    LOG(WARNING) << "Can't mark dirty a file that wasn't cached: " << id;
276868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return FILE_ERROR_NOT_FOUND;
277868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
278868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
279cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  entry.mutable_file_specific_info()->mutable_cache_state()->set_is_dirty(true);
280cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  entry.mutable_file_specific_info()->mutable_cache_state()->clear_md5();
281cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  error = storage_->PutEntry(entry);
282cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (error != FILE_ERROR_OK)
283cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return error;
2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  write_opened_files_[id]++;
2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  file_closer->reset(new base::ScopedClosureRunner(
2875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      base::Bind(&google_apis::RunTaskWithTaskRunner,
2885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 blocking_task_runner_,
2895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 base::Bind(&FileCache::CloseForWrite,
2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            weak_ptr_factory_.GetWeakPtr(),
2915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            id))));
2925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return FILE_ERROR_OK;
2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool FileCache::IsOpenedForWrite(const std::string& id) {
2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  AssertOnSequencedWorkerPool();
2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return write_opened_files_.count(id);
2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)FileError FileCache::UpdateMd5(const std::string& id) {
3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  AssertOnSequencedWorkerPool();
3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (IsOpenedForWrite(id))
3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return FILE_ERROR_IN_USE;
3055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
306cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ResourceEntry entry;
307cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  FileError error = storage_->GetEntry(id, &entry);
308cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (error != FILE_ERROR_OK)
309cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return error;
310cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!entry.file_specific_info().cache_state().is_present())
3115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return FILE_ERROR_NOT_FOUND;
3125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const std::string& md5 = util::GetMd5Digest(GetCacheFilePath(id));
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (md5.empty())
3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return FILE_ERROR_NOT_FOUND;
3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
317cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  entry.mutable_file_specific_info()->mutable_cache_state()->set_md5(md5);
318cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return storage_->PutEntry(entry);
319868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
320868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)FileError FileCache::ClearDirty(const std::string& id) {
32290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  AssertOnSequencedWorkerPool();
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (IsOpenedForWrite(id))
3255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return FILE_ERROR_IN_USE;
3265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
32790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Clearing a dirty file means its entry and actual file blob must exist in
32890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // cache.
329cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ResourceEntry entry;
330cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  FileError error = storage_->GetEntry(id, &entry);
331cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (error != FILE_ERROR_OK)
332cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return error;
333cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!entry.file_specific_info().cache_state().is_present()) {
33490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LOG(WARNING) << "Can't clear dirty state of a file that wasn't cached: "
335424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                 << id;
33690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return FILE_ERROR_NOT_FOUND;
33790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
33890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // If a file is not dirty (it should have been marked dirty via OpenForWrite),
3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // clearing its dirty state is an invalid operation.
341cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!entry.file_specific_info().cache_state().is_dirty()) {
342424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    LOG(WARNING) << "Can't clear dirty state of a non-dirty file: " << id;
34390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return FILE_ERROR_INVALID_OPERATION;
34490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
34590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
346cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  entry.mutable_file_specific_info()->mutable_cache_state()->set_is_dirty(
347cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      false);
348cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return storage_->PutEntry(entry);
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
351424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)FileError FileCache::Remove(const std::string& id) {
35290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  AssertOnSequencedWorkerPool();
35390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
354cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ResourceEntry entry;
35590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // If entry doesn't exist, nothing to do.
357cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  FileError error = storage_->GetEntry(id, &entry);
358cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (error == FILE_ERROR_NOT_FOUND)
359cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return FILE_ERROR_OK;
360cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (error != FILE_ERROR_OK)
361cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return error;
362cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!entry.file_specific_info().has_cache_state())
36390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return FILE_ERROR_OK;
36490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Cannot delete a mounted file.
366424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (mounted_files_.count(id))
3677d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return FILE_ERROR_IN_USE;
36890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Delete the file.
370424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  base::FilePath path = GetCacheFilePath(id);
3717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!base::DeleteFile(path, false /* recursive */))
3727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return FILE_ERROR_FAILED;
37390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
37490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Now that all file operations have completed, remove from metadata.
375cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  entry.mutable_file_specific_info()->clear_cache_state();
376cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return storage_->PutEntry(entry);
37790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
37890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
379d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)bool FileCache::ClearAll() {
380d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  AssertOnSequencedWorkerPool();
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
382d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Remove files.
383d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  base::FileEnumerator enumerator(cache_file_directory_,
384d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                                  false,  // not recursive
385d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                                  base::FileEnumerator::FILES);
386d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  for (base::FilePath file = enumerator.Next(); !file.empty();
387d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)       file = enumerator.Next())
388d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    base::DeleteFile(file, false /* recursive */);
389d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
390d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return true;
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3937d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool FileCache::Initialize() {
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AssertOnSequencedWorkerPool();
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Older versions do not clear MD5 when marking entries dirty.
3975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Clear MD5 of all dirty entries to deal with old data.
398cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<ResourceMetadataStorage::Iterator> it = storage_->GetIterator();
3995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (; !it->IsAtEnd(); it->Advance()) {
400cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (it->GetValue().file_specific_info().cache_state().is_dirty()) {
401cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      ResourceEntry new_entry(it->GetValue());
402cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      new_entry.mutable_file_specific_info()->mutable_cache_state()->
403cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          clear_md5();
404cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if (storage_->PutEntry(new_entry) != FILE_ERROR_OK)
4055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return false;
4065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
4075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
408cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (it->HasError())
409cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return false;
4105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4118bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (!RenameCacheFilesToNewFormat())
4128bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return false;
413868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return true;
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void FileCache::Destroy() {
4177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
4187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
4197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Destroy myself on the blocking pool.
4207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Note that base::DeletePointer<> cannot be used as the destructor of this
4217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // class is private.
4227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  blocking_task_runner_->PostTask(
4237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      FROM_HERE,
4247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      base::Bind(&FileCache::DestroyOnBlockingPool, base::Unretained(this)));
4257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
4267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
427c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void FileCache::DestroyOnBlockingPool() {
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AssertOnSequencedWorkerPool();
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delete this;
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4320f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)bool FileCache::RecoverFilesFromCacheDirectory(
4330f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    const base::FilePath& dest_directory,
434f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const ResourceMetadataStorage::RecoveredCacheInfoMap&
435f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        recovered_cache_info) {
4360f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  int file_number = 1;
4370f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
4380f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  base::FileEnumerator enumerator(cache_file_directory_,
4390f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                                  false,  // not recursive
4400f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                                  base::FileEnumerator::FILES);
4410f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  for (base::FilePath current = enumerator.Next(); !current.empty();
4420f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)       current = enumerator.Next()) {
4430f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    const std::string& id = GetIdFromPath(current);
444cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    ResourceEntry entry;
445cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    FileError error = storage_->GetEntry(id, &entry);
446cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (error != FILE_ERROR_OK && error != FILE_ERROR_NOT_FOUND)
447cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      return false;
448cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (error == FILE_ERROR_OK &&
449cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        entry.file_specific_info().cache_state().is_present()) {
4500f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      // This file is managed by FileCache, no need to recover it.
4510f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      continue;
4520f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    }
4530f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
4540f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    // If a cache entry which is non-dirty and has matching MD5 is found in
4550f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    // |recovered_cache_entries|, it means the current file is already uploaded
4560f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    // to the server. Just delete it instead of recovering it.
457f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    ResourceMetadataStorage::RecoveredCacheInfoMap::const_iterator it =
458f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        recovered_cache_info.find(id);
459f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (it != recovered_cache_info.end()) {
460f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // Due to the DB corruption, cache info might be recovered from old
461f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // revision. Perform MD5 check even when is_dirty is false just in case.
462f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      if (!it->second.is_dirty &&
463f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          it->second.md5 == util::GetMd5Digest(current)) {
4640f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        base::DeleteFile(current, false /* recursive */);
4650f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        continue;
4660f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      }
4670f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    }
4680f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
4690f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    // Read file contents to sniff mime type.
4700f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    std::vector<char> content(net::kMaxBytesToSniff);
4710f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    const int read_result =
472a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        base::ReadFile(current, &content[0], content.size());
4730f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    if (read_result < 0) {
4740f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      LOG(WARNING) << "Cannot read: " << current.value();
4750f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      return false;
4760f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    }
4770f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    if (read_result == 0)  // Skip empty files.
4780f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      continue;
4790f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
480f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Use recovered file name if available, otherwise decide file name with
481f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // sniffed mime type.
4820f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    base::FilePath dest_base_name(FILE_PATH_LITERAL("file"));
4830f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    std::string mime_type;
484f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (it != recovered_cache_info.end() && !it->second.title.empty()) {
485f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // We can use a file name recovered from the trashed DB.
486f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      dest_base_name = base::FilePath::FromUTF8Unsafe(it->second.title);
487f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    } else if (net::SniffMimeType(&content[0], read_result,
488f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                  net::FilePathToFileURL(current),
489f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                  std::string(), &mime_type) ||
490f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)               net::SniffMimeTypeFromLocalData(&content[0], read_result,
491f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                               &mime_type)) {
4920f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      // Change base name for common mime types.
4930f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      if (net::MatchesMimeType("image/*", mime_type)) {
4940f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        dest_base_name = base::FilePath(FILE_PATH_LITERAL("image"));
4950f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      } else if (net::MatchesMimeType("video/*", mime_type)) {
4960f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        dest_base_name = base::FilePath(FILE_PATH_LITERAL("video"));
4970f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      } else if (net::MatchesMimeType("audio/*", mime_type)) {
4980f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        dest_base_name = base::FilePath(FILE_PATH_LITERAL("audio"));
4990f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      }
5000f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
5010f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      // Estimate extension from mime type.
5020f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      std::vector<base::FilePath::StringType> extensions;
5030f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      base::FilePath::StringType extension;
5040f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      if (net::GetPreferredExtensionForMimeType(mime_type, &extension))
5050f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        extensions.push_back(extension);
5060f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      else
5070f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        net::GetExtensionsForMimeType(mime_type, &extensions);
5080f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
5090f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      // Add extension if possible.
5100f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      if (!extensions.empty())
5110f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        dest_base_name = dest_base_name.AddExtension(extensions[0]);
5120f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    }
5130f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
5140f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    // Add file number to the file name and move.
5150f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    const base::FilePath& dest_path = dest_directory.Append(dest_base_name)
5160f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        .InsertBeforeExtensionASCII(base::StringPrintf("%08d", file_number++));
517a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (!base::CreateDirectory(dest_directory) ||
5180f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        !base::Move(current, dest_path)) {
5190f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      LOG(WARNING) << "Failed to move: " << current.value()
5200f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                   << " to " << dest_path.value();
5210f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      return false;
5220f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    }
5230f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
5240f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  UMA_HISTOGRAM_COUNTS("Drive.NumberOfCacheFilesRecoveredAfterDBCorruption",
5250f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                       file_number - 1);
5260f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  return true;
5270f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
5280f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
529b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)FileError FileCache::MarkAsUnmounted(const base::FilePath& file_path) {
5302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AssertOnSequencedWorkerPool();
531c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(IsUnderFileCacheDirectory(file_path));
5322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
533424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  std::string id = GetIdFromPath(file_path);
5342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
535cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Get the entry associated with the id.
536cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ResourceEntry entry;
537cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  FileError error = storage_->GetEntry(id, &entry);
538cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (error != FILE_ERROR_OK)
539cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return error;
5402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
541424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  std::set<std::string>::iterator it = mounted_files_.find(id);
5427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (it == mounted_files_.end())
543c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return FILE_ERROR_INVALID_OPERATION;
5442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  mounted_files_.erase(it);
546c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return FILE_ERROR_OK;
5472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
549c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool FileCache::HasEnoughSpaceFor(int64 num_bytes,
550c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                  const base::FilePath& path) {
5512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int64 free_space = 0;
5522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (free_disk_space_getter_)
5532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    free_space = free_disk_space_getter_->AmountOfFreeDiskSpace();
5542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else
5552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    free_space = base::SysInfo::AmountOfFreeDiskSpace(path);
5562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Subtract this as if this portion does not exist.
5585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  free_space -= cryptohome::kMinFreeSpaceInBytes;
5592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return (free_space >= num_bytes);
5602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5628bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)bool FileCache::RenameCacheFilesToNewFormat() {
5638bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  base::FileEnumerator enumerator(cache_file_directory_,
5648bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                  false,  // not recursive
5658bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                  base::FileEnumerator::FILES);
5668bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  for (base::FilePath current = enumerator.Next(); !current.empty();
5678bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)       current = enumerator.Next()) {
5688bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    base::FilePath new_path = current.RemoveExtension();
5698bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    if (!new_path.Extension().empty()) {
5708bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      // Delete files with multiple extensions.
5718bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      if (!base::DeleteFile(current, false /* recursive */))
5728bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        return false;
5738bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      continue;
5748bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    }
5758bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    const std::string& id = GetIdFromPath(new_path);
5768bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    new_path = GetCacheFilePath(util::CanonicalizeResourceId(id));
5778bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    if (new_path != current && !base::Move(current, new_path))
5788bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      return false;
5797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
5808bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  return true;
5817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
5827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
5835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void FileCache::CloseForWrite(const std::string& id) {
5845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  AssertOnSequencedWorkerPool();
5855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::map<std::string, int>::iterator it = write_opened_files_.find(id);
5875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (it == write_opened_files_.end())
5885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
5895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_LT(0, it->second);
5915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  --it->second;
5925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (it->second == 0)
5935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    write_opened_files_.erase(it);
59446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
59546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Update last modified date.
59646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  ResourceEntry entry;
59746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  FileError error = storage_->GetEntry(id, &entry);
59846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (error != FILE_ERROR_OK) {
59946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    LOG(ERROR) << "Failed to get entry: " << id << ", "
60046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)               << FileErrorToString(error);
60146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return;
60246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
60346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  entry.mutable_file_info()->set_last_modified(
60446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      base::Time::Now().ToInternalValue());
60546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  error = storage_->PutEntry(entry);
60646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (error != FILE_ERROR_OK) {
60746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    LOG(ERROR) << "Failed to put entry: " << id << ", "
60846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)               << FileErrorToString(error);
60946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
6105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
612b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}  // namespace internal
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace drive
614