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 "webkit/browser/fileapi/file_system_operation_runner.h" 6 7 #include "base/bind.h" 8 #include "net/url_request/url_request_context.h" 9 #include "webkit/browser/fileapi/file_observers.h" 10 #include "webkit/browser/fileapi/file_stream_writer.h" 11 #include "webkit/browser/fileapi/file_system_context.h" 12 #include "webkit/browser/fileapi/file_system_operation_impl.h" 13 #include "webkit/browser/fileapi/file_writer_delegate.h" 14 #include "webkit/common/blob/shareable_file_reference.h" 15 16 namespace fileapi { 17 18 typedef FileSystemOperationRunner::OperationID OperationID; 19 20 const OperationID FileSystemOperationRunner::kErrorOperationID = -1; 21 22 FileSystemOperationRunner::~FileSystemOperationRunner() { 23 } 24 25 void FileSystemOperationRunner::Shutdown() { 26 operations_.Clear(); 27 } 28 29 OperationID FileSystemOperationRunner::CreateFile( 30 const FileSystemURL& url, 31 bool exclusive, 32 const StatusCallback& callback) { 33 base::PlatformFileError error = base::PLATFORM_FILE_OK; 34 FileSystemOperation* operation = 35 file_system_context_->CreateFileSystemOperation(url, &error); 36 if (!operation) { 37 callback.Run(error); 38 return kErrorOperationID; 39 } 40 OperationID id = operations_.Add(operation); 41 PrepareForWrite(id, url); 42 operation->CreateFile( 43 url, exclusive, 44 base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), 45 id, callback)); 46 return id; 47 } 48 49 OperationID FileSystemOperationRunner::CreateDirectory( 50 const FileSystemURL& url, 51 bool exclusive, 52 bool recursive, 53 const StatusCallback& callback) { 54 base::PlatformFileError error = base::PLATFORM_FILE_OK; 55 FileSystemOperation* operation = 56 file_system_context_->CreateFileSystemOperation(url, &error); 57 if (!operation) { 58 callback.Run(error); 59 return kErrorOperationID; 60 } 61 OperationID id = operations_.Add(operation); 62 PrepareForWrite(id, url); 63 operation->CreateDirectory( 64 url, exclusive, recursive, 65 base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), 66 id, callback)); 67 return id; 68 } 69 70 OperationID FileSystemOperationRunner::Copy( 71 const FileSystemURL& src_url, 72 const FileSystemURL& dest_url, 73 const StatusCallback& callback) { 74 base::PlatformFileError error = base::PLATFORM_FILE_OK; 75 FileSystemOperation* operation = 76 file_system_context_->CreateFileSystemOperation(dest_url, &error); 77 if (!operation) { 78 callback.Run(error); 79 return kErrorOperationID; 80 } 81 OperationID id = operations_.Add(operation); 82 PrepareForWrite(id, dest_url); 83 PrepareForRead(id, src_url); 84 operation->Copy( 85 src_url, dest_url, 86 base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), 87 id, callback)); 88 return id; 89 } 90 91 OperationID FileSystemOperationRunner::Move( 92 const FileSystemURL& src_url, 93 const FileSystemURL& dest_url, 94 const StatusCallback& callback) { 95 base::PlatformFileError error = base::PLATFORM_FILE_OK; 96 FileSystemOperation* operation = 97 file_system_context_->CreateFileSystemOperation(dest_url, &error); 98 if (!operation) { 99 callback.Run(error); 100 return kErrorOperationID; 101 } 102 OperationID id = operations_.Add(operation); 103 PrepareForWrite(id, dest_url); 104 PrepareForWrite(id, src_url); 105 operation->Move( 106 src_url, dest_url, 107 base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), 108 id, callback)); 109 return id; 110 } 111 112 OperationID FileSystemOperationRunner::DirectoryExists( 113 const FileSystemURL& url, 114 const StatusCallback& callback) { 115 base::PlatformFileError error = base::PLATFORM_FILE_OK; 116 FileSystemOperation* operation = 117 file_system_context_->CreateFileSystemOperation(url, &error); 118 if (!operation) { 119 callback.Run(error); 120 return kErrorOperationID; 121 } 122 OperationID id = operations_.Add(operation); 123 PrepareForRead(id, url); 124 operation->DirectoryExists( 125 url, 126 base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), 127 id, callback)); 128 return id; 129 } 130 131 OperationID FileSystemOperationRunner::FileExists( 132 const FileSystemURL& url, 133 const StatusCallback& callback) { 134 base::PlatformFileError error = base::PLATFORM_FILE_OK; 135 FileSystemOperation* operation = 136 file_system_context_->CreateFileSystemOperation(url, &error); 137 if (!operation) { 138 callback.Run(error); 139 return kErrorOperationID; 140 } 141 OperationID id = operations_.Add(operation); 142 PrepareForRead(id, url); 143 operation->FileExists( 144 url, 145 base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), 146 id, callback)); 147 return id; 148 } 149 150 OperationID FileSystemOperationRunner::GetMetadata( 151 const FileSystemURL& url, 152 const GetMetadataCallback& callback) { 153 base::PlatformFileError error = base::PLATFORM_FILE_OK; 154 FileSystemOperation* operation = 155 file_system_context_->CreateFileSystemOperation(url, &error); 156 if (!operation) { 157 callback.Run(error, base::PlatformFileInfo()); 158 return kErrorOperationID; 159 } 160 OperationID id = operations_.Add(operation); 161 PrepareForRead(id, url); 162 operation->GetMetadata( 163 url, 164 base::Bind(&FileSystemOperationRunner::DidGetMetadata, AsWeakPtr(), 165 id, callback)); 166 return id; 167 } 168 169 OperationID FileSystemOperationRunner::ReadDirectory( 170 const FileSystemURL& url, 171 const ReadDirectoryCallback& callback) { 172 base::PlatformFileError error = base::PLATFORM_FILE_OK; 173 FileSystemOperation* operation = 174 file_system_context_->CreateFileSystemOperation(url, &error); 175 if (!operation) { 176 callback.Run(error, std::vector<DirectoryEntry>(), false); 177 return kErrorOperationID; 178 } 179 OperationID id = operations_.Add(operation); 180 PrepareForRead(id, url); 181 operation->ReadDirectory( 182 url, 183 base::Bind(&FileSystemOperationRunner::DidReadDirectory, AsWeakPtr(), 184 id, callback)); 185 return id; 186 } 187 188 OperationID FileSystemOperationRunner::Remove( 189 const FileSystemURL& url, bool recursive, 190 const StatusCallback& callback) { 191 base::PlatformFileError error = base::PLATFORM_FILE_OK; 192 FileSystemOperation* operation = 193 file_system_context_->CreateFileSystemOperation(url, &error); 194 if (!operation) { 195 callback.Run(error); 196 return kErrorOperationID; 197 } 198 OperationID id = operations_.Add(operation); 199 PrepareForWrite(id, url); 200 operation->Remove( 201 url, recursive, 202 base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), 203 id, callback)); 204 return id; 205 } 206 207 OperationID FileSystemOperationRunner::Write( 208 const net::URLRequestContext* url_request_context, 209 const FileSystemURL& url, 210 const GURL& blob_url, 211 int64 offset, 212 const WriteCallback& callback) { 213 base::PlatformFileError error = base::PLATFORM_FILE_OK; 214 FileSystemOperation* operation = 215 file_system_context_->CreateFileSystemOperation(url, &error); 216 if (!operation) { 217 callback.Run(error, 0, true); 218 return kErrorOperationID; 219 } 220 221 scoped_ptr<FileStreamWriter> writer( 222 file_system_context_->CreateFileStreamWriter(url, offset)); 223 if (!writer) { 224 // Write is not supported. 225 callback.Run(base::PLATFORM_FILE_ERROR_SECURITY, 0, true); 226 return kErrorOperationID; 227 } 228 229 DCHECK(blob_url.is_valid()); 230 scoped_ptr<FileWriterDelegate> writer_delegate( 231 new FileWriterDelegate(writer.Pass())); 232 scoped_ptr<net::URLRequest> blob_request(url_request_context->CreateRequest( 233 blob_url, writer_delegate.get())); 234 235 OperationID id = operations_.Add(operation); 236 PrepareForWrite(id, url); 237 operation->Write( 238 url, writer_delegate.Pass(), blob_request.Pass(), 239 base::Bind(&FileSystemOperationRunner::DidWrite, AsWeakPtr(), 240 id, callback)); 241 return id; 242 } 243 244 OperationID FileSystemOperationRunner::Truncate( 245 const FileSystemURL& url, int64 length, 246 const StatusCallback& callback) { 247 base::PlatformFileError error = base::PLATFORM_FILE_OK; 248 FileSystemOperation* operation = 249 file_system_context_->CreateFileSystemOperation(url, &error); 250 if (!operation) { 251 callback.Run(error); 252 return kErrorOperationID; 253 } 254 OperationID id = operations_.Add(operation); 255 PrepareForWrite(id, url); 256 operation->Truncate( 257 url, length, 258 base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), 259 id, callback)); 260 return id; 261 } 262 263 void FileSystemOperationRunner::Cancel( 264 OperationID id, 265 const StatusCallback& callback) { 266 FileSystemOperation* operation = operations_.Lookup(id); 267 if (!operation) { 268 // The operation is already finished; report that we failed to stop it. 269 callback.Run(base::PLATFORM_FILE_ERROR_INVALID_OPERATION); 270 return; 271 } 272 operation->Cancel(callback); 273 } 274 275 OperationID FileSystemOperationRunner::TouchFile( 276 const FileSystemURL& url, 277 const base::Time& last_access_time, 278 const base::Time& last_modified_time, 279 const StatusCallback& callback) { 280 base::PlatformFileError error = base::PLATFORM_FILE_OK; 281 FileSystemOperation* operation = 282 file_system_context_->CreateFileSystemOperation(url, &error); 283 if (!operation) { 284 callback.Run(error); 285 return kErrorOperationID; 286 } 287 OperationID id = operations_.Add(operation); 288 PrepareForWrite(id, url); 289 operation->TouchFile( 290 url, last_access_time, last_modified_time, 291 base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), 292 id, callback)); 293 return id; 294 } 295 296 OperationID FileSystemOperationRunner::OpenFile( 297 const FileSystemURL& url, 298 int file_flags, 299 base::ProcessHandle peer_handle, 300 const OpenFileCallback& callback) { 301 base::PlatformFileError error = base::PLATFORM_FILE_OK; 302 FileSystemOperation* operation = 303 file_system_context_->CreateFileSystemOperation(url, &error); 304 if (!operation) { 305 callback.Run(error, base::kInvalidPlatformFileValue, 306 base::Closure(), base::ProcessHandle()); 307 return kErrorOperationID; 308 } 309 OperationID id = operations_.Add(operation); 310 if (file_flags & 311 (base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_OPEN_ALWAYS | 312 base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_OPEN_TRUNCATED | 313 base::PLATFORM_FILE_WRITE | base::PLATFORM_FILE_EXCLUSIVE_WRITE | 314 base::PLATFORM_FILE_DELETE_ON_CLOSE | 315 base::PLATFORM_FILE_WRITE_ATTRIBUTES)) { 316 PrepareForWrite(id, url); 317 } else { 318 PrepareForRead(id, url); 319 } 320 operation->OpenFile( 321 url, file_flags, peer_handle, 322 base::Bind(&FileSystemOperationRunner::DidOpenFile, AsWeakPtr(), 323 id, callback)); 324 return id; 325 } 326 327 OperationID FileSystemOperationRunner::CreateSnapshotFile( 328 const FileSystemURL& url, 329 const SnapshotFileCallback& callback) { 330 base::PlatformFileError error = base::PLATFORM_FILE_OK; 331 FileSystemOperation* operation = 332 file_system_context_->CreateFileSystemOperation(url, &error); 333 if (!operation) { 334 callback.Run(error, base::PlatformFileInfo(), base::FilePath(), NULL); 335 return kErrorOperationID; 336 } 337 OperationID id = operations_.Add(operation); 338 PrepareForRead(id, url); 339 operation->CreateSnapshotFile( 340 url, 341 base::Bind(&FileSystemOperationRunner::DidCreateSnapshot, AsWeakPtr(), 342 id, callback)); 343 return id; 344 } 345 346 OperationID FileSystemOperationRunner::CopyInForeignFile( 347 const base::FilePath& src_local_disk_path, 348 const FileSystemURL& dest_url, 349 const StatusCallback& callback) { 350 base::PlatformFileError error = base::PLATFORM_FILE_OK; 351 FileSystemOperation* operation = CreateFileSystemOperationImpl( 352 dest_url, &error); 353 if (!operation) { 354 callback.Run(error); 355 return kErrorOperationID; 356 } 357 OperationID id = operations_.Add(operation); 358 operation->AsFileSystemOperationImpl()->CopyInForeignFile( 359 src_local_disk_path, dest_url, 360 base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), 361 id, callback)); 362 return id; 363 } 364 365 OperationID FileSystemOperationRunner::RemoveFile( 366 const FileSystemURL& url, 367 const StatusCallback& callback) { 368 base::PlatformFileError error = base::PLATFORM_FILE_OK; 369 FileSystemOperation* operation = CreateFileSystemOperationImpl(url, &error); 370 if (!operation) { 371 callback.Run(error); 372 return kErrorOperationID; 373 } 374 OperationID id = operations_.Add(operation); 375 operation->AsFileSystemOperationImpl()->RemoveFile( 376 url, 377 base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), 378 id, callback)); 379 return id; 380 } 381 382 OperationID FileSystemOperationRunner::RemoveDirectory( 383 const FileSystemURL& url, 384 const StatusCallback& callback) { 385 base::PlatformFileError error = base::PLATFORM_FILE_OK; 386 FileSystemOperation* operation = CreateFileSystemOperationImpl(url, &error); 387 if (!operation) { 388 callback.Run(error); 389 return kErrorOperationID; 390 } 391 OperationID id = operations_.Add(operation); 392 operation->AsFileSystemOperationImpl()->RemoveDirectory( 393 url, 394 base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), 395 id, callback)); 396 return id; 397 } 398 399 OperationID FileSystemOperationRunner::CopyFileLocal( 400 const FileSystemURL& src_url, 401 const FileSystemURL& dest_url, 402 const StatusCallback& callback) { 403 base::PlatformFileError error = base::PLATFORM_FILE_OK; 404 FileSystemOperation* operation = CreateFileSystemOperationImpl( 405 src_url, &error); 406 if (!operation) { 407 callback.Run(error); 408 return kErrorOperationID; 409 } 410 OperationID id = operations_.Add(operation); 411 operation->AsFileSystemOperationImpl()->CopyFileLocal( 412 src_url, dest_url, 413 base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), 414 id, callback)); 415 return id; 416 } 417 418 OperationID FileSystemOperationRunner::MoveFileLocal( 419 const FileSystemURL& src_url, 420 const FileSystemURL& dest_url, 421 const StatusCallback& callback) { 422 base::PlatformFileError error = base::PLATFORM_FILE_OK; 423 FileSystemOperation* operation = CreateFileSystemOperationImpl( 424 src_url, &error); 425 if (!operation) { 426 callback.Run(error); 427 return kErrorOperationID; 428 } 429 OperationID id = operations_.Add(operation); 430 operation->AsFileSystemOperationImpl()->MoveFileLocal( 431 src_url, dest_url, 432 base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), 433 id, callback)); 434 return id; 435 } 436 437 base::PlatformFileError FileSystemOperationRunner::SyncGetPlatformPath( 438 const FileSystemURL& url, 439 base::FilePath* platform_path) { 440 base::PlatformFileError error = base::PLATFORM_FILE_OK; 441 FileSystemOperation* operation = CreateFileSystemOperationImpl(url, &error); 442 if (!operation) 443 return error; 444 445 return operation->AsFileSystemOperationImpl()->SyncGetPlatformPath( 446 url, platform_path); 447 } 448 449 FileSystemOperationRunner::FileSystemOperationRunner( 450 FileSystemContext* file_system_context) 451 : file_system_context_(file_system_context) {} 452 453 void FileSystemOperationRunner::DidFinish( 454 OperationID id, 455 const StatusCallback& callback, 456 base::PlatformFileError rv) { 457 callback.Run(rv); 458 FinishOperation(id); 459 } 460 461 void FileSystemOperationRunner::DidGetMetadata( 462 OperationID id, 463 const GetMetadataCallback& callback, 464 base::PlatformFileError rv, 465 const base::PlatformFileInfo& file_info) { 466 callback.Run(rv, file_info); 467 FinishOperation(id); 468 } 469 470 void FileSystemOperationRunner::DidReadDirectory( 471 OperationID id, 472 const ReadDirectoryCallback& callback, 473 base::PlatformFileError rv, 474 const std::vector<DirectoryEntry>& entries, 475 bool has_more) { 476 callback.Run(rv, entries, has_more); 477 if (rv != base::PLATFORM_FILE_OK || !has_more) 478 FinishOperation(id); 479 } 480 481 void FileSystemOperationRunner::DidWrite( 482 OperationID id, 483 const WriteCallback& callback, 484 base::PlatformFileError rv, 485 int64 bytes, 486 bool complete) { 487 callback.Run(rv, bytes, complete); 488 if (rv != base::PLATFORM_FILE_OK || complete) 489 FinishOperation(id); 490 } 491 492 void FileSystemOperationRunner::DidOpenFile( 493 OperationID id, 494 const OpenFileCallback& callback, 495 base::PlatformFileError rv, 496 base::PlatformFile file, 497 const base::Closure& on_close_callback, 498 base::ProcessHandle peer_handle) { 499 callback.Run(rv, file, on_close_callback, peer_handle); 500 FinishOperation(id); 501 } 502 503 void FileSystemOperationRunner::DidCreateSnapshot( 504 OperationID id, 505 const SnapshotFileCallback& callback, 506 base::PlatformFileError rv, 507 const base::PlatformFileInfo& file_info, 508 const base::FilePath& platform_path, 509 const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref) { 510 callback.Run(rv, file_info, platform_path, file_ref); 511 FinishOperation(id); 512 } 513 514 FileSystemOperation* 515 FileSystemOperationRunner::CreateFileSystemOperationImpl( 516 const FileSystemURL& url, base::PlatformFileError* error) { 517 FileSystemOperation* operation = 518 file_system_context_->CreateFileSystemOperation(url, error); 519 if (!operation) 520 return NULL; 521 if (!operation->AsFileSystemOperationImpl()) { 522 *error = base::PLATFORM_FILE_ERROR_INVALID_OPERATION; 523 delete operation; 524 return NULL; 525 } 526 return operation; 527 } 528 529 void FileSystemOperationRunner::PrepareForWrite(OperationID id, 530 const FileSystemURL& url) { 531 if (file_system_context_->GetUpdateObservers(url.type())) { 532 file_system_context_->GetUpdateObservers(url.type())->Notify( 533 &FileUpdateObserver::OnStartUpdate, MakeTuple(url)); 534 } 535 write_target_urls_[id].insert(url); 536 } 537 538 void FileSystemOperationRunner::PrepareForRead(OperationID id, 539 const FileSystemURL& url) { 540 if (file_system_context_->GetAccessObservers(url.type())) { 541 file_system_context_->GetAccessObservers(url.type())->Notify( 542 &FileAccessObserver::OnAccess, MakeTuple(url)); 543 } 544 } 545 546 void FileSystemOperationRunner::FinishOperation(OperationID id) { 547 OperationToURLSet::iterator found = write_target_urls_.find(id); 548 if (found != write_target_urls_.end()) { 549 const FileSystemURLSet& urls = found->second; 550 for (FileSystemURLSet::const_iterator iter = urls.begin(); 551 iter != urls.end(); ++iter) { 552 if (file_system_context_->GetUpdateObservers(iter->type())) { 553 file_system_context_->GetUpdateObservers(iter->type())->Notify( 554 &FileUpdateObserver::OnEndUpdate, MakeTuple(*iter)); 555 } 556 } 557 write_target_urls_.erase(found); 558 } 559 DCHECK(operations_.Lookup(id)); 560 operations_.Remove(id); 561 } 562 563 } // namespace fileapi 564