1 // Copyright (c) 2011 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 "base/file_util_proxy.h" 6 7 #include "base/message_loop_proxy.h" 8 9 // TODO(jianli): Move the code from anonymous namespace to base namespace so 10 // that all of the base:: prefixes would be unnecessary. 11 namespace { 12 13 namespace { 14 15 // Performs common checks for move and copy. 16 // This also removes the destination directory if it's non-empty and all other 17 // checks are passed (so that the copy/move correctly overwrites the 18 // destination). PerformCommonCheckAndPreparationForMoveAndCopy(const FilePath & src_file_path,const FilePath & dest_file_path)19 static base::PlatformFileError PerformCommonCheckAndPreparationForMoveAndCopy( 20 const FilePath& src_file_path, 21 const FilePath& dest_file_path) { 22 // Exits earlier if the source path does not exist. 23 if (!file_util::PathExists(src_file_path)) 24 return base::PLATFORM_FILE_ERROR_NOT_FOUND; 25 26 // The parent of the |dest_file_path| does not exist. 27 if (!file_util::DirectoryExists(dest_file_path.DirName())) 28 return base::PLATFORM_FILE_ERROR_NOT_FOUND; 29 30 // It is an error to try to copy/move an entry into its child. 31 if (src_file_path.IsParent(dest_file_path)) 32 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; 33 34 // Now it is ok to return if the |dest_file_path| does not exist. 35 if (!file_util::PathExists(dest_file_path)) 36 return base::PLATFORM_FILE_OK; 37 38 // |src_file_path| exists and is a directory. 39 // |dest_file_path| exists and is a file. 40 bool src_is_directory = file_util::DirectoryExists(src_file_path); 41 bool dest_is_directory = file_util::DirectoryExists(dest_file_path); 42 if (src_is_directory && !dest_is_directory) 43 return base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY; 44 45 // |src_file_path| exists and is a file. 46 // |dest_file_path| exists and is a directory. 47 if (!src_is_directory && dest_is_directory) 48 return base::PLATFORM_FILE_ERROR_NOT_A_FILE; 49 50 // It is an error to copy/move an entry into the same path. 51 if (src_file_path.value() == dest_file_path.value()) 52 return base::PLATFORM_FILE_ERROR_EXISTS; 53 54 if (dest_is_directory) { 55 // It is an error to copy/move an entry to a non-empty directory. 56 // Otherwise the copy/move attempt must overwrite the destination, but 57 // the file_util's Copy or Move method doesn't perform overwrite 58 // on all platforms, so we delete the destination directory here. 59 // TODO(kinuko): may be better to change the file_util::{Copy,Move}. 60 if (!file_util::Delete(dest_file_path, false /* recursive */)) { 61 if (!file_util::IsDirectoryEmpty(dest_file_path)) 62 return base::PLATFORM_FILE_ERROR_NOT_EMPTY; 63 return base::PLATFORM_FILE_ERROR_FAILED; 64 } 65 } 66 return base::PLATFORM_FILE_OK; 67 } 68 69 } // anonymous namespace 70 71 class MessageLoopRelay 72 : public base::RefCountedThreadSafe<MessageLoopRelay> { 73 public: MessageLoopRelay()74 MessageLoopRelay() 75 : origin_message_loop_proxy_( 76 base::MessageLoopProxy::CreateForCurrentThread()), 77 error_code_(base::PLATFORM_FILE_OK) { 78 } 79 Start(scoped_refptr<base::MessageLoopProxy> message_loop_proxy,const tracked_objects::Location & from_here)80 bool Start(scoped_refptr<base::MessageLoopProxy> message_loop_proxy, 81 const tracked_objects::Location& from_here) { 82 return message_loop_proxy->PostTask( 83 from_here, 84 NewRunnableMethod(this, &MessageLoopRelay::ProcessOnTargetThread)); 85 } 86 87 protected: 88 friend class base::RefCountedThreadSafe<MessageLoopRelay>; ~MessageLoopRelay()89 virtual ~MessageLoopRelay() {} 90 91 // Called to perform work on the FILE thread. 92 virtual void RunWork() = 0; 93 94 // Called to notify the callback on the origin thread. 95 virtual void RunCallback() = 0; 96 set_error_code(base::PlatformFileError error_code)97 void set_error_code(base::PlatformFileError error_code) { 98 error_code_ = error_code; 99 } 100 error_code() const101 base::PlatformFileError error_code() const { 102 return error_code_; 103 } 104 105 private: ProcessOnTargetThread()106 void ProcessOnTargetThread() { 107 RunWork(); 108 origin_message_loop_proxy_->PostTask( 109 FROM_HERE, 110 NewRunnableMethod(this, &MessageLoopRelay::RunCallback)); 111 } 112 113 scoped_refptr<base::MessageLoopProxy> origin_message_loop_proxy_; 114 base::PlatformFileError error_code_; 115 }; 116 117 class RelayCreateOrOpen : public MessageLoopRelay { 118 public: RelayCreateOrOpen(scoped_refptr<base::MessageLoopProxy> message_loop_proxy,const FilePath & file_path,int file_flags,base::FileUtilProxy::CreateOrOpenCallback * callback)119 RelayCreateOrOpen( 120 scoped_refptr<base::MessageLoopProxy> message_loop_proxy, 121 const FilePath& file_path, 122 int file_flags, 123 base::FileUtilProxy::CreateOrOpenCallback* callback) 124 : message_loop_proxy_(message_loop_proxy), 125 file_path_(file_path), 126 file_flags_(file_flags), 127 callback_(callback), 128 file_handle_(base::kInvalidPlatformFileValue), 129 created_(false) { 130 DCHECK(callback); 131 } 132 133 protected: ~RelayCreateOrOpen()134 virtual ~RelayCreateOrOpen() { 135 if (file_handle_ != base::kInvalidPlatformFileValue) 136 base::FileUtilProxy::Close(message_loop_proxy_, file_handle_, NULL); 137 } 138 RunWork()139 virtual void RunWork() { 140 if (!file_util::DirectoryExists(file_path_.DirName())) { 141 // If its parent does not exist, should return NOT_FOUND error. 142 set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND); 143 return; 144 } 145 base::PlatformFileError error_code = base::PLATFORM_FILE_OK; 146 file_handle_ = base::CreatePlatformFile(file_path_, file_flags_, 147 &created_, &error_code); 148 set_error_code(error_code); 149 } 150 RunCallback()151 virtual void RunCallback() { 152 callback_->Run(error_code(), base::PassPlatformFile(&file_handle_), 153 created_); 154 delete callback_; 155 } 156 157 private: 158 scoped_refptr<base::MessageLoopProxy> message_loop_proxy_; 159 FilePath file_path_; 160 int file_flags_; 161 base::FileUtilProxy::CreateOrOpenCallback* callback_; 162 base::PlatformFile file_handle_; 163 bool created_; 164 }; 165 166 class RelayCreateTemporary : public MessageLoopRelay { 167 public: RelayCreateTemporary(scoped_refptr<base::MessageLoopProxy> message_loop_proxy,base::FileUtilProxy::CreateTemporaryCallback * callback)168 RelayCreateTemporary( 169 scoped_refptr<base::MessageLoopProxy> message_loop_proxy, 170 base::FileUtilProxy::CreateTemporaryCallback* callback) 171 : message_loop_proxy_(message_loop_proxy), 172 callback_(callback), 173 file_handle_(base::kInvalidPlatformFileValue) { 174 DCHECK(callback); 175 } 176 177 protected: ~RelayCreateTemporary()178 virtual ~RelayCreateTemporary() { 179 if (file_handle_ != base::kInvalidPlatformFileValue) 180 base::FileUtilProxy::Close(message_loop_proxy_, file_handle_, NULL); 181 } 182 RunWork()183 virtual void RunWork() { 184 // TODO(darin): file_util should have a variant of CreateTemporaryFile 185 // that returns a FilePath and a PlatformFile. 186 file_util::CreateTemporaryFile(&file_path_); 187 188 // Use a fixed set of flags that are appropriate for writing to a temporary 189 // file from the IO thread using a net::FileStream. 190 int file_flags = 191 base::PLATFORM_FILE_CREATE_ALWAYS | 192 base::PLATFORM_FILE_WRITE | 193 base::PLATFORM_FILE_ASYNC | 194 base::PLATFORM_FILE_TEMPORARY; 195 base::PlatformFileError error_code = base::PLATFORM_FILE_OK; 196 file_handle_ = base::CreatePlatformFile(file_path_, file_flags, 197 NULL, &error_code); 198 set_error_code(error_code); 199 } 200 RunCallback()201 virtual void RunCallback() { 202 callback_->Run(error_code(), base::PassPlatformFile(&file_handle_), 203 file_path_); 204 delete callback_; 205 } 206 207 private: 208 scoped_refptr<base::MessageLoopProxy> message_loop_proxy_; 209 base::FileUtilProxy::CreateTemporaryCallback* callback_; 210 base::PlatformFile file_handle_; 211 FilePath file_path_; 212 }; 213 214 class RelayWithStatusCallback : public MessageLoopRelay { 215 public: RelayWithStatusCallback(base::FileUtilProxy::StatusCallback * callback)216 explicit RelayWithStatusCallback( 217 base::FileUtilProxy::StatusCallback* callback) 218 : callback_(callback) { 219 // It is OK for callback to be NULL. 220 } 221 222 protected: RunCallback()223 virtual void RunCallback() { 224 // The caller may not have been interested in the result. 225 if (callback_) { 226 callback_->Run(error_code()); 227 delete callback_; 228 } 229 } 230 231 private: 232 base::FileUtilProxy::StatusCallback* callback_; 233 }; 234 235 class RelayClose : public RelayWithStatusCallback { 236 public: RelayClose(base::PlatformFile file_handle,base::FileUtilProxy::StatusCallback * callback)237 RelayClose(base::PlatformFile file_handle, 238 base::FileUtilProxy::StatusCallback* callback) 239 : RelayWithStatusCallback(callback), 240 file_handle_(file_handle) { 241 } 242 243 protected: RunWork()244 virtual void RunWork() { 245 if (!base::ClosePlatformFile(file_handle_)) 246 set_error_code(base::PLATFORM_FILE_ERROR_FAILED); 247 } 248 249 private: 250 base::PlatformFile file_handle_; 251 }; 252 253 class RelayEnsureFileExists : public MessageLoopRelay { 254 public: RelayEnsureFileExists(scoped_refptr<base::MessageLoopProxy> message_loop_proxy,const FilePath & file_path,base::FileUtilProxy::EnsureFileExistsCallback * callback)255 RelayEnsureFileExists( 256 scoped_refptr<base::MessageLoopProxy> message_loop_proxy, 257 const FilePath& file_path, 258 base::FileUtilProxy::EnsureFileExistsCallback* callback) 259 : message_loop_proxy_(message_loop_proxy), 260 file_path_(file_path), 261 callback_(callback), 262 created_(false) { 263 DCHECK(callback); 264 } 265 266 protected: RunWork()267 virtual void RunWork() { 268 if (!file_util::DirectoryExists(file_path_.DirName())) { 269 // If its parent does not exist, should return NOT_FOUND error. 270 set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND); 271 return; 272 } 273 base::PlatformFileError error_code = base::PLATFORM_FILE_OK; 274 // Tries to create the |file_path_| exclusively. This should fail 275 // with PLATFORM_FILE_ERROR_EXISTS if the path already exists. 276 base::PlatformFile handle = base::CreatePlatformFile( 277 file_path_, 278 base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_READ, 279 &created_, &error_code); 280 if (error_code == base::PLATFORM_FILE_ERROR_EXISTS) { 281 // Make sure created_ is false. 282 created_ = false; 283 error_code = base::PLATFORM_FILE_OK; 284 } 285 if (handle != base::kInvalidPlatformFileValue) 286 base::ClosePlatformFile(handle); 287 set_error_code(error_code); 288 } 289 RunCallback()290 virtual void RunCallback() { 291 callback_->Run(error_code(), created_); 292 delete callback_; 293 } 294 295 private: 296 scoped_refptr<base::MessageLoopProxy> message_loop_proxy_; 297 FilePath file_path_; 298 base::FileUtilProxy::EnsureFileExistsCallback* callback_; 299 bool created_; 300 }; 301 302 class RelayDelete : public RelayWithStatusCallback { 303 public: RelayDelete(const FilePath & file_path,bool recursive,base::FileUtilProxy::StatusCallback * callback)304 RelayDelete(const FilePath& file_path, 305 bool recursive, 306 base::FileUtilProxy::StatusCallback* callback) 307 : RelayWithStatusCallback(callback), 308 file_path_(file_path), 309 recursive_(recursive) { 310 } 311 312 protected: RunWork()313 virtual void RunWork() { 314 if (!file_util::PathExists(file_path_)) { 315 set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND); 316 return; 317 } 318 if (!file_util::Delete(file_path_, recursive_)) { 319 if (!recursive_ && !file_util::IsDirectoryEmpty(file_path_)) { 320 set_error_code(base::PLATFORM_FILE_ERROR_NOT_EMPTY); 321 return; 322 } 323 set_error_code(base::PLATFORM_FILE_ERROR_FAILED); 324 } 325 } 326 327 private: 328 FilePath file_path_; 329 bool recursive_; 330 }; 331 332 class RelayCopy : public RelayWithStatusCallback { 333 public: RelayCopy(const FilePath & src_file_path,const FilePath & dest_file_path,base::FileUtilProxy::StatusCallback * callback)334 RelayCopy(const FilePath& src_file_path, 335 const FilePath& dest_file_path, 336 base::FileUtilProxy::StatusCallback* callback) 337 : RelayWithStatusCallback(callback), 338 src_file_path_(src_file_path), 339 dest_file_path_(dest_file_path) { 340 } 341 342 protected: RunWork()343 virtual void RunWork() { 344 set_error_code(PerformCommonCheckAndPreparationForMoveAndCopy( 345 src_file_path_, dest_file_path_)); 346 if (error_code() != base::PLATFORM_FILE_OK) 347 return; 348 if (!file_util::CopyDirectory(src_file_path_, dest_file_path_, 349 true /* recursive */)) 350 set_error_code(base::PLATFORM_FILE_ERROR_FAILED); 351 } 352 353 private: 354 FilePath src_file_path_; 355 FilePath dest_file_path_; 356 }; 357 358 class RelayMove : public RelayWithStatusCallback { 359 public: RelayMove(const FilePath & src_file_path,const FilePath & dest_file_path,base::FileUtilProxy::StatusCallback * callback)360 RelayMove(const FilePath& src_file_path, 361 const FilePath& dest_file_path, 362 base::FileUtilProxy::StatusCallback* callback) 363 : RelayWithStatusCallback(callback), 364 src_file_path_(src_file_path), 365 dest_file_path_(dest_file_path) { 366 } 367 368 protected: RunWork()369 virtual void RunWork() { 370 set_error_code(PerformCommonCheckAndPreparationForMoveAndCopy( 371 src_file_path_, dest_file_path_)); 372 if (error_code() != base::PLATFORM_FILE_OK) 373 return; 374 if (!file_util::Move(src_file_path_, dest_file_path_)) 375 set_error_code(base::PLATFORM_FILE_ERROR_FAILED); 376 } 377 378 private: 379 FilePath src_file_path_; 380 FilePath dest_file_path_; 381 }; 382 383 class RelayCreateDirectory : public RelayWithStatusCallback { 384 public: RelayCreateDirectory(const FilePath & file_path,bool exclusive,bool recursive,base::FileUtilProxy::StatusCallback * callback)385 RelayCreateDirectory( 386 const FilePath& file_path, 387 bool exclusive, 388 bool recursive, 389 base::FileUtilProxy::StatusCallback* callback) 390 : RelayWithStatusCallback(callback), 391 file_path_(file_path), 392 exclusive_(exclusive), 393 recursive_(recursive) { 394 } 395 396 protected: RunWork()397 virtual void RunWork() { 398 bool path_exists = file_util::PathExists(file_path_); 399 // If parent dir of file doesn't exist. 400 if (!recursive_ && !file_util::PathExists(file_path_.DirName())) { 401 set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND); 402 return; 403 } 404 if (exclusive_ && path_exists) { 405 set_error_code(base::PLATFORM_FILE_ERROR_EXISTS); 406 return; 407 } 408 // If file exists at the path. 409 if (path_exists && !file_util::DirectoryExists(file_path_)) { 410 set_error_code(base::PLATFORM_FILE_ERROR_EXISTS); 411 return; 412 } 413 if (!file_util::CreateDirectory(file_path_)) 414 set_error_code(base::PLATFORM_FILE_ERROR_FAILED); 415 } 416 417 private: 418 FilePath file_path_; 419 bool exclusive_; 420 bool recursive_; 421 }; 422 423 class RelayReadDirectory : public MessageLoopRelay { 424 public: RelayReadDirectory(const FilePath & file_path,base::FileUtilProxy::ReadDirectoryCallback * callback)425 RelayReadDirectory(const FilePath& file_path, 426 base::FileUtilProxy::ReadDirectoryCallback* callback) 427 : callback_(callback), file_path_(file_path) { 428 DCHECK(callback); 429 } 430 431 protected: RunWork()432 virtual void RunWork() { 433 // TODO(kkanetkar): Implement directory read in multiple chunks. 434 if (!file_util::DirectoryExists(file_path_)) { 435 set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND); 436 return; 437 } 438 439 file_util::FileEnumerator file_enum( 440 file_path_, false, static_cast<file_util::FileEnumerator::FILE_TYPE>( 441 file_util::FileEnumerator::FILES | 442 file_util::FileEnumerator::DIRECTORIES)); 443 FilePath current; 444 while (!(current = file_enum.Next()).empty()) { 445 base::FileUtilProxy::Entry entry; 446 file_util::FileEnumerator::FindInfo info; 447 file_enum.GetFindInfo(&info); 448 entry.is_directory = file_enum.IsDirectory(info); 449 // This will just give the entry's name instead of entire path 450 // if we use current.value(). 451 entry.name = file_util::FileEnumerator::GetFilename(info).value(); 452 entries_.push_back(entry); 453 } 454 } 455 RunCallback()456 virtual void RunCallback() { 457 callback_->Run(error_code(), entries_); 458 delete callback_; 459 } 460 461 private: 462 base::FileUtilProxy::ReadDirectoryCallback* callback_; 463 FilePath file_path_; 464 std::vector<base::FileUtilProxy::Entry> entries_; 465 }; 466 467 class RelayGetFileInfo : public MessageLoopRelay { 468 public: RelayGetFileInfo(const FilePath & file_path,base::FileUtilProxy::GetFileInfoCallback * callback)469 RelayGetFileInfo(const FilePath& file_path, 470 base::FileUtilProxy::GetFileInfoCallback* callback) 471 : callback_(callback), 472 file_path_(file_path) { 473 DCHECK(callback); 474 } 475 476 protected: RunWork()477 virtual void RunWork() { 478 if (!file_util::PathExists(file_path_)) { 479 set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND); 480 return; 481 } 482 if (!file_util::GetFileInfo(file_path_, &file_info_)) 483 set_error_code(base::PLATFORM_FILE_ERROR_FAILED); 484 } 485 RunCallback()486 virtual void RunCallback() { 487 callback_->Run(error_code(), file_info_); 488 delete callback_; 489 } 490 491 private: 492 base::FileUtilProxy::GetFileInfoCallback* callback_; 493 FilePath file_path_; 494 base::PlatformFileInfo file_info_; 495 }; 496 497 class RelayGetFileInfoFromPlatformFile : public MessageLoopRelay { 498 public: RelayGetFileInfoFromPlatformFile(base::PlatformFile file,base::FileUtilProxy::GetFileInfoCallback * callback)499 RelayGetFileInfoFromPlatformFile( 500 base::PlatformFile file, 501 base::FileUtilProxy::GetFileInfoCallback* callback) 502 : callback_(callback), 503 file_(file) { 504 DCHECK(callback); 505 } 506 507 protected: RunWork()508 virtual void RunWork() { 509 if (!base::GetPlatformFileInfo(file_, &file_info_)) 510 set_error_code(base::PLATFORM_FILE_ERROR_FAILED); 511 } 512 RunCallback()513 virtual void RunCallback() { 514 callback_->Run(error_code(), file_info_); 515 delete callback_; 516 } 517 518 private: 519 base::FileUtilProxy::GetFileInfoCallback* callback_; 520 base::PlatformFile file_; 521 base::PlatformFileInfo file_info_; 522 }; 523 524 class RelayRead : public MessageLoopRelay { 525 public: RelayRead(base::PlatformFile file,int64 offset,int bytes_to_read,base::FileUtilProxy::ReadCallback * callback)526 RelayRead(base::PlatformFile file, 527 int64 offset, 528 int bytes_to_read, 529 base::FileUtilProxy::ReadCallback* callback) 530 : file_(file), 531 offset_(offset), 532 buffer_(new char[bytes_to_read]), 533 bytes_to_read_(bytes_to_read), 534 callback_(callback), 535 bytes_read_(0) { 536 } 537 538 protected: RunWork()539 virtual void RunWork() { 540 bytes_read_ = base::ReadPlatformFile(file_, offset_, buffer_.get(), 541 bytes_to_read_); 542 if (bytes_read_ < 0) 543 set_error_code(base::PLATFORM_FILE_ERROR_FAILED); 544 } 545 RunCallback()546 virtual void RunCallback() { 547 if (callback_) { 548 callback_->Run(error_code(), buffer_.get(), bytes_read_); 549 delete callback_; 550 } 551 } 552 553 private: 554 base::PlatformFile file_; 555 int64 offset_; 556 scoped_array<char> buffer_; 557 int bytes_to_read_; 558 base::FileUtilProxy::ReadCallback* callback_; 559 int bytes_read_; 560 }; 561 562 class RelayWrite : public MessageLoopRelay { 563 public: RelayWrite(base::PlatformFile file,int64 offset,const char * buffer,int bytes_to_write,base::FileUtilProxy::WriteCallback * callback)564 RelayWrite(base::PlatformFile file, 565 int64 offset, 566 const char* buffer, 567 int bytes_to_write, 568 base::FileUtilProxy::WriteCallback* callback) 569 : file_(file), 570 offset_(offset), 571 buffer_(new char[bytes_to_write]), 572 bytes_to_write_(bytes_to_write), 573 callback_(callback), 574 bytes_written_(0) { 575 memcpy(buffer_.get(), buffer, bytes_to_write); 576 } 577 578 protected: RunWork()579 virtual void RunWork() { 580 bytes_written_ = base::WritePlatformFile(file_, offset_, buffer_.get(), 581 bytes_to_write_); 582 if (bytes_written_ < 0) 583 set_error_code(base::PLATFORM_FILE_ERROR_FAILED); 584 } 585 RunCallback()586 virtual void RunCallback() { 587 if (callback_) { 588 callback_->Run(error_code(), bytes_written_); 589 delete callback_; 590 } 591 } 592 593 private: 594 base::PlatformFile file_; 595 int64 offset_; 596 scoped_array<char> buffer_; 597 int bytes_to_write_; 598 base::FileUtilProxy::WriteCallback* callback_; 599 int bytes_written_; 600 }; 601 602 class RelayTouch : public RelayWithStatusCallback { 603 public: RelayTouch(base::PlatformFile file,const base::Time & last_access_time,const base::Time & last_modified_time,base::FileUtilProxy::StatusCallback * callback)604 RelayTouch(base::PlatformFile file, 605 const base::Time& last_access_time, 606 const base::Time& last_modified_time, 607 base::FileUtilProxy::StatusCallback* callback) 608 : RelayWithStatusCallback(callback), 609 file_(file), 610 last_access_time_(last_access_time), 611 last_modified_time_(last_modified_time) { 612 } 613 614 protected: RunWork()615 virtual void RunWork() { 616 if (!base::TouchPlatformFile(file_, last_access_time_, last_modified_time_)) 617 set_error_code(base::PLATFORM_FILE_ERROR_FAILED); 618 } 619 620 private: 621 base::PlatformFile file_; 622 base::Time last_access_time_; 623 base::Time last_modified_time_; 624 }; 625 626 class RelayTouchFilePath : public RelayWithStatusCallback { 627 public: RelayTouchFilePath(const FilePath & file_path,const base::Time & last_access_time,const base::Time & last_modified_time,base::FileUtilProxy::StatusCallback * callback)628 RelayTouchFilePath(const FilePath& file_path, 629 const base::Time& last_access_time, 630 const base::Time& last_modified_time, 631 base::FileUtilProxy::StatusCallback* callback) 632 : RelayWithStatusCallback(callback), 633 file_path_(file_path), 634 last_access_time_(last_access_time), 635 last_modified_time_(last_modified_time) { 636 } 637 638 protected: RunWork()639 virtual void RunWork() { 640 if (!file_util::TouchFile( 641 file_path_, last_access_time_, last_modified_time_)) 642 set_error_code(base::PLATFORM_FILE_ERROR_FAILED); 643 } 644 645 private: 646 FilePath file_path_; 647 base::Time last_access_time_; 648 base::Time last_modified_time_; 649 }; 650 651 class RelayTruncatePlatformFile : public RelayWithStatusCallback { 652 public: RelayTruncatePlatformFile(base::PlatformFile file,int64 length,base::FileUtilProxy::StatusCallback * callback)653 RelayTruncatePlatformFile(base::PlatformFile file, 654 int64 length, 655 base::FileUtilProxy::StatusCallback* callback) 656 : RelayWithStatusCallback(callback), 657 file_(file), 658 length_(length) { 659 } 660 661 protected: RunWork()662 virtual void RunWork() { 663 if (!base::TruncatePlatformFile(file_, length_)) 664 set_error_code(base::PLATFORM_FILE_ERROR_FAILED); 665 } 666 667 private: 668 base::PlatformFile file_; 669 int64 length_; 670 }; 671 672 class RelayTruncate : public RelayWithStatusCallback { 673 public: RelayTruncate(const FilePath & path,int64 length,base::FileUtilProxy::StatusCallback * callback)674 RelayTruncate(const FilePath& path, 675 int64 length, 676 base::FileUtilProxy::StatusCallback* callback) 677 : RelayWithStatusCallback(callback), 678 path_(path), 679 length_(length) { 680 } 681 682 protected: RunWork()683 virtual void RunWork() { 684 base::PlatformFileError error_code(base::PLATFORM_FILE_ERROR_FAILED); 685 base::PlatformFile file = 686 base::CreatePlatformFile( 687 path_, 688 base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE, 689 NULL, 690 &error_code); 691 if (error_code != base::PLATFORM_FILE_OK) { 692 set_error_code(error_code); 693 return; 694 } 695 if (!base::TruncatePlatformFile(file, length_)) 696 set_error_code(base::PLATFORM_FILE_ERROR_FAILED); 697 base::ClosePlatformFile(file); 698 } 699 700 private: 701 FilePath path_; 702 int64 length_; 703 }; 704 705 class RelayFlush : public RelayWithStatusCallback { 706 public: RelayFlush(base::PlatformFile file,base::FileUtilProxy::StatusCallback * callback)707 RelayFlush(base::PlatformFile file, 708 base::FileUtilProxy::StatusCallback* callback) 709 : RelayWithStatusCallback(callback), 710 file_(file) { 711 } 712 713 protected: RunWork()714 virtual void RunWork() { 715 if (!base::FlushPlatformFile(file_)) 716 set_error_code(base::PLATFORM_FILE_ERROR_FAILED); 717 } 718 719 private: 720 base::PlatformFile file_; 721 }; 722 Start(const tracked_objects::Location & from_here,scoped_refptr<base::MessageLoopProxy> message_loop_proxy,scoped_refptr<MessageLoopRelay> relay)723 bool Start(const tracked_objects::Location& from_here, 724 scoped_refptr<base::MessageLoopProxy> message_loop_proxy, 725 scoped_refptr<MessageLoopRelay> relay) { 726 return relay->Start(message_loop_proxy, from_here); 727 } 728 729 } // namespace 730 731 namespace base { 732 733 // static CreateOrOpen(scoped_refptr<MessageLoopProxy> message_loop_proxy,const FilePath & file_path,int file_flags,CreateOrOpenCallback * callback)734 bool FileUtilProxy::CreateOrOpen( 735 scoped_refptr<MessageLoopProxy> message_loop_proxy, 736 const FilePath& file_path, int file_flags, 737 CreateOrOpenCallback* callback) { 738 return Start(FROM_HERE, message_loop_proxy, new RelayCreateOrOpen( 739 message_loop_proxy, file_path, file_flags, callback)); 740 } 741 742 // static CreateTemporary(scoped_refptr<MessageLoopProxy> message_loop_proxy,CreateTemporaryCallback * callback)743 bool FileUtilProxy::CreateTemporary( 744 scoped_refptr<MessageLoopProxy> message_loop_proxy, 745 CreateTemporaryCallback* callback) { 746 return Start(FROM_HERE, message_loop_proxy, 747 new RelayCreateTemporary(message_loop_proxy, callback)); 748 } 749 750 // static Close(scoped_refptr<MessageLoopProxy> message_loop_proxy,base::PlatformFile file_handle,StatusCallback * callback)751 bool FileUtilProxy::Close(scoped_refptr<MessageLoopProxy> message_loop_proxy, 752 base::PlatformFile file_handle, 753 StatusCallback* callback) { 754 return Start(FROM_HERE, message_loop_proxy, 755 new RelayClose(file_handle, callback)); 756 } 757 758 // static EnsureFileExists(scoped_refptr<MessageLoopProxy> message_loop_proxy,const FilePath & file_path,EnsureFileExistsCallback * callback)759 bool FileUtilProxy::EnsureFileExists( 760 scoped_refptr<MessageLoopProxy> message_loop_proxy, 761 const FilePath& file_path, 762 EnsureFileExistsCallback* callback) { 763 return Start(FROM_HERE, message_loop_proxy, new RelayEnsureFileExists( 764 message_loop_proxy, file_path, callback)); 765 } 766 767 // Retrieves the information about a file. It is invalid to pass NULL for the 768 // callback. GetFileInfo(scoped_refptr<MessageLoopProxy> message_loop_proxy,const FilePath & file_path,GetFileInfoCallback * callback)769 bool FileUtilProxy::GetFileInfo( 770 scoped_refptr<MessageLoopProxy> message_loop_proxy, 771 const FilePath& file_path, 772 GetFileInfoCallback* callback) { 773 return Start(FROM_HERE, message_loop_proxy, new RelayGetFileInfo( 774 file_path, callback)); 775 } 776 777 // static GetFileInfoFromPlatformFile(scoped_refptr<MessageLoopProxy> message_loop_proxy,PlatformFile file,GetFileInfoCallback * callback)778 bool FileUtilProxy::GetFileInfoFromPlatformFile( 779 scoped_refptr<MessageLoopProxy> message_loop_proxy, 780 PlatformFile file, 781 GetFileInfoCallback* callback) { 782 return Start(FROM_HERE, message_loop_proxy, 783 new RelayGetFileInfoFromPlatformFile(file, callback)); 784 } 785 786 // static ReadDirectory(scoped_refptr<MessageLoopProxy> message_loop_proxy,const FilePath & file_path,ReadDirectoryCallback * callback)787 bool FileUtilProxy::ReadDirectory( 788 scoped_refptr<MessageLoopProxy> message_loop_proxy, 789 const FilePath& file_path, 790 ReadDirectoryCallback* callback) { 791 return Start(FROM_HERE, message_loop_proxy, new RelayReadDirectory( 792 file_path, callback)); 793 } 794 795 // static CreateDirectory(scoped_refptr<MessageLoopProxy> message_loop_proxy,const FilePath & file_path,bool exclusive,bool recursive,StatusCallback * callback)796 bool FileUtilProxy::CreateDirectory( 797 scoped_refptr<MessageLoopProxy> message_loop_proxy, 798 const FilePath& file_path, 799 bool exclusive, 800 bool recursive, 801 StatusCallback* callback) { 802 return Start(FROM_HERE, message_loop_proxy, new RelayCreateDirectory( 803 file_path, exclusive, recursive, callback)); 804 } 805 806 // static Copy(scoped_refptr<MessageLoopProxy> message_loop_proxy,const FilePath & src_file_path,const FilePath & dest_file_path,StatusCallback * callback)807 bool FileUtilProxy::Copy(scoped_refptr<MessageLoopProxy> message_loop_proxy, 808 const FilePath& src_file_path, 809 const FilePath& dest_file_path, 810 StatusCallback* callback) { 811 return Start(FROM_HERE, message_loop_proxy, 812 new RelayCopy(src_file_path, dest_file_path, callback)); 813 } 814 815 // static Move(scoped_refptr<MessageLoopProxy> message_loop_proxy,const FilePath & src_file_path,const FilePath & dest_file_path,StatusCallback * callback)816 bool FileUtilProxy::Move(scoped_refptr<MessageLoopProxy> message_loop_proxy, 817 const FilePath& src_file_path, 818 const FilePath& dest_file_path, 819 StatusCallback* callback) { 820 return Start(FROM_HERE, message_loop_proxy, 821 new RelayMove(src_file_path, dest_file_path, callback)); 822 } 823 824 // static Delete(scoped_refptr<MessageLoopProxy> message_loop_proxy,const FilePath & file_path,bool recursive,StatusCallback * callback)825 bool FileUtilProxy::Delete(scoped_refptr<MessageLoopProxy> message_loop_proxy, 826 const FilePath& file_path, 827 bool recursive, 828 StatusCallback* callback) { 829 return Start(FROM_HERE, message_loop_proxy, 830 new RelayDelete(file_path, recursive, callback)); 831 } 832 833 // static RecursiveDelete(scoped_refptr<MessageLoopProxy> message_loop_proxy,const FilePath & file_path,StatusCallback * callback)834 bool FileUtilProxy::RecursiveDelete( 835 scoped_refptr<MessageLoopProxy> message_loop_proxy, 836 const FilePath& file_path, 837 StatusCallback* callback) { 838 return Start(FROM_HERE, message_loop_proxy, 839 new RelayDelete(file_path, true, callback)); 840 } 841 842 // static Read(scoped_refptr<MessageLoopProxy> message_loop_proxy,PlatformFile file,int64 offset,int bytes_to_read,ReadCallback * callback)843 bool FileUtilProxy::Read( 844 scoped_refptr<MessageLoopProxy> message_loop_proxy, 845 PlatformFile file, 846 int64 offset, 847 int bytes_to_read, 848 ReadCallback* callback) { 849 return Start(FROM_HERE, message_loop_proxy, 850 new RelayRead(file, offset, bytes_to_read, callback)); 851 } 852 853 // static Write(scoped_refptr<MessageLoopProxy> message_loop_proxy,PlatformFile file,int64 offset,const char * buffer,int bytes_to_write,WriteCallback * callback)854 bool FileUtilProxy::Write( 855 scoped_refptr<MessageLoopProxy> message_loop_proxy, 856 PlatformFile file, 857 int64 offset, 858 const char* buffer, 859 int bytes_to_write, 860 WriteCallback* callback) { 861 return Start(FROM_HERE, message_loop_proxy, 862 new RelayWrite(file, offset, buffer, bytes_to_write, callback)); 863 } 864 865 // static Touch(scoped_refptr<MessageLoopProxy> message_loop_proxy,PlatformFile file,const base::Time & last_access_time,const base::Time & last_modified_time,StatusCallback * callback)866 bool FileUtilProxy::Touch( 867 scoped_refptr<MessageLoopProxy> message_loop_proxy, 868 PlatformFile file, 869 const base::Time& last_access_time, 870 const base::Time& last_modified_time, 871 StatusCallback* callback) { 872 return Start(FROM_HERE, message_loop_proxy, 873 new RelayTouch(file, last_access_time, last_modified_time, 874 callback)); 875 } 876 877 // static Touch(scoped_refptr<MessageLoopProxy> message_loop_proxy,const FilePath & file_path,const base::Time & last_access_time,const base::Time & last_modified_time,StatusCallback * callback)878 bool FileUtilProxy::Touch( 879 scoped_refptr<MessageLoopProxy> message_loop_proxy, 880 const FilePath& file_path, 881 const base::Time& last_access_time, 882 const base::Time& last_modified_time, 883 StatusCallback* callback) { 884 return Start(FROM_HERE, message_loop_proxy, 885 new RelayTouchFilePath(file_path, last_access_time, 886 last_modified_time, callback)); 887 } 888 889 // static Truncate(scoped_refptr<MessageLoopProxy> message_loop_proxy,PlatformFile file,int64 length,StatusCallback * callback)890 bool FileUtilProxy::Truncate( 891 scoped_refptr<MessageLoopProxy> message_loop_proxy, 892 PlatformFile file, 893 int64 length, 894 StatusCallback* callback) { 895 return Start(FROM_HERE, message_loop_proxy, 896 new RelayTruncatePlatformFile(file, length, callback)); 897 } 898 899 // static Truncate(scoped_refptr<MessageLoopProxy> message_loop_proxy,const FilePath & path,int64 length,StatusCallback * callback)900 bool FileUtilProxy::Truncate( 901 scoped_refptr<MessageLoopProxy> message_loop_proxy, 902 const FilePath& path, 903 int64 length, 904 StatusCallback* callback) { 905 return Start(FROM_HERE, message_loop_proxy, 906 new RelayTruncate(path, length, callback)); 907 } 908 909 // static Flush(scoped_refptr<MessageLoopProxy> message_loop_proxy,PlatformFile file,StatusCallback * callback)910 bool FileUtilProxy::Flush( 911 scoped_refptr<MessageLoopProxy> message_loop_proxy, 912 PlatformFile file, 913 StatusCallback* callback) { 914 return Start(FROM_HERE, message_loop_proxy, new RelayFlush(file, callback)); 915 } 916 917 } // namespace base 918