#include <vector>
#include "base/callback_helpers.h"
-#include "base/file_util.h"
#include "base/files/file_enumerator.h"
+#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/strings/string_util.h"
#include "chromeos/chromeos_constants.h"
#include "content/public/browser/browser_thread.h"
#include "google_apis/drive/task_util.h"
+#include "net/base/filename_util.h"
#include "net/base/mime_sniffer.h"
#include "net/base/mime_util.h"
-#include "net/base/net_util.h"
#include "third_party/cros_system_api/constants/cryptohome.h"
using content::BrowserThread;
return cache_file_directory_.IsParent(path);
}
-bool FileCache::GetCacheEntry(const std::string& id, FileCacheEntry* entry) {
- DCHECK(entry);
- AssertOnSequencedWorkerPool();
- return storage_->GetCacheEntry(id, entry);
-}
-
-scoped_ptr<FileCache::Iterator> FileCache::GetIterator() {
- AssertOnSequencedWorkerPool();
- return storage_->GetCacheEntryIterator();
-}
-
bool FileCache::FreeDiskSpaceIfNeededFor(int64 num_bytes) {
AssertOnSequencedWorkerPool();
DVLOG(1) << "Freeing up disk space for " << num_bytes;
// Remove all entries unless specially marked.
- scoped_ptr<ResourceMetadataStorage::CacheEntryIterator> it =
- storage_->GetCacheEntryIterator();
+ scoped_ptr<ResourceMetadataStorage::Iterator> it = storage_->GetIterator();
for (; !it->IsAtEnd(); it->Advance()) {
- const FileCacheEntry& entry = it->GetValue();
- if (!entry.is_pinned() &&
- !entry.is_dirty() &&
- !mounted_files_.count(it->GetID()))
- storage_->RemoveCacheEntry(it->GetID());
+ if (it->GetValue().file_specific_info().has_cache_state() &&
+ !it->GetValue().file_specific_info().cache_state().is_pinned() &&
+ !it->GetValue().file_specific_info().cache_state().is_dirty() &&
+ !mounted_files_.count(it->GetID())) {
+ ResourceEntry entry(it->GetValue());
+ entry.mutable_file_specific_info()->clear_cache_state();
+ storage_->PutEntry(entry);
+ }
}
- DCHECK(!it->HasError());
+ if (it->HasError())
+ return false;
// Remove all files which have no corresponding cache entries.
base::FileEnumerator enumerator(cache_file_directory_,
false, // not recursive
base::FileEnumerator::FILES);
- FileCacheEntry entry;
+ ResourceEntry entry;
for (base::FilePath current = enumerator.Next(); !current.empty();
current = enumerator.Next()) {
std::string id = GetIdFromPath(current);
- if (!storage_->GetCacheEntry(id, &entry))
+ FileError error = storage_->GetEntry(id, &entry);
+ if (error == FILE_ERROR_NOT_FOUND ||
+ (error == FILE_ERROR_OK &&
+ !entry.file_specific_info().cache_state().is_present()))
base::DeleteFile(current, false /* recursive */);
+ else if (error != FILE_ERROR_OK)
+ return false;
}
// Check the disk space again.
AssertOnSequencedWorkerPool();
DCHECK(cache_file_path);
- FileCacheEntry cache_entry;
- if (!storage_->GetCacheEntry(id, &cache_entry) ||
- !cache_entry.is_present())
+ ResourceEntry entry;
+ FileError error = storage_->GetEntry(id, &entry);
+ if (error != FILE_ERROR_OK)
+ return error;
+ if (!entry.file_specific_info().cache_state().is_present())
return FILE_ERROR_NOT_FOUND;
*cache_file_path = GetCacheFilePath(id);
FileOperationType file_operation_type) {
AssertOnSequencedWorkerPool();
+ ResourceEntry entry;
+ FileError error = storage_->GetEntry(id, &entry);
+ if (error != FILE_ERROR_OK)
+ return error;
+
int64 file_size = 0;
if (file_operation_type == FILE_OPERATION_COPY) {
if (!base::GetFileSize(source_path, &file_size)) {
}
// Now that file operations have completed, update metadata.
- FileCacheEntry cache_entry;
- storage_->GetCacheEntry(id, &cache_entry);
- cache_entry.set_md5(md5);
- cache_entry.set_is_present(true);
+ FileCacheEntry* cache_state =
+ entry.mutable_file_specific_info()->mutable_cache_state();
+ cache_state->set_md5(md5);
+ cache_state->set_is_present(true);
if (md5.empty())
- cache_entry.set_is_dirty(true);
- return storage_->PutCacheEntry(id, cache_entry) ?
- FILE_ERROR_OK : FILE_ERROR_FAILED;
+ cache_state->set_is_dirty(true);
+ return storage_->PutEntry(entry);
}
FileError FileCache::Pin(const std::string& id) {
AssertOnSequencedWorkerPool();
- FileCacheEntry cache_entry;
- storage_->GetCacheEntry(id, &cache_entry);
- cache_entry.set_is_pinned(true);
- return storage_->PutCacheEntry(id, cache_entry) ?
- FILE_ERROR_OK : FILE_ERROR_FAILED;
+ ResourceEntry entry;
+ FileError error = storage_->GetEntry(id, &entry);
+ if (error != FILE_ERROR_OK)
+ return error;
+ entry.mutable_file_specific_info()->mutable_cache_state()->set_is_pinned(
+ true);
+ return storage_->PutEntry(entry);
}
FileError FileCache::Unpin(const std::string& id) {
AssertOnSequencedWorkerPool();
// Unpinning a file means its entry must exist in cache.
- FileCacheEntry cache_entry;
- if (!storage_->GetCacheEntry(id, &cache_entry))
- return FILE_ERROR_NOT_FOUND;
+ ResourceEntry entry;
+ FileError error = storage_->GetEntry(id, &entry);
+ if (error != FILE_ERROR_OK)
+ return error;
// Now that file operations have completed, update metadata.
- if (cache_entry.is_present()) {
- cache_entry.set_is_pinned(false);
- if (!storage_->PutCacheEntry(id, cache_entry))
- return FILE_ERROR_FAILED;
+ if (entry.file_specific_info().cache_state().is_present()) {
+ entry.mutable_file_specific_info()->mutable_cache_state()->set_is_pinned(
+ false);
} else {
// Remove the existing entry if we are unpinning a non-present file.
- if (!storage_->RemoveCacheEntry(id))
- return FILE_ERROR_FAILED;
+ entry.mutable_file_specific_info()->clear_cache_state();
}
+ error = storage_->PutEntry(entry);
+ if (error != FILE_ERROR_OK)
+ return error;
// Now it's a chance to free up space if needed.
FreeDiskSpaceIfNeededFor(0);
DCHECK(cache_file_path);
// Get cache entry associated with the id and md5
- FileCacheEntry cache_entry;
- if (!storage_->GetCacheEntry(id, &cache_entry))
+ ResourceEntry entry;
+ FileError error = storage_->GetEntry(id, &entry);
+ if (error != FILE_ERROR_OK)
+ return error;
+ if (!entry.file_specific_info().cache_state().is_present())
return FILE_ERROR_NOT_FOUND;
if (mounted_files_.count(id))
// Marking a file dirty means its entry and actual file blob must exist in
// cache.
- FileCacheEntry cache_entry;
- if (!storage_->GetCacheEntry(id, &cache_entry) ||
- !cache_entry.is_present()) {
+ ResourceEntry entry;
+ FileError error = storage_->GetEntry(id, &entry);
+ if (error != FILE_ERROR_OK)
+ return error;
+ if (!entry.file_specific_info().cache_state().is_present()) {
LOG(WARNING) << "Can't mark dirty a file that wasn't cached: " << id;
return FILE_ERROR_NOT_FOUND;
}
- cache_entry.set_is_dirty(true);
- cache_entry.clear_md5();
- if (!storage_->PutCacheEntry(id, cache_entry))
- return FILE_ERROR_FAILED;
+ entry.mutable_file_specific_info()->mutable_cache_state()->set_is_dirty(true);
+ entry.mutable_file_specific_info()->mutable_cache_state()->clear_md5();
+ error = storage_->PutEntry(entry);
+ if (error != FILE_ERROR_OK)
+ return error;
write_opened_files_[id]++;
file_closer->reset(new base::ScopedClosureRunner(
- base::Bind(&google_apis::RunTaskOnThread,
+ base::Bind(&google_apis::RunTaskWithTaskRunner,
blocking_task_runner_,
base::Bind(&FileCache::CloseForWrite,
weak_ptr_factory_.GetWeakPtr(),
if (IsOpenedForWrite(id))
return FILE_ERROR_IN_USE;
- FileCacheEntry cache_entry;
- if (!storage_->GetCacheEntry(id, &cache_entry) ||
- !cache_entry.is_present())
+ ResourceEntry entry;
+ FileError error = storage_->GetEntry(id, &entry);
+ if (error != FILE_ERROR_OK)
+ return error;
+ if (!entry.file_specific_info().cache_state().is_present())
return FILE_ERROR_NOT_FOUND;
const std::string& md5 = util::GetMd5Digest(GetCacheFilePath(id));
if (md5.empty())
return FILE_ERROR_NOT_FOUND;
- cache_entry.set_md5(md5);
- return storage_->PutCacheEntry(id, cache_entry) ?
- FILE_ERROR_OK : FILE_ERROR_FAILED;
+ entry.mutable_file_specific_info()->mutable_cache_state()->set_md5(md5);
+ return storage_->PutEntry(entry);
}
FileError FileCache::ClearDirty(const std::string& id) {
// Clearing a dirty file means its entry and actual file blob must exist in
// cache.
- FileCacheEntry cache_entry;
- if (!storage_->GetCacheEntry(id, &cache_entry) ||
- !cache_entry.is_present()) {
+ ResourceEntry entry;
+ FileError error = storage_->GetEntry(id, &entry);
+ if (error != FILE_ERROR_OK)
+ return error;
+ if (!entry.file_specific_info().cache_state().is_present()) {
LOG(WARNING) << "Can't clear dirty state of a file that wasn't cached: "
<< id;
return FILE_ERROR_NOT_FOUND;
// If a file is not dirty (it should have been marked dirty via OpenForWrite),
// clearing its dirty state is an invalid operation.
- if (!cache_entry.is_dirty()) {
+ if (!entry.file_specific_info().cache_state().is_dirty()) {
LOG(WARNING) << "Can't clear dirty state of a non-dirty file: " << id;
return FILE_ERROR_INVALID_OPERATION;
}
- cache_entry.set_is_dirty(false);
- return storage_->PutCacheEntry(id, cache_entry) ?
- FILE_ERROR_OK : FILE_ERROR_FAILED;
+ entry.mutable_file_specific_info()->mutable_cache_state()->set_is_dirty(
+ false);
+ return storage_->PutEntry(entry);
}
FileError FileCache::Remove(const std::string& id) {
AssertOnSequencedWorkerPool();
- FileCacheEntry cache_entry;
+ ResourceEntry entry;
// If entry doesn't exist, nothing to do.
- if (!storage_->GetCacheEntry(id, &cache_entry))
+ FileError error = storage_->GetEntry(id, &entry);
+ if (error == FILE_ERROR_NOT_FOUND)
+ return FILE_ERROR_OK;
+ if (error != FILE_ERROR_OK)
+ return error;
+ if (!entry.file_specific_info().has_cache_state())
return FILE_ERROR_OK;
// Cannot delete a mounted file.
return FILE_ERROR_FAILED;
// Now that all file operations have completed, remove from metadata.
- return storage_->RemoveCacheEntry(id) ? FILE_ERROR_OK : FILE_ERROR_FAILED;
+ entry.mutable_file_specific_info()->clear_cache_state();
+ return storage_->PutEntry(entry);
}
bool FileCache::ClearAll() {
AssertOnSequencedWorkerPool();
- // Remove entries on the metadata.
- scoped_ptr<ResourceMetadataStorage::CacheEntryIterator> it =
- storage_->GetCacheEntryIterator();
- for (; !it->IsAtEnd(); it->Advance()) {
- if (!storage_->RemoveCacheEntry(it->GetID()))
- return false;
- }
-
- if (it->HasError())
- return false;
-
// Remove files.
base::FileEnumerator enumerator(cache_file_directory_,
false, // not recursive
// Older versions do not clear MD5 when marking entries dirty.
// Clear MD5 of all dirty entries to deal with old data.
- scoped_ptr<ResourceMetadataStorage::CacheEntryIterator> it =
- storage_->GetCacheEntryIterator();
+ scoped_ptr<ResourceMetadataStorage::Iterator> it = storage_->GetIterator();
for (; !it->IsAtEnd(); it->Advance()) {
- if (it->GetValue().is_dirty()) {
- FileCacheEntry new_entry(it->GetValue());
- new_entry.clear_md5();
- if (!storage_->PutCacheEntry(it->GetID(), new_entry))
+ if (it->GetValue().file_specific_info().cache_state().is_dirty()) {
+ ResourceEntry new_entry(it->GetValue());
+ new_entry.mutable_file_specific_info()->mutable_cache_state()->
+ clear_md5();
+ if (storage_->PutEntry(new_entry) != FILE_ERROR_OK)
return false;
}
}
+ if (it->HasError())
+ return false;
if (!RenameCacheFilesToNewFormat())
return false;
for (base::FilePath current = enumerator.Next(); !current.empty();
current = enumerator.Next()) {
const std::string& id = GetIdFromPath(current);
- FileCacheEntry entry;
- if (storage_->GetCacheEntry(id, &entry)) {
+ ResourceEntry entry;
+ FileError error = storage_->GetEntry(id, &entry);
+ if (error != FILE_ERROR_OK && error != FILE_ERROR_NOT_FOUND)
+ return false;
+ if (error == FILE_ERROR_OK &&
+ entry.file_specific_info().cache_state().is_present()) {
// This file is managed by FileCache, no need to recover it.
continue;
}
std::string id = GetIdFromPath(file_path);
- // Get cache entry associated with the id and md5
- FileCacheEntry cache_entry;
- if (!storage_->GetCacheEntry(id, &cache_entry))
- return FILE_ERROR_NOT_FOUND;
+ // Get the entry associated with the id.
+ ResourceEntry entry;
+ FileError error = storage_->GetEntry(id, &entry);
+ if (error != FILE_ERROR_OK)
+ return error;
std::set<std::string>::iterator it = mounted_files_.find(id);
if (it == mounted_files_.end())
--it->second;
if (it->second == 0)
write_opened_files_.erase(it);
+
+ // Update last modified date.
+ ResourceEntry entry;
+ FileError error = storage_->GetEntry(id, &entry);
+ if (error != FILE_ERROR_OK) {
+ LOG(ERROR) << "Failed to get entry: " << id << ", "
+ << FileErrorToString(error);
+ return;
+ }
+ entry.mutable_file_info()->set_last_modified(
+ base::Time::Now().ToInternalValue());
+ error = storage_->PutEntry(entry);
+ if (error != FILE_ERROR_OK) {
+ LOG(ERROR) << "Failed to put entry: " << id << ", "
+ << FileErrorToString(error);
+ }
}
} // namespace internal