Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / drive / file_cache.cc
index c387cdd..0fea321 100644 (file)
@@ -7,8 +7,8 @@
 #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"
@@ -21,9 +21,9 @@
 #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;
@@ -71,17 +71,6 @@ bool FileCache::IsUnderFileCacheDirectory(const base::FilePath& path) const {
   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();
 
@@ -93,27 +82,35 @@ bool FileCache::FreeDiskSpaceIfNeededFor(int64 num_bytes) {
   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.
@@ -125,9 +122,11 @@ FileError FileCache::GetFile(const std::string& id,
   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);
@@ -140,6 +139,11 @@ FileError FileCache::Store(const std::string& 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)) {
@@ -176,44 +180,47 @@ FileError FileCache::Store(const std::string& id,
   }
 
   // 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);
@@ -227,8 +234,11 @@ FileError FileCache::MarkAsMounted(const std::string& id,
   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))
@@ -257,21 +267,24 @@ FileError FileCache::OpenForWrite(
 
   // 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(),
@@ -290,18 +303,19 @@ FileError FileCache::UpdateMd5(const std::string& id) {
   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) {
@@ -312,9 +326,11 @@ 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;
@@ -322,23 +338,28 @@ FileError FileCache::ClearDirty(const std::string& id) {
 
   // 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.
@@ -351,23 +372,13 @@ FileError FileCache::Remove(const std::string& id) {
     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
@@ -384,16 +395,18 @@ bool FileCache::Initialize() {
 
   // 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;
@@ -428,8 +441,12 @@ bool FileCache::RecoverFilesFromCacheDirectory(
   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;
     }
@@ -515,10 +532,11 @@ FileError FileCache::MarkAsUnmounted(const base::FilePath& file_path) {
 
   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())
@@ -573,6 +591,22 @@ void FileCache::CloseForWrite(const std::string& id) {
   --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