root/base/files/file_util_proxy.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. CallWithTranslatedParameter
  2. error_
  3. RunWork
  4. Reply
  5. error_
  6. RunWork
  7. Reply
  8. RunWorkForFilePath
  9. RunWorkForPlatformFile
  10. Reply
  11. bytes_read_
  12. RunWork
  13. Reply
  14. bytes_written_
  15. RunWork
  16. Reply
  17. CreateOrOpenAdapter
  18. CloseAdapter
  19. DeleteAdapter
  20. CreateOrOpen
  21. CreateTemporary
  22. Close
  23. GetFileInfo
  24. GetFileInfoFromPlatformFile
  25. DeleteFile
  26. Read
  27. Write
  28. Touch
  29. Touch
  30. Truncate
  31. Flush
  32. RelayCreateOrOpen
  33. RelayClose

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/files/file_util_proxy.h"

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/file_util.h"
#include "base/files/file.h"
#include "base/location.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/task_runner.h"
#include "base/task_runner_util.h"

namespace base {

namespace {

void CallWithTranslatedParameter(const FileUtilProxy::StatusCallback& callback,
                                 bool value) {
  DCHECK(!callback.is_null());
  callback.Run(value ? File::FILE_OK : File::FILE_ERROR_FAILED);
}

// Helper classes or routines for individual methods.
class CreateOrOpenHelper {
 public:
  CreateOrOpenHelper(TaskRunner* task_runner,
                     const FileUtilProxy::CloseTask& close_task)
      : task_runner_(task_runner),
        close_task_(close_task),
        file_handle_(kInvalidPlatformFileValue),
        created_(false),
        error_(File::FILE_OK) {}

  ~CreateOrOpenHelper() {
    if (file_handle_ != kInvalidPlatformFileValue) {
      task_runner_->PostTask(
          FROM_HERE,
          base::Bind(base::IgnoreResult(close_task_), file_handle_));
    }
  }

  void RunWork(const FileUtilProxy::CreateOrOpenTask& task) {
    error_ = task.Run(&file_handle_, &created_);
  }

  void Reply(const FileUtilProxy::CreateOrOpenCallback& callback) {
    DCHECK(!callback.is_null());
    callback.Run(error_, PassPlatformFile(&file_handle_), created_);
  }

 private:
  scoped_refptr<TaskRunner> task_runner_;
  FileUtilProxy::CloseTask close_task_;
  PlatformFile file_handle_;
  bool created_;
  File::Error error_;
  DISALLOW_COPY_AND_ASSIGN(CreateOrOpenHelper);
};

class CreateTemporaryHelper {
 public:
  explicit CreateTemporaryHelper(TaskRunner* task_runner)
      : task_runner_(task_runner),
        file_handle_(kInvalidPlatformFileValue),
        error_(File::FILE_OK) {}

  ~CreateTemporaryHelper() {
    if (file_handle_ != kInvalidPlatformFileValue) {
      FileUtilProxy::Close(
          task_runner_.get(), file_handle_, FileUtilProxy::StatusCallback());
    }
  }

  void RunWork(int additional_file_flags) {
    // TODO(darin): file_util should have a variant of CreateTemporaryFile
    // that returns a FilePath and a PlatformFile.
    if (!base::CreateTemporaryFile(&file_path_)) {
      // TODO(davidben): base::CreateTemporaryFile should preserve the error
      // code.
      error_ = File::FILE_ERROR_FAILED;
      return;
    }

    int file_flags =
        PLATFORM_FILE_WRITE |
        PLATFORM_FILE_TEMPORARY |
        PLATFORM_FILE_CREATE_ALWAYS |
        additional_file_flags;

    error_ = File::FILE_OK;
    // TODO(rvargas): Convert this code to use File.
    file_handle_ =
        CreatePlatformFile(file_path_, file_flags, NULL,
                           reinterpret_cast<PlatformFileError*>(&error_));
    if (error_ != File::FILE_OK) {
      base::DeleteFile(file_path_, false);
      file_path_.clear();
    }
  }

  void Reply(const FileUtilProxy::CreateTemporaryCallback& callback) {
    DCHECK(!callback.is_null());
    callback.Run(error_, PassPlatformFile(&file_handle_), file_path_);
  }

 private:
  scoped_refptr<TaskRunner> task_runner_;
  PlatformFile file_handle_;
  FilePath file_path_;
  File::Error error_;
  DISALLOW_COPY_AND_ASSIGN(CreateTemporaryHelper);
};

class GetFileInfoHelper {
 public:
  GetFileInfoHelper()
      : error_(File::FILE_OK) {}

  void RunWorkForFilePath(const FilePath& file_path) {
    if (!PathExists(file_path)) {
      error_ = File::FILE_ERROR_NOT_FOUND;
      return;
    }
    // TODO(rvargas): switch this file to base::File.
    if (!GetFileInfo(file_path, reinterpret_cast<File::Info*>(&file_info_)))
      error_ = File::FILE_ERROR_FAILED;
  }

