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