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