syncable_file_system_operation.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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.h" 15#include "webkit/browser/fileapi/file_system_operation_context.h" 16#include "webkit/browser/fileapi/file_system_url.h" 17#include "webkit/browser/fileapi/file_writer_delegate.h" 18#include "webkit/common/blob/shareable_file_reference.h" 19 20using fileapi::FileSystemURL; 21 22namespace sync_file_system { 23 24namespace { 25 26void WriteCallbackAdapter( 27 const SyncableFileSystemOperation::WriteCallback& callback, 28 base::File::Error status) { 29 callback.Run(status, 0, true); 30} 31 32} // namespace 33 34class SyncableFileSystemOperation::QueueableTask 35 : public SyncableFileOperationRunner::Task { 36 public: 37 QueueableTask(base::WeakPtr<SyncableFileSystemOperation> operation, 38 const base::Closure& task) 39 : operation_(operation), 40 task_(task), 41 target_paths_(operation->target_paths_) {} 42 43 virtual ~QueueableTask() { 44 DCHECK(!operation_); 45 } 46 47 virtual void Run() OVERRIDE { 48 if (!operation_) 49 return; 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::File::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 weak_factory_.GetWeakPtr(), 90 base::Bind(&FileSystemOperation::CreateFile, 91 base::Unretained(impl_.get()), 92 url, exclusive, 93 base::Bind(&self::DidFinish, weak_factory_.GetWeakPtr())))); 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::File::FILE_ERROR_NOT_FOUND); 105 return; 106 } 107 if (!is_directory_operation_enabled_) { 108 callback.Run(base::File::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 weak_factory_.GetWeakPtr(), 116 base::Bind(&FileSystemOperation::CreateDirectory, 117 base::Unretained(impl_.get()), 118 url, exclusive, recursive, 119 base::Bind(&self::DidFinish, weak_factory_.GetWeakPtr())))); 120 operation_runner_->PostOperationTask(task.Pass()); 121} 122 123void SyncableFileSystemOperation::Copy( 124 const FileSystemURL& src_url, 125 const FileSystemURL& dest_url, 126 CopyOrMoveOption option, 127 const CopyProgressCallback& progress_callback, 128 const StatusCallback& callback) { 129 DCHECK(CalledOnValidThread()); 130 if (!operation_runner_.get()) { 131 callback.Run(base::File::FILE_ERROR_NOT_FOUND); 132 return; 133 } 134 DCHECK(operation_runner_.get()); 135 target_paths_.push_back(dest_url); 136 completion_callback_ = callback; 137 scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask( 138 weak_factory_.GetWeakPtr(), 139 base::Bind(&FileSystemOperation::Copy, 140 base::Unretained(impl_.get()), 141 src_url, dest_url, option, progress_callback, 142 base::Bind(&self::DidFinish, weak_factory_.GetWeakPtr())))); 143 operation_runner_->PostOperationTask(task.Pass()); 144} 145 146void SyncableFileSystemOperation::Move( 147 const FileSystemURL& src_url, 148 const FileSystemURL& dest_url, 149 CopyOrMoveOption option, 150 const StatusCallback& callback) { 151 DCHECK(CalledOnValidThread()); 152 if (!operation_runner_.get()) { 153 callback.Run(base::File::FILE_ERROR_NOT_FOUND); 154 return; 155 } 156 DCHECK(operation_runner_.get()); 157 target_paths_.push_back(src_url); 158 target_paths_.push_back(dest_url); 159 completion_callback_ = callback; 160 scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask( 161 weak_factory_.GetWeakPtr(), 162 base::Bind(&FileSystemOperation::Move, 163 base::Unretained(impl_.get()), 164 src_url, dest_url, option, 165 base::Bind(&self::DidFinish, weak_factory_.GetWeakPtr())))); 166 operation_runner_->PostOperationTask(task.Pass()); 167} 168 169void SyncableFileSystemOperation::DirectoryExists( 170 const FileSystemURL& url, 171 const StatusCallback& callback) { 172 DCHECK(CalledOnValidThread()); 173 impl_->DirectoryExists(url, callback); 174} 175 176void SyncableFileSystemOperation::FileExists( 177 const FileSystemURL& url, 178 const StatusCallback& callback) { 179 DCHECK(CalledOnValidThread()); 180 impl_->FileExists(url, callback); 181} 182 183void SyncableFileSystemOperation::GetMetadata( 184 const FileSystemURL& url, 185 const GetMetadataCallback& callback) { 186 DCHECK(CalledOnValidThread()); 187 impl_->GetMetadata(url, callback); 188} 189 190void SyncableFileSystemOperation::ReadDirectory( 191 const FileSystemURL& url, 192 const ReadDirectoryCallback& callback) { 193 DCHECK(CalledOnValidThread()); 194 // This is a read operation and there'd be no hard to let it go even if 195 // directory operation is disabled. (And we should allow this if it's made 196 // on the root directory) 197 impl_->ReadDirectory(url, callback); 198} 199 200void SyncableFileSystemOperation::Remove( 201 const FileSystemURL& url, bool recursive, 202 const StatusCallback& callback) { 203 DCHECK(CalledOnValidThread()); 204 if (!operation_runner_.get()) { 205 callback.Run(base::File::FILE_ERROR_NOT_FOUND); 206 return; 207 } 208 DCHECK(operation_runner_.get()); 209 target_paths_.push_back(url); 210 completion_callback_ = callback; 211 scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask( 212 weak_factory_.GetWeakPtr(), 213 base::Bind(&FileSystemOperation::Remove, 214 base::Unretained(impl_.get()), 215 url, recursive, 216 base::Bind(&self::DidFinish, weak_factory_.GetWeakPtr())))); 217 operation_runner_->PostOperationTask(task.Pass()); 218} 219 220void SyncableFileSystemOperation::Write( 221 const FileSystemURL& url, 222 scoped_ptr<fileapi::FileWriterDelegate> writer_delegate, 223 scoped_ptr<net::URLRequest> blob_request, 224 const WriteCallback& callback) { 225 DCHECK(CalledOnValidThread()); 226 if (!operation_runner_.get()) { 227 callback.Run(base::File::FILE_ERROR_NOT_FOUND, 0, true); 228 return; 229 } 230 DCHECK(operation_runner_.get()); 231 target_paths_.push_back(url); 232 completion_callback_ = base::Bind(&WriteCallbackAdapter, callback); 233 scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask( 234 weak_factory_.GetWeakPtr(), 235 base::Bind(&FileSystemOperation::Write, 236 base::Unretained(impl_.get()), 237 url, 238 base::Passed(&writer_delegate), 239 base::Passed(&blob_request), 240 base::Bind(&self::DidWrite, weak_factory_.GetWeakPtr(), 241 callback)))); 242 operation_runner_->PostOperationTask(task.Pass()); 243} 244 245void SyncableFileSystemOperation::Truncate( 246 const FileSystemURL& url, int64 length, 247 const StatusCallback& callback) { 248 DCHECK(CalledOnValidThread()); 249 if (!operation_runner_.get()) { 250 callback.Run(base::File::FILE_ERROR_NOT_FOUND); 251 return; 252 } 253 DCHECK(operation_runner_.get()); 254 target_paths_.push_back(url); 255 completion_callback_ = callback; 256 scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask( 257 weak_factory_.GetWeakPtr(), 258 base::Bind(&FileSystemOperation::Truncate, 259 base::Unretained(impl_.get()), 260 url, length, 261 base::Bind(&self::DidFinish, weak_factory_.GetWeakPtr())))); 262 operation_runner_->PostOperationTask(task.Pass()); 263} 264 265void SyncableFileSystemOperation::TouchFile( 266 const FileSystemURL& url, 267 const base::Time& last_access_time, 268 const base::Time& last_modified_time, 269 const StatusCallback& callback) { 270 DCHECK(CalledOnValidThread()); 271 impl_->TouchFile(url, last_access_time, last_modified_time, callback); 272} 273 274void SyncableFileSystemOperation::OpenFile( 275 const FileSystemURL& url, 276 int file_flags, 277 const OpenFileCallback& callback) { 278 NOTREACHED(); 279} 280 281void SyncableFileSystemOperation::Cancel( 282 const StatusCallback& cancel_callback) { 283 DCHECK(CalledOnValidThread()); 284 impl_->Cancel(cancel_callback); 285} 286 287void SyncableFileSystemOperation::CreateSnapshotFile( 288 const FileSystemURL& path, 289 const SnapshotFileCallback& callback) { 290 DCHECK(CalledOnValidThread()); 291 impl_->CreateSnapshotFile(path, callback); 292} 293 294void SyncableFileSystemOperation::CopyInForeignFile( 295 const base::FilePath& src_local_disk_path, 296 const FileSystemURL& dest_url, 297 const StatusCallback& callback) { 298 DCHECK(CalledOnValidThread()); 299 if (!operation_runner_.get()) { 300 callback.Run(base::File::FILE_ERROR_NOT_FOUND); 301 return; 302 } 303 DCHECK(operation_runner_.get()); 304 target_paths_.push_back(dest_url); 305 completion_callback_ = callback; 306 scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask( 307 weak_factory_.GetWeakPtr(), 308 base::Bind(&FileSystemOperation::CopyInForeignFile, 309 base::Unretained(impl_.get()), 310 src_local_disk_path, dest_url, 311 base::Bind(&self::DidFinish, weak_factory_.GetWeakPtr())))); 312 operation_runner_->PostOperationTask(task.Pass()); 313} 314 315void SyncableFileSystemOperation::RemoveFile( 316 const FileSystemURL& url, 317 const StatusCallback& callback) { 318 DCHECK(CalledOnValidThread()); 319 impl_->RemoveFile(url, callback); 320} 321 322void SyncableFileSystemOperation::RemoveDirectory( 323 const FileSystemURL& url, 324 const StatusCallback& callback) { 325 DCHECK(CalledOnValidThread()); 326 impl_->RemoveDirectory(url, callback); 327} 328 329void SyncableFileSystemOperation::CopyFileLocal( 330 const FileSystemURL& src_url, 331 const FileSystemURL& dest_url, 332 CopyOrMoveOption option, 333 const CopyFileProgressCallback& progress_callback, 334 const StatusCallback& callback) { 335 DCHECK(CalledOnValidThread()); 336 impl_->CopyFileLocal(src_url, dest_url, option, progress_callback, callback); 337} 338 339void SyncableFileSystemOperation::MoveFileLocal( 340 const FileSystemURL& src_url, 341 const FileSystemURL& dest_url, 342 CopyOrMoveOption option, 343 const StatusCallback& callback) { 344 DCHECK(CalledOnValidThread()); 345 impl_->MoveFileLocal(src_url, dest_url, option, callback); 346} 347 348base::File::Error SyncableFileSystemOperation::SyncGetPlatformPath( 349 const FileSystemURL& url, 350 base::FilePath* platform_path) { 351 return impl_->SyncGetPlatformPath(url, platform_path); 352} 353 354SyncableFileSystemOperation::SyncableFileSystemOperation( 355 const FileSystemURL& url, 356 fileapi::FileSystemContext* file_system_context, 357 scoped_ptr<fileapi::FileSystemOperationContext> operation_context) 358 : url_(url), 359 weak_factory_(this) { 360 DCHECK(file_system_context); 361 SyncFileSystemBackend* backend = 362 SyncFileSystemBackend::GetBackend(file_system_context); 363 DCHECK(backend); 364 if (!backend->sync_context()) { 365 // Syncable FileSystem is opened in a file system context which doesn't 366 // support (or is not initialized for) the API. 367 // Returning here to leave operation_runner_ as NULL. 368 return; 369 } 370 impl_.reset(fileapi::FileSystemOperation::Create( 371 url_, file_system_context, operation_context.Pass())); 372 operation_runner_ = backend->sync_context()->operation_runner(); 373 is_directory_operation_enabled_ = IsSyncFSDirectoryOperationEnabled( 374 url.origin()); 375} 376 377void SyncableFileSystemOperation::DidFinish(base::File::Error status) { 378 DCHECK(CalledOnValidThread()); 379 DCHECK(!completion_callback_.is_null()); 380 if (operation_runner_.get()) 381 operation_runner_->OnOperationCompleted(target_paths_); 382 completion_callback_.Run(status); 383} 384 385void SyncableFileSystemOperation::DidWrite( 386 const WriteCallback& callback, 387 base::File::Error result, 388 int64 bytes, 389 bool complete) { 390 DCHECK(CalledOnValidThread()); 391 if (!complete) { 392 callback.Run(result, bytes, complete); 393 return; 394 } 395 if (operation_runner_.get()) 396 operation_runner_->OnOperationCompleted(target_paths_); 397 callback.Run(result, bytes, complete); 398} 399 400void SyncableFileSystemOperation::OnCancelled() { 401 DCHECK(!completion_callback_.is_null()); 402 completion_callback_.Run(base::File::FILE_ERROR_ABORT); 403} 404 405} // namespace sync_file_system 406