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/open_file_operation.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/bind_helpers.h"
      9 #include "base/callback_helpers.h"
     10 #include "base/files/file_path.h"
     11 #include "base/logging.h"
     12 #include "base/message_loop/message_loop_proxy.h"
     13 #include "base/task_runner_util.h"
     14 #include "chrome/browser/chromeos/drive/drive.pb.h"
     15 #include "chrome/browser/chromeos/drive/file_cache.h"
     16 #include "chrome/browser/chromeos/drive/file_errors.h"
     17 #include "chrome/browser/chromeos/drive/file_system/create_file_operation.h"
     18 #include "chrome/browser/chromeos/drive/file_system/download_operation.h"
     19 #include "chrome/browser/chromeos/drive/file_system/operation_observer.h"
     20 #include "chrome/browser/chromeos/drive/job_scheduler.h"
     21 #include "content/public/browser/browser_thread.h"
     22 
     23 using content::BrowserThread;
     24 
     25 namespace drive {
     26 namespace file_system {
     27 
     28 OpenFileOperation::OpenFileOperation(
     29     base::SequencedTaskRunner* blocking_task_runner,
     30     OperationObserver* observer,
     31     JobScheduler* scheduler,
     32     internal::ResourceMetadata* metadata,
     33     internal::FileCache* cache,
     34     const base::FilePath& temporary_file_directory)
     35     : blocking_task_runner_(blocking_task_runner),
     36       observer_(observer),
     37       cache_(cache),
     38       create_file_operation_(new CreateFileOperation(
     39           blocking_task_runner, observer, metadata)),
     40       download_operation_(new DownloadOperation(
     41           blocking_task_runner, observer, scheduler,
     42           metadata, cache, temporary_file_directory)),
     43       weak_ptr_factory_(this) {
     44 }
     45 
     46 OpenFileOperation::~OpenFileOperation() {
     47 }
     48 
     49 void OpenFileOperation::OpenFile(const base::FilePath& file_path,
     50                                  OpenMode open_mode,
     51                                  const std::string& mime_type,
     52                                  const OpenFileCallback& callback) {
     53   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     54   DCHECK(!callback.is_null());
     55 
     56   switch (open_mode) {
     57     case OPEN_FILE:
     58       // It is not necessary to create a new file even if not exists.
     59       // So call OpenFileAfterCreateFile directly with FILE_ERROR_OK
     60       // to skip file creation.
     61       OpenFileAfterCreateFile(file_path, callback, FILE_ERROR_OK);
     62       break;
     63     case CREATE_FILE:
     64       create_file_operation_->CreateFile(
     65           file_path,
     66           true,  // exclusive: fail if already exists
     67           mime_type,
     68           base::Bind(&OpenFileOperation::OpenFileAfterCreateFile,
     69                      weak_ptr_factory_.GetWeakPtr(), file_path, callback));
     70       break;
     71     case OPEN_OR_CREATE_FILE:
     72       create_file_operation_->CreateFile(
     73           file_path,
     74           false,  // not-exclusive
     75           mime_type,
     76           base::Bind(&OpenFileOperation::OpenFileAfterCreateFile,
     77                      weak_ptr_factory_.GetWeakPtr(), file_path, callback));
     78       break;
     79   }
     80 }
     81 
     82 void OpenFileOperation::OpenFileAfterCreateFile(
     83     const base::FilePath& file_path,
     84     const OpenFileCallback& callback,
     85     FileError error) {
     86   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     87   DCHECK(!callback.is_null());
     88 
     89   if (error != FILE_ERROR_OK) {
     90     callback.Run(error, base::FilePath(), base::Closure());
     91     return;
     92   }
     93 
     94   download_operation_->EnsureFileDownloadedByPath(
     95       file_path,
     96       ClientContext(USER_INITIATED),
     97       GetFileContentInitializedCallback(),
     98       google_apis::GetContentCallback(),
     99       base::Bind(
    100           &OpenFileOperation::OpenFileAfterFileDownloaded,
    101           weak_ptr_factory_.GetWeakPtr(), callback));
    102 }
    103 
    104 void OpenFileOperation::OpenFileAfterFileDownloaded(
    105     const OpenFileCallback& callback,
    106     FileError error,
    107     const base::FilePath& local_file_path,
    108     scoped_ptr<ResourceEntry> entry) {
    109   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    110   DCHECK(!callback.is_null());
    111 
    112   if (error == FILE_ERROR_OK) {
    113     DCHECK(entry);
    114     DCHECK(entry->has_file_specific_info());
    115     if (entry->file_specific_info().is_hosted_document())
    116       // No support for opening a hosted document.
    117       error = FILE_ERROR_INVALID_OPERATION;
    118   }
    119 
    120   if (error != FILE_ERROR_OK) {
    121     callback.Run(error, base::FilePath(), base::Closure());
    122     return;
    123   }
    124 
    125   scoped_ptr<base::ScopedClosureRunner>* file_closer =
    126       new scoped_ptr<base::ScopedClosureRunner>;
    127   base::PostTaskAndReplyWithResult(
    128       blocking_task_runner_.get(),
    129       FROM_HERE,
    130       base::Bind(&internal::FileCache::OpenForWrite,
    131                  base::Unretained(cache_),
    132                  entry->local_id(),
    133                  file_closer),
    134       base::Bind(&OpenFileOperation::OpenFileAfterOpenForWrite,
    135                  weak_ptr_factory_.GetWeakPtr(),
    136                  local_file_path,
    137                  entry->local_id(),
    138                  callback,
    139                  base::Owned(file_closer)));
    140 }
    141 
    142 void OpenFileOperation::OpenFileAfterOpenForWrite(
    143     const base::FilePath& local_file_path,
    144     const std::string& local_id,
    145     const OpenFileCallback& callback,
    146     scoped_ptr<base::ScopedClosureRunner>* file_closer,
    147     FileError error) {
    148   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    149   DCHECK(!callback.is_null());
    150 
    151   if (error != FILE_ERROR_OK) {
    152     callback.Run(error, base::FilePath(), base::Closure());
    153     return;
    154   }
    155 
    156   ++open_files_[local_id];
    157   callback.Run(error, local_file_path,
    158                base::Bind(&OpenFileOperation::CloseFile,
    159                           weak_ptr_factory_.GetWeakPtr(),
    160                           local_id,
    161                           base::Passed(file_closer)));
    162 }
    163 
    164 void OpenFileOperation::CloseFile(
    165     const std::string& local_id,
    166     scoped_ptr<base::ScopedClosureRunner> file_closer) {
    167   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    168   DCHECK_GT(open_files_[local_id], 0);
    169 
    170   if (--open_files_[local_id] == 0) {
    171     // All clients closes this file, so notify to upload the file.
    172     open_files_.erase(local_id);
    173     observer_->OnEntryUpdatedByOperation(local_id);
    174 
    175     // Clients may have enlarged the file. By FreeDiskpSpaceIfNeededFor(0),
    176     // we try to ensure (0 + the-minimum-safe-margin = 512MB as of now) space.
    177     blocking_task_runner_->PostTask(
    178         FROM_HERE,
    179         base::Bind(base::IgnoreResult(
    180             base::Bind(&internal::FileCache::FreeDiskSpaceIfNeededFor,
    181                        base::Unretained(cache_),
    182                        0))));
    183   }
    184 }
    185 
    186 }  // namespace file_system
    187 }  // namespace drive
    188