Home | History | Annotate | Download | only in file_system
      1 // Copyright 2013 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/get_file_for_saving_operation.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/bind_helpers.h"
      9 #include "base/callback_helpers.h"
     10 #include "chrome/browser/chromeos/drive/file_cache.h"
     11 #include "chrome/browser/chromeos/drive/file_system/create_file_operation.h"
     12 #include "chrome/browser/chromeos/drive/file_system/download_operation.h"
     13 #include "chrome/browser/chromeos/drive/file_system/operation_delegate.h"
     14 #include "chrome/browser/chromeos/drive/file_write_watcher.h"
     15 #include "chrome/browser/chromeos/drive/job_scheduler.h"
     16 #include "chrome/browser/drive/event_logger.h"
     17 #include "content/public/browser/browser_thread.h"
     18 
     19 using content::BrowserThread;
     20 
     21 namespace drive {
     22 namespace file_system {
     23 
     24 namespace {
     25 
     26 FileError OpenCacheFileForWrite(
     27     internal::ResourceMetadata* metadata,
     28     internal::FileCache* cache,
     29     const std::string& local_id,
     30     scoped_ptr<base::ScopedClosureRunner>* file_closer,
     31     ResourceEntry* entry) {
     32   FileError error = cache->OpenForWrite(local_id, file_closer);
     33   if (error != FILE_ERROR_OK)
     34     return error;
     35   return metadata->GetResourceEntryById(local_id, entry);
     36 }
     37 
     38 }  // namespace
     39 
     40 GetFileForSavingOperation::GetFileForSavingOperation(
     41     EventLogger* logger,
     42     base::SequencedTaskRunner* blocking_task_runner,
     43     OperationDelegate* delegate,
     44     JobScheduler* scheduler,
     45     internal::ResourceMetadata* metadata,
     46     internal::FileCache* cache,
     47     const base::FilePath& temporary_file_directory)
     48     : logger_(logger),
     49       create_file_operation_(new CreateFileOperation(blocking_task_runner,
     50                                                      delegate,
     51                                                      metadata)),
     52       download_operation_(new DownloadOperation(blocking_task_runner,
     53                                                 delegate,
     54                                                 scheduler,
     55                                                 metadata,
     56                                                 cache,
     57                                                 temporary_file_directory)),
     58       file_write_watcher_(new internal::FileWriteWatcher),
     59       blocking_task_runner_(blocking_task_runner),
     60       delegate_(delegate),
     61       metadata_(metadata),
     62       cache_(cache),
     63       weak_ptr_factory_(this) {
     64 }
     65 
     66 GetFileForSavingOperation::~GetFileForSavingOperation() {
     67 }
     68 
     69 void GetFileForSavingOperation::GetFileForSaving(
     70     const base::FilePath& file_path,
     71     const GetFileCallback& callback) {
     72   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     73   DCHECK(!callback.is_null());
     74 
     75   create_file_operation_->CreateFile(
     76       file_path,
     77       false,  // error_if_already_exists
     78       std::string(),  // no specific mime type
     79       base::Bind(&GetFileForSavingOperation::GetFileForSavingAfterCreate,
     80                  weak_ptr_factory_.GetWeakPtr(),
     81                  file_path,
     82                  callback));
     83 }
     84 
     85 void GetFileForSavingOperation::GetFileForSavingAfterCreate(
     86     const base::FilePath& file_path,
     87     const GetFileCallback& callback,
     88     FileError error) {
     89   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     90   DCHECK(!callback.is_null());
     91 
     92   if (error != FILE_ERROR_OK) {
     93     callback.Run(error, base::FilePath(), scoped_ptr<ResourceEntry>());
     94     return;
     95   }
     96 
     97   download_operation_->EnsureFileDownloadedByPath(
     98       file_path,
     99       ClientContext(USER_INITIATED),
    100       GetFileContentInitializedCallback(),
    101       google_apis::GetContentCallback(),
    102       base::Bind(&GetFileForSavingOperation::GetFileForSavingAfterDownload,
    103                  weak_ptr_factory_.GetWeakPtr(),
    104                  callback));
    105 }
    106 
    107 void GetFileForSavingOperation::GetFileForSavingAfterDownload(
    108     const GetFileCallback& callback,
    109     FileError error,
    110     const base::FilePath& cache_path,
    111     scoped_ptr<ResourceEntry> entry) {
    112   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    113   DCHECK(!callback.is_null());
    114 
    115   if (error != FILE_ERROR_OK) {
    116     callback.Run(error, base::FilePath(), scoped_ptr<ResourceEntry>());
    117     return;
    118   }
    119 
    120   const std::string& local_id = entry->local_id();
    121   ResourceEntry* entry_ptr = entry.get();
    122   scoped_ptr<base::ScopedClosureRunner>* file_closer =
    123       new scoped_ptr<base::ScopedClosureRunner>;
    124   base::PostTaskAndReplyWithResult(
    125       blocking_task_runner_.get(),
    126       FROM_HERE,
    127       base::Bind(&OpenCacheFileForWrite,
    128                  metadata_,
    129                  cache_,
    130                  local_id,
    131                  file_closer,
    132                  entry_ptr),
    133       base::Bind(&GetFileForSavingOperation::GetFileForSavingAfterOpenForWrite,
    134                  weak_ptr_factory_.GetWeakPtr(),
    135                  callback,
    136                  cache_path,
    137                  base::Passed(&entry),
    138                  base::Owned(file_closer)));
    139 }
    140 
    141 void GetFileForSavingOperation::GetFileForSavingAfterOpenForWrite(
    142     const GetFileCallback& callback,
    143     const base::FilePath& cache_path,
    144     scoped_ptr<ResourceEntry> entry,
    145     scoped_ptr<base::ScopedClosureRunner>* file_closer,
    146     FileError error) {
    147   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    148   DCHECK(!callback.is_null());
    149 
    150   if (error != FILE_ERROR_OK) {
    151     callback.Run(error, base::FilePath(), scoped_ptr<ResourceEntry>());
    152     return;
    153   }
    154 
    155   const std::string& local_id = entry->local_id();
    156   file_write_watcher_->StartWatch(
    157       cache_path,
    158       base::Bind(&GetFileForSavingOperation::GetFileForSavingAfterWatch,
    159                  weak_ptr_factory_.GetWeakPtr(),
    160                  callback,
    161                  cache_path,
    162                  base::Passed(&entry)),
    163       base::Bind(&GetFileForSavingOperation::OnWriteEvent,
    164                  weak_ptr_factory_.GetWeakPtr(),
    165                  local_id,
    166                  base::Passed(file_closer)));
    167 }
    168 
    169 void GetFileForSavingOperation::GetFileForSavingAfterWatch(
    170     const GetFileCallback& callback,
    171     const base::FilePath& cache_path,
    172     scoped_ptr<ResourceEntry> entry,
    173     bool success) {
    174   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    175   DCHECK(!callback.is_null());
    176 
    177   logger_->Log(logging::LOG_INFO, "Started watching modification to %s [%s].",
    178                entry->local_id().c_str(),
    179                success ? "ok" : "fail");
    180 
    181   if (!success) {
    182     callback.Run(FILE_ERROR_FAILED,
    183                  base::FilePath(), scoped_ptr<ResourceEntry>());
    184     return;
    185   }
    186 
    187   callback.Run(FILE_ERROR_OK, cache_path, entry.Pass());
    188 }
    189 
    190 void GetFileForSavingOperation::OnWriteEvent(
    191     const std::string& local_id,
    192     scoped_ptr<base::ScopedClosureRunner> file_closer) {
    193   logger_->Log(logging::LOG_INFO, "Detected modification to %s.",
    194                local_id.c_str());
    195 
    196   delegate_->OnEntryUpdatedByOperation(local_id);
    197 
    198   // Clients may have enlarged the file. By FreeDiskpSpaceIfNeededFor(0),
    199   // we try to ensure (0 + the-minimum-safe-margin = 512MB as of now) space.
    200   blocking_task_runner_->PostTask(
    201       FROM_HERE,
    202       base::Bind(base::IgnoreResult(
    203           base::Bind(&internal::FileCache::FreeDiskSpaceIfNeededFor,
    204                      base::Unretained(cache_),
    205                      0))));
    206 }
    207 
    208 }  // namespace file_system
    209 }  // namespace drive
    210