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