Home | History | Annotate | Download | only in files
      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 "base/files/file_util_proxy.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/bind_helpers.h"
      9 #include "base/file_util.h"
     10 #include "base/location.h"
     11 #include "base/message_loop/message_loop_proxy.h"
     12 #include "base/task_runner.h"
     13 #include "base/task_runner_util.h"
     14 
     15 namespace base {
     16 
     17 namespace {
     18 
     19 void CallWithTranslatedParameter(const FileUtilProxy::StatusCallback& callback,
     20                                  bool value) {
     21   DCHECK(!callback.is_null());
     22   callback.Run(value ? PLATFORM_FILE_OK : PLATFORM_FILE_ERROR_FAILED);
     23 }
     24 
     25 // Helper classes or routines for individual methods.
     26 class CreateOrOpenHelper {
     27  public:
     28   CreateOrOpenHelper(TaskRunner* task_runner,
     29                      const FileUtilProxy::CloseTask& close_task)
     30       : task_runner_(task_runner),
     31         close_task_(close_task),
     32         file_handle_(kInvalidPlatformFileValue),
     33         created_(false),
     34         error_(PLATFORM_FILE_OK) {}
     35 
     36   ~CreateOrOpenHelper() {
     37     if (file_handle_ != kInvalidPlatformFileValue) {
     38       task_runner_->PostTask(
     39           FROM_HERE,
     40           base::Bind(base::IgnoreResult(close_task_), file_handle_));
     41     }
     42   }
     43 
     44   void RunWork(const FileUtilProxy::CreateOrOpenTask& task) {
     45     error_ = task.Run(&file_handle_, &created_);
     46   }
     47 
     48   void Reply(const FileUtilProxy::CreateOrOpenCallback& callback) {
     49     DCHECK(!callback.is_null());
     50     callback.Run(error_, PassPlatformFile(&file_handle_), created_);
     51   }
     52 
     53  private:
     54   scoped_refptr<TaskRunner> task_runner_;
     55   FileUtilProxy::CloseTask close_task_;
     56   PlatformFile file_handle_;
     57   bool created_;
     58   PlatformFileError error_;
     59   DISALLOW_COPY_AND_ASSIGN(CreateOrOpenHelper);
     60 };
     61 
     62 class CreateTemporaryHelper {
     63  public:
     64   explicit CreateTemporaryHelper(TaskRunner* task_runner)
     65       : task_runner_(task_runner),
     66         file_handle_(kInvalidPlatformFileValue),
     67         error_(PLATFORM_FILE_OK) {}
     68 
     69   ~CreateTemporaryHelper() {
     70     if (file_handle_ != kInvalidPlatformFileValue) {
     71       FileUtilProxy::Close(
     72           task_runner_.get(), file_handle_, FileUtilProxy::StatusCallback());
     73     }
     74   }
     75 
     76   void RunWork(int additional_file_flags) {
     77     // TODO(darin): file_util should have a variant of CreateTemporaryFile
     78     // that returns a FilePath and a PlatformFile.
     79     file_util::CreateTemporaryFile(&file_path_);
     80 
     81     int file_flags =
     82         PLATFORM_FILE_WRITE |
     83         PLATFORM_FILE_TEMPORARY |
     84         PLATFORM_FILE_CREATE_ALWAYS |
     85         additional_file_flags;
     86 
     87     error_ = PLATFORM_FILE_OK;
     88     file_handle_ = CreatePlatformFile(file_path_, file_flags, NULL, &error_);
     89   }
     90 
     91   void Reply(const FileUtilProxy::CreateTemporaryCallback& callback) {
     92     DCHECK(!callback.is_null());
     93     callback.Run(error_, PassPlatformFile(&file_handle_), file_path_);
     94   }
     95 
     96  private:
     97   scoped_refptr<TaskRunner> task_runner_;
     98   PlatformFile file_handle_;
     99   FilePath file_path_;
    100   PlatformFileError error_;
    101   DISALLOW_COPY_AND_ASSIGN(CreateTemporaryHelper);
    102 };
    103 
    104 class GetFileInfoHelper {
    105  public:
    106   GetFileInfoHelper()
    107       : error_(PLATFORM_FILE_OK) {}
    108 
    109   void RunWorkForFilePath(const FilePath& file_path) {
    110     if (!PathExists(file_path)) {
    111       error_ = PLATFORM_FILE_ERROR_NOT_FOUND;
    112       return;
    113     }
    114     if (!file_util::GetFileInfo(file_path, &file_info_))
    115       error_ = PLATFORM_FILE_ERROR_FAILED;
    116   }
    117 
    118   void RunWorkForPlatformFile(PlatformFile file) {
    119     if (!GetPlatformFileInfo(file, &file_info_))
    120       error_ = PLATFORM_FILE_ERROR_FAILED;
    121   }
    122 
    123   void Reply(const FileUtilProxy::GetFileInfoCallback& callback) {
    124     if (!callback.is_null()) {
    125       callback.Run(error_, file_info_);
    126     }
    127   }
    128 
    129  private:
    130   PlatformFileError error_;
    131   PlatformFileInfo file_info_;
    132   DISALLOW_COPY_AND_ASSIGN(GetFileInfoHelper);
    133 };
    134 
    135 class ReadHelper {
    136  public:
    137   explicit ReadHelper(int bytes_to_read)
    138       : buffer_(new char[bytes_to_read]),
    139         bytes_to_read_(bytes_to_read),
    140         bytes_read_(0) {}
    141 
    142   void RunWork(PlatformFile file, int64 offset) {
    143     bytes_read_ = ReadPlatformFile(file, offset, buffer_.get(), bytes_to_read_);
    144   }
    145 
    146   void Reply(const FileUtilProxy::ReadCallback& callback) {
    147     if (!callback.is_null()) {
    148       PlatformFileError error =
    149           (bytes_read_ < 0) ? PLATFORM_FILE_ERROR_FAILED : PLATFORM_FILE_OK;
    150       callback.Run(error, buffer_.get(), bytes_read_);
    151     }
    152   }
    153 
    154  private:
    155   scoped_ptr<char[]> buffer_;
    156   int bytes_to_read_;
    157   int bytes_read_;
    158   DISALLOW_COPY_AND_ASSIGN(ReadHelper);
    159 };
    160 
    161 class WriteHelper {
    162  public:
    163   WriteHelper(const char* buffer, int bytes_to_write)
    164       : buffer_(new char[bytes_to_write]),
    165         bytes_to_write_(bytes_to_write),
    166         bytes_written_(0) {
    167     memcpy(buffer_.get(), buffer, bytes_to_write);
    168   }
    169 
    170   void RunWork(PlatformFile file, int64 offset) {
    171     bytes_written_ = WritePlatformFile(file, offset, buffer_.get(),
    172                                        bytes_to_write_);
    173   }
    174 
    175   void Reply(const FileUtilProxy::WriteCallback& callback) {
    176     if (!callback.is_null()) {
    177       PlatformFileError error =
    178           (bytes_written_ < 0) ? PLATFORM_FILE_ERROR_FAILED : PLATFORM_FILE_OK;
    179       callback.Run(error, bytes_written_);
    180     }
    181   }
    182 
    183  private:
    184   scoped_ptr<char[]> buffer_;
    185   int bytes_to_write_;
    186   int bytes_written_;
    187   DISALLOW_COPY_AND_ASSIGN(WriteHelper);
    188 };
    189 
    190 PlatformFileError CreateOrOpenAdapter(
    191     const FilePath& file_path, int file_flags,
    192     PlatformFile* file_handle, bool* created) {
    193   DCHECK(file_handle);
    194   DCHECK(created);
    195   if (!DirectoryExists(file_path.DirName())) {
    196     // If its parent does not exist, should return NOT_FOUND error.
    197     return PLATFORM_FILE_ERROR_NOT_FOUND;
    198   }
    199   PlatformFileError error = PLATFORM_FILE_OK;
    200   *file_handle = CreatePlatformFile(file_path, file_flags, created, &error);
    201   return error;
    202 }
    203 
    204 PlatformFileError CloseAdapter(PlatformFile file_handle) {
    205   if (!ClosePlatformFile(file_handle)) {
    206     return PLATFORM_FILE_ERROR_FAILED;
    207   }
    208   return PLATFORM_FILE_OK;
    209 }
    210 
    211 PlatformFileError DeleteAdapter(const FilePath& file_path, bool recursive) {
    212   if (!PathExists(file_path)) {
    213     return PLATFORM_FILE_ERROR_NOT_FOUND;
    214   }
    215   if (!base::DeleteFile(file_path, recursive)) {
    216     if (!recursive && !file_util::IsDirectoryEmpty(file_path)) {
    217       return PLATFORM_FILE_ERROR_NOT_EMPTY;
    218     }
    219     return PLATFORM_FILE_ERROR_FAILED;
    220   }
    221   return PLATFORM_FILE_OK;
    222 }
    223 
    224 }  // namespace
    225 
    226 // static
    227 bool FileUtilProxy::CreateOrOpen(
    228     TaskRunner* task_runner,
    229     const FilePath& file_path, int file_flags,
    230     const CreateOrOpenCallback& callback) {
    231   return RelayCreateOrOpen(
    232       task_runner,
    233       base::Bind(&CreateOrOpenAdapter, file_path, file_flags),
    234       base::Bind(&CloseAdapter),
    235       callback);
    236 }
    237 
    238 // static
    239 bool FileUtilProxy::CreateTemporary(
    240     TaskRunner* task_runner,
    241     int additional_file_flags,
    242     const CreateTemporaryCallback& callback) {
    243   CreateTemporaryHelper* helper = new CreateTemporaryHelper(task_runner);
    244   return task_runner->PostTaskAndReply(
    245       FROM_HERE,
    246       Bind(&CreateTemporaryHelper::RunWork, Unretained(helper),
    247            additional_file_flags),
    248       Bind(&CreateTemporaryHelper::Reply, Owned(helper), callback));
    249 }
    250 
    251 // static
    252 bool FileUtilProxy::Close(
    253     TaskRunner* task_runner,
    254     base::PlatformFile file_handle,
    255     const StatusCallback& callback) {
    256   return RelayClose(
    257       task_runner,
    258       base::Bind(&CloseAdapter),
    259       file_handle, callback);
    260 }
    261 
    262 // Retrieves the information about a file. It is invalid to pass NULL for the
    263 // callback.
    264 bool FileUtilProxy::GetFileInfo(
    265     TaskRunner* task_runner,
    266     const FilePath& file_path,
    267     const GetFileInfoCallback& callback) {
    268   GetFileInfoHelper* helper = new GetFileInfoHelper;
    269   return task_runner->PostTaskAndReply(
    270       FROM_HERE,
    271       Bind(&GetFileInfoHelper::RunWorkForFilePath,
    272            Unretained(helper), file_path),
    273       Bind(&GetFileInfoHelper::Reply, Owned(helper), callback));
    274 }
    275 
    276 // static
    277 bool FileUtilProxy::GetFileInfoFromPlatformFile(
    278     TaskRunner* task_runner,
    279     PlatformFile file,
    280     const GetFileInfoCallback& callback) {
    281   GetFileInfoHelper* helper = new GetFileInfoHelper;
    282   return task_runner->PostTaskAndReply(
    283       FROM_HERE,
    284       Bind(&GetFileInfoHelper::RunWorkForPlatformFile,
    285            Unretained(helper), file),
    286       Bind(&GetFileInfoHelper::Reply, Owned(helper), callback));
    287 }
    288 
    289 // static
    290 bool FileUtilProxy::DeleteFile(TaskRunner* task_runner,
    291                                const FilePath& file_path,
    292                                bool recursive,
    293                                const StatusCallback& callback) {
    294   return base::PostTaskAndReplyWithResult(
    295       task_runner, FROM_HERE,
    296       Bind(&DeleteAdapter, file_path, recursive),
    297       callback);
    298 }
    299 
    300 // static
    301 bool FileUtilProxy::Read(
    302     TaskRunner* task_runner,
    303     PlatformFile file,
    304     int64 offset,
    305     int bytes_to_read,
    306     const ReadCallback& callback) {
    307   if (bytes_to_read < 0) {
    308     return false;
    309   }
    310   ReadHelper* helper = new ReadHelper(bytes_to_read);
    311   return task_runner->PostTaskAndReply(
    312       FROM_HERE,
    313       Bind(&ReadHelper::RunWork, Unretained(helper), file, offset),
    314       Bind(&ReadHelper::Reply, Owned(helper), callback));
    315 }
    316 
    317 // static
    318 bool FileUtilProxy::Write(
    319     TaskRunner* task_runner,
    320     PlatformFile file,
    321     int64 offset,
    322     const char* buffer,
    323     int bytes_to_write,
    324     const WriteCallback& callback) {
    325   if (bytes_to_write <= 0 || buffer == NULL) {
    326     return false;
    327   }
    328   WriteHelper* helper = new WriteHelper(buffer, bytes_to_write);
    329   return task_runner->PostTaskAndReply(
    330       FROM_HERE,
    331       Bind(&WriteHelper::RunWork, Unretained(helper), file, offset),
    332       Bind(&WriteHelper::Reply, Owned(helper), callback));
    333 }
    334 
    335 // static
    336 bool FileUtilProxy::Touch(
    337     TaskRunner* task_runner,
    338     PlatformFile file,
    339     const Time& last_access_time,
    340     const Time& last_modified_time,
    341     const StatusCallback& callback) {
    342   return base::PostTaskAndReplyWithResult(
    343       task_runner,
    344       FROM_HERE,
    345       Bind(&TouchPlatformFile, file,
    346            last_access_time, last_modified_time),
    347       Bind(&CallWithTranslatedParameter, callback));
    348 }
    349 
    350 // static
    351 bool FileUtilProxy::Touch(
    352     TaskRunner* task_runner,
    353     const FilePath& file_path,
    354     const Time& last_access_time,
    355     const Time& last_modified_time,
    356     const StatusCallback& callback) {
    357   return base::PostTaskAndReplyWithResult(
    358       task_runner,
    359       FROM_HERE,
    360       Bind(&file_util::TouchFile, file_path,
    361            last_access_time, last_modified_time),
    362       Bind(&CallWithTranslatedParameter, callback));
    363 }
    364 
    365 // static
    366 bool FileUtilProxy::Truncate(
    367     TaskRunner* task_runner,
    368     PlatformFile file,
    369     int64 length,
    370     const StatusCallback& callback) {
    371   return base::PostTaskAndReplyWithResult(
    372       task_runner,
    373       FROM_HERE,
    374       Bind(&TruncatePlatformFile, file, length),
    375       Bind(&CallWithTranslatedParameter, callback));
    376 }
    377 
    378 // static
    379 bool FileUtilProxy::Flush(
    380     TaskRunner* task_runner,
    381     PlatformFile file,
    382     const StatusCallback& callback) {
    383   return base::PostTaskAndReplyWithResult(
    384       task_runner,
    385       FROM_HERE,
    386       Bind(&FlushPlatformFile, file),
    387       Bind(&CallWithTranslatedParameter, callback));
    388 }
    389 
    390 // static
    391 bool FileUtilProxy::RelayCreateOrOpen(
    392     TaskRunner* task_runner,
    393     const CreateOrOpenTask& open_task,
    394     const CloseTask& close_task,
    395     const CreateOrOpenCallback& callback) {
    396   CreateOrOpenHelper* helper = new CreateOrOpenHelper(
    397       task_runner, close_task);
    398   return task_runner->PostTaskAndReply(
    399       FROM_HERE,
    400       Bind(&CreateOrOpenHelper::RunWork, Unretained(helper), open_task),
    401       Bind(&CreateOrOpenHelper::Reply, Owned(helper), callback));
    402 }
    403 
    404 // static
    405 bool FileUtilProxy::RelayClose(
    406     TaskRunner* task_runner,
    407     const CloseTask& close_task,
    408     PlatformFile file_handle,
    409     const StatusCallback& callback) {
    410   return base::PostTaskAndReplyWithResult(
    411       task_runner, FROM_HERE, Bind(close_task, file_handle), callback);
    412 }
    413 
    414 }  // namespace base
    415