Home | History | Annotate | Download | only in fileapi
      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 "webkit/browser/fileapi/native_file_util.h"
      6 
      7 #include "base/file_util.h"
      8 #include "base/files/file_enumerator.h"
      9 #include "base/memory/scoped_ptr.h"
     10 #include "webkit/browser/fileapi/file_system_operation_context.h"
     11 
     12 namespace fileapi {
     13 
     14 namespace {
     15 
     16 // Sets permissions on directory at |dir_path| based on the target platform.
     17 // Returns true on success, or false otherwise.
     18 //
     19 // TODO(benchan): Find a better place outside webkit to host this function.
     20 bool SetPlatformSpecificDirectoryPermissions(const base::FilePath& dir_path) {
     21 #if defined(OS_CHROMEOS)
     22     // System daemons on Chrome OS may run as a user different than the Chrome
     23     // process but need to access files under the directories created here.
     24     // Because of that, grant the execute permission on the created directory
     25     // to group and other users.
     26     if (HANDLE_EINTR(chmod(dir_path.value().c_str(),
     27                            S_IRWXU | S_IXGRP | S_IXOTH)) != 0) {
     28       return false;
     29     }
     30 #endif
     31     // Keep the directory permissions unchanged on non-Chrome OS platforms.
     32     return true;
     33 }
     34 
     35 }  // namespace
     36 
     37 using base::PlatformFile;
     38 using base::PlatformFileError;
     39 
     40 class NativeFileEnumerator : public FileSystemFileUtil::AbstractFileEnumerator {
     41  public:
     42   NativeFileEnumerator(const base::FilePath& root_path,
     43                        bool recursive,
     44                        int file_type)
     45     : file_enum_(root_path, recursive, file_type) {
     46   }
     47 
     48   virtual ~NativeFileEnumerator() {}
     49 
     50   virtual base::FilePath Next() OVERRIDE;
     51   virtual int64 Size() OVERRIDE;
     52   virtual base::Time LastModifiedTime() OVERRIDE;
     53   virtual bool IsDirectory() OVERRIDE;
     54 
     55  private:
     56   base::FileEnumerator file_enum_;
     57   base::FileEnumerator::FileInfo file_util_info_;
     58 };
     59 
     60 base::FilePath NativeFileEnumerator::Next() {
     61   base::FilePath rv = file_enum_.Next();
     62   if (!rv.empty())
     63     file_util_info_ = file_enum_.GetInfo();
     64   return rv;
     65 }
     66 
     67 int64 NativeFileEnumerator::Size() {
     68   return file_util_info_.GetSize();
     69 }
     70 
     71 base::Time NativeFileEnumerator::LastModifiedTime() {
     72   return file_util_info_.GetLastModifiedTime();
     73 }
     74 
     75 bool NativeFileEnumerator::IsDirectory() {
     76   return file_util_info_.IsDirectory();
     77 }
     78 
     79 PlatformFileError NativeFileUtil::CreateOrOpen(
     80     const base::FilePath& path, int file_flags,
     81     PlatformFile* file_handle, bool* created) {
     82   if (!base::DirectoryExists(path.DirName())) {
     83     // If its parent does not exist, should return NOT_FOUND error.
     84     return base::PLATFORM_FILE_ERROR_NOT_FOUND;
     85   }
     86   if (base::DirectoryExists(path))
     87     return base::PLATFORM_FILE_ERROR_NOT_A_FILE;
     88   PlatformFileError error_code = base::PLATFORM_FILE_OK;
     89   *file_handle = base::CreatePlatformFile(path, file_flags,
     90                                           created, &error_code);
     91   return error_code;
     92 }
     93 
     94 PlatformFileError NativeFileUtil::Close(PlatformFile file_handle) {
     95   if (!base::ClosePlatformFile(file_handle))
     96     return base::PLATFORM_FILE_ERROR_FAILED;
     97   return base::PLATFORM_FILE_OK;
     98 }
     99 
    100 PlatformFileError NativeFileUtil::EnsureFileExists(
    101     const base::FilePath& path,
    102     bool* created) {
    103   if (!base::DirectoryExists(path.DirName()))
    104     // If its parent does not exist, should return NOT_FOUND error.
    105     return base::PLATFORM_FILE_ERROR_NOT_FOUND;
    106   PlatformFileError error_code = base::PLATFORM_FILE_OK;
    107   // Tries to create the |path| exclusively.  This should fail
    108   // with base::PLATFORM_FILE_ERROR_EXISTS if the path already exists.
    109   PlatformFile handle = base::CreatePlatformFile(
    110       path,
    111       base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_READ,
    112       created, &error_code);
    113   if (error_code == base::PLATFORM_FILE_ERROR_EXISTS) {
    114     // Make sure created_ is false.
    115     if (created)
    116       *created = false;
    117     error_code = base::PLATFORM_FILE_OK;
    118   }
    119   if (handle != base::kInvalidPlatformFileValue)
    120     base::ClosePlatformFile(handle);
    121   return error_code;
    122 }
    123 
    124 PlatformFileError NativeFileUtil::CreateDirectory(
    125     const base::FilePath& path,
    126     bool exclusive,
    127     bool recursive) {
    128   // If parent dir of file doesn't exist.
    129   if (!recursive && !base::PathExists(path.DirName()))
    130     return base::PLATFORM_FILE_ERROR_NOT_FOUND;
    131 
    132   bool path_exists = base::PathExists(path);
    133   if (exclusive && path_exists)
    134     return base::PLATFORM_FILE_ERROR_EXISTS;
    135 
    136   // If file exists at the path.
    137   if (path_exists && !base::DirectoryExists(path))
    138     return base::PLATFORM_FILE_ERROR_EXISTS;
    139 
    140   if (!file_util::CreateDirectory(path))
    141     return base::PLATFORM_FILE_ERROR_FAILED;
    142 
    143   if (!SetPlatformSpecificDirectoryPermissions(path))
    144     return base::PLATFORM_FILE_ERROR_FAILED;
    145 
    146   return base::PLATFORM_FILE_OK;
    147 }
    148 
    149 PlatformFileError NativeFileUtil::GetFileInfo(
    150     const base::FilePath& path,
    151     base::PlatformFileInfo* file_info) {
    152   if (!base::PathExists(path))
    153     return base::PLATFORM_FILE_ERROR_NOT_FOUND;
    154   if (!file_util::GetFileInfo(path, file_info))
    155     return base::PLATFORM_FILE_ERROR_FAILED;
    156   return base::PLATFORM_FILE_OK;
    157 }
    158 
    159 scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator>
    160     NativeFileUtil::CreateFileEnumerator(const base::FilePath& root_path,
    161                                          bool recursive) {
    162   return make_scoped_ptr(new NativeFileEnumerator(
    163       root_path, recursive,
    164       base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES))
    165       .PassAs<FileSystemFileUtil::AbstractFileEnumerator>();
    166 }
    167 
    168 PlatformFileError NativeFileUtil::Touch(
    169     const base::FilePath& path,
    170     const base::Time& last_access_time,
    171     const base::Time& last_modified_time) {
    172   if (!file_util::TouchFile(
    173           path, last_access_time, last_modified_time))
    174     return base::PLATFORM_FILE_ERROR_FAILED;
    175   return base::PLATFORM_FILE_OK;
    176 }
    177 
    178 PlatformFileError NativeFileUtil::Truncate(
    179     const base::FilePath& path, int64 length) {
    180   PlatformFileError error_code(base::PLATFORM_FILE_ERROR_FAILED);
    181   PlatformFile file =
    182       base::CreatePlatformFile(
    183           path,
    184           base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE,
    185           NULL,
    186           &error_code);
    187   if (error_code != base::PLATFORM_FILE_OK) {
    188     return error_code;
    189   }
    190   DCHECK_NE(base::kInvalidPlatformFileValue, file);
    191   if (!base::TruncatePlatformFile(file, length))
    192     error_code = base::PLATFORM_FILE_ERROR_FAILED;
    193   base::ClosePlatformFile(file);
    194   return error_code;
    195 }
    196 
    197 bool NativeFileUtil::PathExists(const base::FilePath& path) {
    198   return base::PathExists(path);
    199 }
    200 
    201 bool NativeFileUtil::DirectoryExists(const base::FilePath& path) {
    202   return base::DirectoryExists(path);
    203 }
    204 
    205 PlatformFileError NativeFileUtil::CopyOrMoveFile(
    206     const base::FilePath& src_path,
    207     const base::FilePath& dest_path,
    208     bool copy) {
    209   base::PlatformFileInfo info;
    210   base::PlatformFileError error = NativeFileUtil::GetFileInfo(src_path, &info);
    211   if (error != base::PLATFORM_FILE_OK)
    212     return error;
    213   if (info.is_directory)
    214     return base::PLATFORM_FILE_ERROR_NOT_A_FILE;
    215 
    216   error = NativeFileUtil::GetFileInfo(dest_path, &info);
    217   if (error != base::PLATFORM_FILE_OK &&
    218       error != base::PLATFORM_FILE_ERROR_NOT_FOUND)
    219     return error;
    220   if (info.is_directory)
    221     return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
    222   if (error == base::PLATFORM_FILE_ERROR_NOT_FOUND) {
    223     error = NativeFileUtil::GetFileInfo(dest_path.DirName(), &info);
    224     if (error != base::PLATFORM_FILE_OK)
    225       return error;
    226     if (!info.is_directory)
    227       return base::PLATFORM_FILE_ERROR_NOT_FOUND;
    228   }
    229 
    230   if (copy) {
    231     if (base::CopyFile(src_path, dest_path))
    232       return base::PLATFORM_FILE_OK;
    233   } else {
    234     if (base::Move(src_path, dest_path))
    235       return base::PLATFORM_FILE_OK;
    236   }
    237   return base::PLATFORM_FILE_ERROR_FAILED;
    238 }
    239 
    240 PlatformFileError NativeFileUtil::DeleteFile(const base::FilePath& path) {
    241   if (!base::PathExists(path))
    242     return base::PLATFORM_FILE_ERROR_NOT_FOUND;
    243   if (base::DirectoryExists(path))
    244     return base::PLATFORM_FILE_ERROR_NOT_A_FILE;
    245   if (!base::DeleteFile(path, false))
    246     return base::PLATFORM_FILE_ERROR_FAILED;
    247   return base::PLATFORM_FILE_OK;
    248 }
    249 
    250 PlatformFileError NativeFileUtil::DeleteDirectory(const base::FilePath& path) {
    251   if (!base::PathExists(path))
    252     return base::PLATFORM_FILE_ERROR_NOT_FOUND;
    253   if (!base::DirectoryExists(path))
    254     return base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY;
    255   if (!file_util::IsDirectoryEmpty(path))
    256     return base::PLATFORM_FILE_ERROR_NOT_EMPTY;
    257   if (!base::DeleteFile(path, false))
    258     return base::PLATFORM_FILE_ERROR_FAILED;
    259   return base::PLATFORM_FILE_OK;
    260 }
    261 
    262 }  // namespace fileapi
    263