syncable_file_system_operation.cc revision 2385ea399aae016c0806a4f9ef3c9cfe3d2a39df
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/sync_file_system/local/syncable_file_system_operation.h" 6 7#include "base/logging.h" 8#include "chrome/browser/sync_file_system/local/local_file_sync_context.h" 9#include "chrome/browser/sync_file_system/local/sync_file_system_backend.h" 10#include "chrome/browser/sync_file_system/local/syncable_file_operation_runner.h" 11#include "chrome/browser/sync_file_system/syncable_file_system_util.h" 12#include "net/url_request/url_request.h" 13#include "webkit/browser/fileapi/file_system_context.h" 14#include "webkit/browser/fileapi/file_system_operation_context.h" 15#include "webkit/browser/fileapi/file_system_operation_impl.h" 16#include "webkit/browser/fileapi/file_system_url.h" 17#include "webkit/browser/fileapi/sandbox_file_system_backend.h" 18#include "webkit/common/blob/shareable_file_reference.h" 19 20using fileapi::FileSystemURL; 21using fileapi::FileSystemOperationContext; 22using fileapi::FileSystemOperationImpl; 23 24namespace sync_file_system { 25 26namespace { 27 28void WriteCallbackAdapter( 29 const SyncableFileSystemOperation::WriteCallback& callback, 30 base::PlatformFileError status) { 31 callback.Run(status, 0, true); 32} 33 34} // namespace 35 36class SyncableFileSystemOperation::QueueableTask 37 : public SyncableFileOperationRunner::Task { 38 public: 39 QueueableTask(base::WeakPtr<SyncableFileSystemOperation> operation, 40 const base::Closure& task) 41 : operation_(operation), 42 task_(task), 43 target_paths_(operation->target_paths_) {} 44 45 virtual ~QueueableTask() { 46 DCHECK(!operation_); 47 } 48 49 virtual void Run() OVERRIDE { 50 DCHECK(!task_.is_null()); 51 task_.Run(); 52 operation_.reset(); 53 } 54 55 virtual void Cancel() OVERRIDE { 56 DCHECK(!task_.is_null()); 57 if (operation_) 58 operation_->OnCancelled(); 59 task_.Reset(); 60 operation_.reset(); 61 } 62 63 virtual const std::vector<FileSystemURL>& target_paths() const OVERRIDE { 64 return target_paths_; 65 } 66 67 private: 68 base::WeakPtr<SyncableFileSystemOperation> operation_; 69 base::Closure task_; 70 std::vector<FileSystemURL> target_paths_; 71 DISALLOW_COPY_AND_ASSIGN(QueueableTask); 72}; 73 74SyncableFileSystemOperation::~SyncableFileSystemOperation() {} 75 76void SyncableFileSystemOperation::CreateFile( 77 const FileSystemURL& url, 78 bool exclusive, 79 const StatusCallback& callback) { 80 DCHECK(CalledOnValidThread()); 81 if (!operation_runner_.get()) { 82 callback.Run(base::PLATFORM_FILE_ERROR_NOT_FOUND); 83 return; 84 } 85 DCHECK(operation_runner_.get()); 86 target_paths_.push_back(url); 87 completion_callback_ = callback; 88 scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask( 89 AsWeakPtr(), 90 base::Bind(&FileSystemOperation::CreateFile, 91 NewOperation()->AsWeakPtr(), 92 url, exclusive, 93 base::Bind(&self::DidFinish, AsWeakPtr())))); 94 operation_runner_->PostOperationTask(task.Pass()); 95} 96 97void SyncableFileSystemOperation::CreateDirectory( 98 const FileSystemURL& url, 99 bool exclusive, 100 bool recursive, 101 const StatusCallback& callback) { 102 DCHECK(CalledOnValidThread()); 103 if (!operation_runner_.get()) { 104 callback.Run(base::PLATFORM_FILE_ERROR_NOT_FOUND); 105 return; 106 } 107 if (!is_directory_operation_enabled_) { 108 callback.Run(base::PLATFORM_FILE_ERROR_INVALID_OPERATION); 109 return; 110 } 111 DCHECK(operation_runner_.get()); 112 target_paths_.push_back(url); 113 completion_callback_ = callback; 114 scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask( 115 AsWeakPtr(), 116 base::Bind(&FileSystemOperation::CreateDirectory, 117 NewOperation()->AsWeakPtr(), 118 url, exclusive, recursive, 119 base::Bind(&self::DidFinish, AsWeakPtr())))); 120 operation_runner_->PostOperationTask(task.Pass()); 121} 122 123void SyncableFileSystemOperation::Copy( 124 const FileSystemURL& src_url, 125 const FileSystemURL& dest_url, 126 const StatusCallback& callback) { 127 DCHECK(CalledOnValidThread()); 128 if (!operation_runner_.get()) { 129 callback.Run(base::PLATFORM_FILE_ERROR_NOT_FOUND); 130 return; 131 } 132 DCHECK(operation_runner_.get()); 133 target_paths_.push_back(dest_url); 134 completion_callback_ = callback; 135 scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask( 136 AsWeakPtr(), 137 base::Bind(&FileSystemOperation::Copy, 138 NewOperation()->AsWeakPtr(), 139 src_url, dest_url, 140 base::Bind(&self::DidFinish, AsWeakPtr())))); 141 operation_runner_->PostOperationTask(task.Pass()); 142} 143 144void SyncableFileSystemOperation::Move( 145 const FileSystemURL& src_url, 146 const FileSystemURL& dest_url, 147 const StatusCallback& callback) { 148 DCHECK(CalledOnValidThread()); 149 if (!operation_runner_.get()) { 150 callback.Run(base::PLATFORM_FILE_ERROR_NOT_FOUND); 151 return; 152 } 153 DCHECK(operation_runner_.get()); 154 target_paths_.push_back(src_url); 155 target_paths_.push_back(dest_url); 156 completion_callback_ = callback; 157 scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask( 158 AsWeakPtr(), 159 base::Bind(&FileSystemOperation::Move, 160 NewOperation()->AsWeakPtr(), 161 src_url, dest_url, 162 base::Bind(&self::DidFinish, AsWeakPtr())))); 163 operation_runner_->PostOperationTask(task.Pass()); 164} 165 166void SyncableFileSystemOperation::DirectoryExists( 167 const FileSystemURL& url, 168 const StatusCallback& callback) { 169 DCHECK(CalledOnValidThread()); 170 NewOperation()->DirectoryExists(url, callback); 171} 172 173void SyncableFileSystemOperation::FileExists( 174 const FileSystemURL& url, 175 const StatusCallback& callback) { 176 DCHECK(CalledOnValidThread()); 177 NewOperation()->FileExists(url, callback); 178} 179 180void SyncableFileSystemOperation::GetMetadata( 181 const FileSystemURL& url, 182 const GetMetadataCallback& callback) { 183 DCHECK(CalledOnValidThread()); 184 NewOperation()->GetMetadata(url, callback); 185} 186 187void SyncableFileSystemOperation::ReadDirectory( 188 const FileSystemURL& url, 189 const ReadDirectoryCallback& callback) { 190 DCHECK(CalledOnValidThread()); 191 // This is a read operation and there'd be no hard to let it go even if 192 // directory operation is disabled. (And we should allow this if it's made 193 // on the root directory) 194 NewOperation()->ReadDirectory(url, callback); 195} 196 197void SyncableFileSystemOperation::Remove( 198 const FileSystemURL& url, bool recursive, 199 const StatusCallback& callback) { 200 DCHECK(CalledOnValidThread()); 201 if (!operation_runner_.get()) { 202 callback.Run(base::PLATFORM_FILE_ERROR_NOT_FOUND); 203 return; 204 } 205 DCHECK(operation_runner_.get()); 206 target_paths_.push_back(url); 207 completion_callback_ = callback; 208 scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask( 209 AsWeakPtr(), 210 base::Bind(&FileSystemOperation::Remove, 211 NewOperation()->AsWeakPtr(), 212 url, recursive, 213 base::Bind(&self::DidFinish, AsWeakPtr())))); 214 operation_runner_->PostOperationTask(task.Pass()); 215} 216 217void SyncableFileSystemOperation::Write( 218 const FileSystemURL& url, 219 scoped_ptr<fileapi::FileWriterDelegate> writer_delegate, 220 scoped_ptr<net::URLRequest> blob_request, 221 const WriteCallback& callback) { 222 DCHECK(CalledOnValidThread()); 223 if (!operation_runner_.get()) { 224 callback.Run(base::PLATFORM_FILE_ERROR_NOT_FOUND, 0, true); 225 return; 226 } 227 DCHECK(operation_runner_.get()); 228 target_paths_.push_back(url); 229 completion_callback_ = base::Bind(&WriteCallbackAdapter, callback); 230 scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask( 231 AsWeakPtr(), 232 base::Bind(&FileSystemOperation::Write, 233 NewOperation()->AsWeakPtr(), 234 url, 235 base::Passed(&writer_delegate), 236 base::Passed(&blob_request), 237 base::Bind(&self::DidWrite, AsWeakPtr(), callback)))); 238 operation_runner_->PostOperationTask(task.Pass()); 239} 240 241void SyncableFileSystemOperation::Truncate( 242 const FileSystemURL& url, int64 length, 243 const StatusCallback& callback) { 244 DCHECK(CalledOnValidThread()); 245 if (!operation_runner_.get()) { 246 callback.Run(base::PLATFORM_FILE_ERROR_NOT_FOUND); 247 return; 248 } 249 DCHECK(operation_runner_.get()); 250 target_paths_.push_back(url); 251 completion_callback_ = callback; 252 scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask( 253 AsWeakPtr(), 254 base::Bind(&FileSystemOperation::Truncate, 255 NewOperation()->AsWeakPtr(), 256 url, length, 257 base::Bind(&self::DidFinish, AsWeakPtr())))); 258 operation_runner_->PostOperationTask(task.Pass()); 259} 260 261void SyncableFileSystemOperation::TouchFile( 262 const FileSystemURL& url, 263 const base::Time& last_access_time, 264 const base::Time& last_modified_time, 265 const StatusCallback& callback) { 266 DCHECK(CalledOnValidThread()); 267 NewOperation()->TouchFile(url, last_access_time, 268 last_modified_time, callback); 269} 270 271void SyncableFileSystemOperation::OpenFile( 272 const FileSystemURL& url, 273 int file_flags, 274 base::ProcessHandle peer_handle, 275 const OpenFileCallback& callback) { 276 NOTREACHED(); 277} 278 279void SyncableFileSystemOperation::Cancel( 280 const StatusCallback& cancel_callback) { 281 DCHECK(CalledOnValidThread()); 282 DCHECK(inflight_operation_); 283 inflight_operation_->Cancel(cancel_callback); 284} 285 286void SyncableFileSystemOperation::CreateSnapshotFile( 287 const FileSystemURL& path, 288 const SnapshotFileCallback& callback) { 289 DCHECK(CalledOnValidThread()); 290 NewOperation()->CreateSnapshotFile(path, callback); 291} 292 293void SyncableFileSystemOperation::CopyInForeignFile( 294 const base::FilePath& src_local_disk_path, 295 const FileSystemURL& dest_url, 296 const StatusCallback& callback) { 297 DCHECK(CalledOnValidThread()); 298 if (!operation_runner_.get()) { 299 callback.Run(base::PLATFORM_FILE_ERROR_NOT_FOUND); 300 return; 301 } 302 DCHECK(operation_runner_.get()); 303 target_paths_.push_back(dest_url); 304 completion_callback_ = callback; 305 scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask( 306 AsWeakPtr(), 307 base::Bind(&FileSystemOperationImpl::CopyInForeignFile, 308 NewOperation()->AsWeakPtr(), 309 src_local_disk_path, dest_url, 310 base::Bind(&self::DidFinish, AsWeakPtr())))); 311 operation_runner_->PostOperationTask(task.Pass()); 312} 313 314SyncableFileSystemOperation::SyncableFileSystemOperation( 315 const FileSystemURL& url, 316 fileapi::FileSystemContext* file_system_context, 317 scoped_ptr<FileSystemOperationContext> operation_context) 318 : FileSystemOperationImpl(url, file_system_context, 319 operation_context.Pass()), 320 url_(url) { 321 DCHECK(file_system_context); 322 SyncFileSystemBackend* backend = 323 SyncFileSystemBackend::GetBackend(file_system_context); 324 DCHECK(backend); 325 if (!backend->sync_context()) { 326 // Syncable FileSystem is opened in a file system context which doesn't 327 // support (or is not initialized for) the API. 328 // Returning here to leave operation_runner_ as NULL. 329 return; 330 } 331 operation_runner_ = backend->sync_context()->operation_runner(); 332 is_directory_operation_enabled_ = IsSyncFSDirectoryOperationEnabled(); 333} 334 335FileSystemOperationImpl* SyncableFileSystemOperation::NewOperation() { 336 DCHECK(operation_context_); 337 inflight_operation_.reset(new FileSystemOperationImpl( 338 url_, file_system_context(), operation_context_.Pass())); 339 DCHECK(inflight_operation_); 340 return inflight_operation_.get(); 341} 342 343void SyncableFileSystemOperation::DidFinish(base::PlatformFileError status) { 344 DCHECK(CalledOnValidThread()); 345 DCHECK(!completion_callback_.is_null()); 346 if (operation_runner_.get()) 347 operation_runner_->OnOperationCompleted(target_paths_); 348 completion_callback_.Run(status); 349} 350 351void SyncableFileSystemOperation::DidWrite( 352 const WriteCallback& callback, 353 base::PlatformFileError result, 354 int64 bytes, 355 bool complete) { 356 DCHECK(CalledOnValidThread()); 357 if (!complete) { 358 callback.Run(result, bytes, complete); 359 return; 360 } 361 if (operation_runner_.get()) 362 operation_runner_->OnOperationCompleted(target_paths_); 363 callback.Run(result, bytes, complete); 364} 365 366void SyncableFileSystemOperation::OnCancelled() { 367 DCHECK(!completion_callback_.is_null()); 368 completion_callback_.Run(base::PLATFORM_FILE_ERROR_ABORT); 369} 370 371} // namespace sync_file_system 372