Home | History | Annotate | Download | only in file_system
      1 // 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 
      5 #include "chrome/browser/chromeos/drive/file_system/update_operation.h"
      6 
      7 #include "base/platform_file.h"
      8 #include "chrome/browser/chromeos/drive/drive.pb.h"
      9 #include "chrome/browser/chromeos/drive/file_cache.h"
     10 #include "chrome/browser/chromeos/drive/file_system/operation_observer.h"
     11 #include "chrome/browser/chromeos/drive/file_system_util.h"
     12 #include "chrome/browser/chromeos/drive/job_scheduler.h"
     13 #include "chrome/browser/chromeos/drive/resource_entry_conversion.h"
     14 #include "chrome/browser/chromeos/drive/resource_metadata.h"
     15 #include "chrome/browser/drive/drive_api_util.h"
     16 #include "content/public/browser/browser_thread.h"
     17 
     18 using content::BrowserThread;
     19 
     20 namespace drive {
     21 namespace file_system {
     22 
     23 struct UpdateOperation::LocalState {
     24   LocalState() : content_is_same(false) {
     25   }
     26 
     27   std::string local_id;
     28   ResourceEntry entry;
     29   base::FilePath drive_file_path;
     30   base::FilePath cache_file_path;
     31   bool content_is_same;
     32 };
     33 
     34 namespace {
     35 
     36 // Gets locally stored information about the specified file.
     37 FileError GetFileLocalState(internal::ResourceMetadata* metadata,
     38                             internal::FileCache* cache,
     39                             UpdateOperation::ContentCheckMode check,
     40                             UpdateOperation::LocalState* local_state) {
     41   FileError error = metadata->GetResourceEntryById(local_state->local_id,
     42                                                    &local_state->entry);
     43   if (error != FILE_ERROR_OK)
     44     return error;
     45 
     46   if (local_state->entry.file_info().is_directory())
     47     return FILE_ERROR_NOT_A_FILE;
     48 
     49   local_state->drive_file_path = metadata->GetFilePath(local_state->local_id);
     50   if (local_state->drive_file_path.empty())
     51     return FILE_ERROR_NOT_FOUND;
     52 
     53   error = cache->GetFile(local_state->local_id, &local_state->cache_file_path);
     54   if (error != FILE_ERROR_OK)
     55     return error;
     56 
     57   if (check == UpdateOperation::RUN_CONTENT_CHECK) {
     58     const std::string& md5 = util::GetMd5Digest(local_state->cache_file_path);
     59     local_state->content_is_same =
     60         (md5 == local_state->entry.file_specific_info().md5());
     61     if (local_state->content_is_same)
     62       cache->ClearDirty(local_state->local_id, md5);
     63   } else {
     64     local_state->content_is_same = false;
     65   }
     66 
     67   return FILE_ERROR_OK;
     68 }
     69 
     70 // Updates locally stored information about the specified file.
     71 FileError UpdateFileLocalState(
     72     internal::ResourceMetadata* metadata,
     73     internal::FileCache* cache,
     74     const std::string& local_id,
     75     scoped_ptr<google_apis::ResourceEntry> resource_entry,
     76     base::FilePath* drive_file_path) {
     77   ResourceEntry entry;
     78   std::string parent_resource_id;
     79   if (!ConvertToResourceEntry(*resource_entry, &entry, &parent_resource_id))
     80     return FILE_ERROR_NOT_A_FILE;
     81 
     82   std::string parent_local_id;
     83   FileError error = metadata->GetIdByResourceId(parent_resource_id,
     84                                                 &parent_local_id);
     85   if (error != FILE_ERROR_OK)
     86     return error;
     87   entry.set_local_id(local_id);
     88   entry.set_parent_local_id(parent_local_id);
     89 
     90   error = metadata->RefreshEntry(entry);
     91   if (error != FILE_ERROR_OK)
     92     return error;
     93 
     94   *drive_file_path = metadata->GetFilePath(local_id);
     95   if (drive_file_path->empty())
     96     return FILE_ERROR_NOT_FOUND;
     97 
     98   // Clear the dirty bit if we have updated an existing file.
     99   return cache->ClearDirty(local_id, entry.file_specific_info().md5());
    100 }
    101 
    102 }  // namespace
    103 
    104 UpdateOperation::UpdateOperation(
    105     base::SequencedTaskRunner* blocking_task_runner,
    106     OperationObserver* observer,
    107     JobScheduler* scheduler,
    108     internal::ResourceMetadata* metadata,
    109     internal::FileCache* cache)
    110     : blocking_task_runner_(blocking_task_runner),
    111       observer_(observer),
    112       scheduler_(scheduler),
    113       metadata_(metadata),
    114       cache_(cache),
    115       weak_ptr_factory_(this) {
    116   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    117 }
    118 
    119 UpdateOperation::~UpdateOperation() {
    120   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    121 }
    122 
    123 void UpdateOperation::UpdateFileByLocalId(
    124     const std::string& local_id,
    125     const ClientContext& context,
    126     ContentCheckMode check,
    127     const FileOperationCallback& callback) {
    128   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    129   DCHECK(!callback.is_null());
    130 
    131   LocalState* local_state = new LocalState;
    132   local_state->local_id = local_id;
    133   base::PostTaskAndReplyWithResult(
    134       blocking_task_runner_.get(),
    135       FROM_HERE,
    136       base::Bind(&GetFileLocalState,
    137                  metadata_,
    138                  cache_,
    139                  check,
    140                  local_state),
    141       base::Bind(&UpdateOperation::UpdateFileAfterGetLocalState,
    142                  weak_ptr_factory_.GetWeakPtr(),
    143                  context,
    144                  callback,
    145                  base::Owned(local_state)));
    146 }
    147 
    148 void UpdateOperation::UpdateFileAfterGetLocalState(
    149     const ClientContext& context,
    150     const FileOperationCallback& callback,
    151     const LocalState* local_state,
    152     FileError error) {
    153   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    154   DCHECK(!callback.is_null());
    155 
    156   if (error != FILE_ERROR_OK || local_state->content_is_same) {
    157     callback.Run(error);
    158     return;
    159   }
    160 
    161   scheduler_->UploadExistingFile(
    162       local_state->entry.resource_id(),
    163       local_state->drive_file_path,
    164       local_state->cache_file_path,
    165       local_state->entry.file_specific_info().content_mime_type(),
    166       "",  // etag
    167       context,
    168       base::Bind(&UpdateOperation::UpdateFileAfterUpload,
    169                  weak_ptr_factory_.GetWeakPtr(),
    170                  callback,
    171                  local_state->local_id));
    172 }
    173 
    174 void UpdateOperation::UpdateFileAfterUpload(
    175     const FileOperationCallback& callback,
    176     const std::string& local_id,
    177     google_apis::GDataErrorCode error,
    178     scoped_ptr<google_apis::ResourceEntry> resource_entry) {
    179   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    180   DCHECK(!callback.is_null());
    181 
    182   FileError drive_error = GDataToFileError(error);
    183   if (drive_error != FILE_ERROR_OK) {
    184     callback.Run(drive_error);
    185     return;
    186   }
    187 
    188   base::FilePath* drive_file_path = new base::FilePath;
    189   base::PostTaskAndReplyWithResult(
    190       blocking_task_runner_.get(),
    191       FROM_HERE,
    192       base::Bind(&UpdateFileLocalState,
    193                  metadata_,
    194                  cache_,
    195                  local_id,
    196                  base::Passed(&resource_entry),
    197                  drive_file_path),
    198       base::Bind(&UpdateOperation::UpdateFileAfterUpdateLocalState,
    199                  weak_ptr_factory_.GetWeakPtr(),
    200                  callback,
    201                  base::Owned(drive_file_path)));
    202 }
    203 
    204 void UpdateOperation::UpdateFileAfterUpdateLocalState(
    205     const FileOperationCallback& callback,
    206     const base::FilePath* drive_file_path,
    207     FileError error) {
    208   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    209   DCHECK(!callback.is_null());
    210 
    211   if (error != FILE_ERROR_OK) {
    212     callback.Run(error);
    213     return;
    214   }
    215   observer_->OnDirectoryChangedByOperation(drive_file_path->DirName());
    216   callback.Run(FILE_ERROR_OK);
    217 }
    218 
    219 }  // namespace file_system
    220 }  // namespace drive
    221