  void RunWorkForPlatformFile(PlatformFile file) {
    if (!GetPlatformFileInfo(
            file, reinterpret_cast<PlatformFileInfo*>(&file_info_))) {
      error_ = File::FILE_ERROR_FAILED;
    }
  }

  void Reply(const FileUtilProxy::GetFileInfoCallback& callback) {
    if (!callback.is_null()) {
      callback.Run(error_, file_info_);
    }
  }

 private:
  File::Error error_;
  File::Info file_info_;
  DISALLOW_COPY_AND_ASSIGN(GetFileInfoHelper);
};

class ReadHelper {
 public:
  explicit ReadHelper(int bytes_to_read)
      : buffer_(new char[bytes_to_read]),
        bytes_to_read_(bytes_to_read),
        bytes_read_(0) {}

  void RunWork(PlatformFile file, int64 offset) {
    bytes_read_ = ReadPlatformFile(file, offset, buffer_.get(), bytes_to_read_);
  }

  void Reply(const FileUtilProxy::ReadCallback& callback) {
    if (!callback.is_null()) {
      File::Error error =
          (bytes_read_ < 0) ? File::FILE_ERROR_FAILED : File::FILE_OK;
      callback.Run(error, buffer_.get(), bytes_read_);
    }
  }

 private:
  scoped_ptr<char[]> buffer_;
  int bytes_to_read_;
  int bytes_read_;
  DISALLOW_COPY_AND_ASSIGN(ReadHelper);
};

class WriteHelper {
 public:
  WriteHelper(const char* buffer, int bytes_to_write)
      : buffer_(new char[bytes_to_write]),
        bytes_to_write_(bytes_to_write),
        bytes_written_(0) {
    memcpy(buffer_.get(), buffer, bytes_to_write);
  }

  void RunWork(PlatformFile file, int64 offset) {
    bytes_written_ = WritePlatformFile(file, offset, buffer_.get(),
                                       bytes_to_write_);
  }

  void Reply(const FileUtilProxy::WriteCallback& callback) {
    if (!callback.is_null()) {
      File::Error error =
          (bytes_written_ < 0) ? File::FILE_ERROR_FAILED : File::FILE_OK;
      callback.Run(error, bytes_written_);
    }
  }

