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