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