 private:
  scoped_ptr<char[]> buffer_;
  int bytes_to_write_;
  int bytes_written_;
  DISALLOW_COPY_AND_ASSIGN(WriteHelper);
};

File::Error CreateOrOpenAdapter(
    const FilePath& file_path, int file_flags,
    PlatformFile* file_handle, bool* created) {
  DCHECK(file_handle);
  DCHECK(created);
  if (!DirectoryExists(file_path.DirName())) {
    // If its parent does not exist, should return NOT_FOUND error.
    return File::FILE_ERROR_NOT_FOUND;
  }
  File::Error error = File::FILE_OK;
  *file_handle =
      CreatePlatformFile(file_path, file_flags, created,
                         reinterpret_cast<PlatformFileError*>(&error));
  return error;
}

File::Error CloseAdapter(PlatformFile file_handle) {
  if (!ClosePlatformFile(file_handle)) {
    return File::FILE_ERROR_FAILED;
  }
  return File::FILE_OK;
}

File::Error DeleteAdapter(const FilePath& file_path, bool recursive) {
  if (!PathExists(file_path)) {
    return File::FILE_ERROR_NOT_FOUND;
  }
  if (!base::DeleteFile(file_path, recursive)) {
    if (!recursive && !base::IsDirectoryEmpty(file_path)) {
      return File::FILE_ERROR_NOT_EMPTY;
    }
    return File::FILE_ERROR_FAILED;
  }
  return File::FILE_OK;
}

}  // namespace

// static
bool FileUtilProxy::CreateOrOpen(
    TaskRunner* task_runner,
    const FilePath& file_path, int file_flags,
    const CreateOrOpenCallback& callback) {
  return RelayCreateOrOpen(
      task_runner,
      base::Bind(&CreateOrOpenAdapter, file_path, file_flags),
      base::Bind(&CloseAdapter),
      callback);
}

// static
bool FileUtilProxy::CreateTemporary(
    TaskRunner* task_runner,
    int additional_file_flags,
    const CreateTemporaryCallback& callback) {
  CreateTemporaryHelper* helper = new CreateTemporaryHelper(task_runner);
  return task_runner->PostTaskAndReply(
      FROM_HERE,
      Bind(&CreateTemporaryHelper::RunWork, Unretained(helper),
           additional_file_flags),
      Bind(&CreateTemporaryHelper::Reply, Owned(helper), callback));
}

// static
bool FileUtilProxy::Close(
    TaskRunner* task_runner,
    base::PlatformFile file_handle,
    const StatusCallback& callback) {
  return RelayClose(
      task_runner,
      base::Bind(&CloseAdapter),
      file_handle, callback);
}

// Retrieves the information about a file. It is invalid to pass NULL for the
// callback.
bool FileUtilProxy::GetFileInfo(
    TaskRunner* task_runner,
    const FilePath& file_path,
    const GetFileInfoCallback& callback) {
  GetFileInfoHelper* helper = new GetFileInfoHelper;
  return task_runner->PostTaskAndReply(
      FROM_HERE,
      Bind(&GetFileInfoHelper::RunWorkForFilePath,
           Unretained(helper), file_path),
      Bind(&GetFileInfoHelper::Reply, Owned(helper), callback));
}

// static
bool FileUtilProxy::GetFileInfoFromPlatformFile(
    TaskRunner* task_runner,
    PlatformFile file,
    const GetFileInfoCallback& callback) {
  GetFileInfoHelper* helper = new GetFileInfoHelper;
  return task_runner->PostTaskAndReply(
      FROM_HERE,
      Bind(&GetFileInfoHelper::RunWorkForPlatformFile,
           Unretained(helper), file),
      Bind(&GetFileInfoHelper::Reply, Owned(helper), callback));
}

// static
bool FileUtilProxy::DeleteFile(TaskRunner* task_runner,
                               const FilePath& file_path,
                               bool recursive,
                               const StatusCallback& callback) {
  return base::PostTaskAndReplyWithResult(
      task_runner, FROM_HERE,
      Bind(&DeleteAdapter, file_path, recursive),
      callback);
}

// static
bool FileUtilProxy::Read(
    TaskRunner* task_runner,
    PlatformFile file,
    int64 offset,
    int bytes_to_read,
    const ReadCallback& callback) {
  if (bytes_to_read < 0) {
    return false;
  }
  ReadHelper* helper = new ReadHelper(bytes_to_read);
  return task_runner->PostTaskAndReply(
      FROM_HERE,
      Bind(&ReadHelper::RunWork, Unretained(helper), file, offset),
      Bind(&ReadHelper::Reply, Owned(helper), callback));
}

// static
bool FileUtilProxy::Write(
    TaskRunner* task_runner,
    PlatformFile file,
    int64 offset,
    const char* buffer,
    int bytes_to_write,
    const WriteCallback& callback) {
  if (bytes_to_write <= 0 || buffer == NULL) {
    return false;
  }
  WriteHelper* helper = new WriteHelper(buffer, bytes_to_write);
  return task_runner->PostTaskAndReply(
      FROM_HERE,
      Bind(&WriteHelper::RunWork, Unretained(helper), file, offset),
      Bind(&WriteHelper::Reply, Owned(helper), callback));
}

// static
bool FileUtilProxy::Touch(
    TaskRunner* task_runner,
    PlatformFile file,
    const Time& last_access_time,
    const Time& last_modified_time,
    const StatusCallback& callback) {
  return base::PostTaskAndReplyWithResult(
      task_runner,
      FROM_HERE,
      Bind(&TouchPlatformFile, file,
           last_access_time, last_modified_time),
      Bind(&CallWithTranslatedParameter, callback));
}

// static
bool FileUtilProxy::Touch(
    TaskRunner* task_runner,
    const FilePath& file_path,
    const Time& last_access_time,
    const Time& last_modified_time,
    const StatusCallback& callback) {
  return base::PostTaskAndReplyWithResult(
      task_runner,
      FROM_HERE,
      Bind(&TouchFile, file_path, last_access_time, last_modified_time),
      Bind(&CallWithTranslatedParameter, callback));
}

// static
bool FileUtilProxy::Truncate(
    TaskRunner* task_runner,
    PlatformFile file,
    int64 length,
    const StatusCallback& callback) {
  return base::PostTaskAndReplyWithResult(
      task_runner,
      FROM_HERE,
      Bind(&TruncatePlatformFile, file, length),
      Bind(&CallWithTranslatedParameter, callback));
}

// static
bool FileUtilProxy::Flush(
    TaskRunner* task_runner,
    PlatformFile file,
    const StatusCallback& callback) {
  return base::PostTaskAndReplyWithResult(
      task_runner,
      FROM_HERE,
      Bind(&FlushPlatformFile, file),
      Bind(&CallWithTranslatedParameter, callback));
}

// static
bool FileUtilProxy::RelayCreateOrOpen(
    TaskRunner* task_runner,
    const CreateOrOpenTask& open_task,
    const CloseTask& close_task,
    const CreateOrOpenCallback& callback) {
  CreateOrOpenHelper* helper = new CreateOrOpenHelper(
      task_runner, close_task);
  return task_runner->PostTaskAndReply(
      FROM_HERE,
      Bind(&CreateOrOpenHelper::RunWork, Unretained(helper), open_task),
      Bind(&CreateOrOpenHelper::Reply, Owned(helper), callback));
}

// static
bool FileUtilProxy::RelayClose(
    TaskRunner* task_runner,
    const CloseTask& close_task,
    PlatformFile file_handle,
    const StatusCallback& callback) {
  return base::PostTaskAndReplyWithResult(
      task_runner, FROM_HERE, Bind(close_task, file_handle), callback);
}

}  // namespace base

/* [<][>][^][v][top][bottom][index][help] */