Home | History | Annotate | Download | only in base
      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).
     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:
     74   MessageLoopRelay()
     75       : origin_message_loop_proxy_(
     76             base::MessageLoopProxy::CreateForCurrentThread()),
     77         error_code_(base::PLATFORM_FILE_OK) {
     78   }
     79 
     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>;
     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 
     97   void set_error_code(base::PlatformFileError error_code) {
     98     error_code_ = error_code;
     99   }
    100 
    101   base::PlatformFileError error_code() const {
    102     return error_code_;
    103   }
    104 
    105  private:
    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:
    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:
    134   virtual ~RelayCreateOrOpen() {
    135     if (file_handle_ != base::kInvalidPlatformFileValue)
    136       base::FileUtilProxy::Close(message_loop_proxy_, file_handle_, NULL);
    137   }
    138 
    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 
    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:
    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:
    178   virtual ~RelayCreateTemporary() {
    179     if (file_handle_ != base::kInvalidPlatformFileValue)
    180       base::FileUtilProxy::Close(message_loop_proxy_, file_handle_, NULL);
    181   }
    182 
    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 
    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:
    216   explicit RelayWithStatusCallback(
    217       base::FileUtilProxy::StatusCallback* callback)
    218       : callback_(callback) {
    219     // It is OK for callback to be NULL.
    220   }
    221 
    222  protected:
    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:
    237   RelayClose(base::PlatformFile file_handle,
    238              base::FileUtilProxy::StatusCallback* callback)
    239       : RelayWithStatusCallback(callback),
    240         file_handle_(file_handle) {
    241   }
    242 
    243  protected:
    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:
    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:
    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 
    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:
    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:
    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:
    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:
    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:
    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:
    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:
    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:
    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:
    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:
    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 
    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:
    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:
    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 
    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:
    499   RelayGetFileInfoFromPlatformFile(
    500       base::PlatformFile file,
    501       base::FileUtilProxy::GetFileInfoCallback* callback)
    502       : callback_(callback),
    503         file_(file) {
    504     DCHECK(callback);
    505   }
    506 
    507  protected:
    508   virtual void RunWork() {
    509     if (!base::GetPlatformFileInfo(file_, &file_info_))
    510       set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
    511   }
    512 
    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:
    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:
    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 
    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:
    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:
    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 
    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:
    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:
    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:
    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:
    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:
    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:
    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:
    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:
    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:
    707   RelayFlush(base::PlatformFile file,
    708              base::FileUtilProxy::StatusCallback* callback)
    709       : RelayWithStatusCallback(callback),
    710         file_(file) {
    711   }
    712 
    713  protected:
    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 
    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
    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
    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
    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
    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.
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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