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 "storage/browser/fileapi/local_file_util.h"
      6 
      7 #include "base/files/file_enumerator.h"
      8 #include "base/files/file_util.h"
      9 #include "base/files/file_util_proxy.h"
     10 #include "storage/browser/fileapi/async_file_util_adapter.h"
     11 #include "storage/browser/fileapi/file_system_context.h"
     12 #include "storage/browser/fileapi/file_system_operation_context.h"
     13 #include "storage/browser/fileapi/file_system_url.h"
     14 #include "storage/browser/fileapi/native_file_util.h"
     15 #include "storage/common/fileapi/file_system_types.h"
     16 #include "storage/common/fileapi/file_system_util.h"
     17 #include "url/gurl.h"
     18 
     19 namespace storage {
     20 
     21 AsyncFileUtil* AsyncFileUtil::CreateForLocalFileSystem() {
     22   return new AsyncFileUtilAdapter(new LocalFileUtil());
     23 }
     24 
     25 class LocalFileEnumerator : public FileSystemFileUtil::AbstractFileEnumerator {
     26  public:
     27   LocalFileEnumerator(const base::FilePath& platform_root_path,
     28                       const base::FilePath& virtual_root_path,
     29                       int file_type)
     30       : file_enum_(platform_root_path, false /* recursive */, file_type),
     31         platform_root_path_(platform_root_path),
     32         virtual_root_path_(virtual_root_path) {
     33   }
     34 
     35   virtual ~LocalFileEnumerator() {}
     36 
     37   virtual base::FilePath Next() OVERRIDE;
     38   virtual int64 Size() OVERRIDE;
     39   virtual base::Time LastModifiedTime() OVERRIDE;
     40   virtual bool IsDirectory() OVERRIDE;
     41 
     42  private:
     43   base::FileEnumerator file_enum_;
     44   base::FileEnumerator::FileInfo file_util_info_;
     45   base::FilePath platform_root_path_;
     46   base::FilePath virtual_root_path_;
     47 };
     48 
     49 base::FilePath LocalFileEnumerator::Next() {
     50   base::FilePath next = file_enum_.Next();
     51   // Don't return symlinks.
     52   while (!next.empty() && base::IsLink(next))
     53     next = file_enum_.Next();
     54   if (next.empty())
     55     return next;
     56   file_util_info_ = file_enum_.GetInfo();
     57 
     58   base::FilePath path;
     59   platform_root_path_.AppendRelativePath(next, &path);
     60   return virtual_root_path_.Append(path);
     61 }
     62 
     63 int64 LocalFileEnumerator::Size() {
     64   return file_util_info_.GetSize();
     65 }
     66 
     67 base::Time LocalFileEnumerator::LastModifiedTime() {
     68   return file_util_info_.GetLastModifiedTime();
     69 }
     70 
     71 bool LocalFileEnumerator::IsDirectory() {
     72   return file_util_info_.IsDirectory();
     73 }
     74 
     75 LocalFileUtil::LocalFileUtil() {}
     76 
     77 LocalFileUtil::~LocalFileUtil() {}
     78 
     79 base::File LocalFileUtil::CreateOrOpen(
     80     FileSystemOperationContext* context,
     81     const FileSystemURL& url, int file_flags) {
     82   base::FilePath file_path;
     83   base::File::Error error = GetLocalFilePath(context, url, &file_path);
     84   if (error != base::File::FILE_OK)
     85     return base::File(error);
     86   // Disallow opening files in symlinked paths.
     87   if (base::IsLink(file_path))
     88     return base::File(base::File::FILE_ERROR_NOT_FOUND);
     89 
     90   return NativeFileUtil::CreateOrOpen(file_path, file_flags);
     91 }
     92 
     93 base::File::Error LocalFileUtil::EnsureFileExists(
     94     FileSystemOperationContext* context,
     95     const FileSystemURL& url,
     96     bool* created) {
     97   base::FilePath file_path;
     98   base::File::Error error = GetLocalFilePath(context, url, &file_path);
     99   if (error != base::File::FILE_OK)
    100     return error;
    101   return NativeFileUtil::EnsureFileExists(file_path, created);
    102 }
    103 
    104 base::File::Error LocalFileUtil::CreateDirectory(
    105     FileSystemOperationContext* context,
    106     const FileSystemURL& url,
    107     bool exclusive,
    108     bool recursive) {
    109   base::FilePath file_path;
    110   base::File::Error error = GetLocalFilePath(context, url, &file_path);
    111   if (error != base::File::FILE_OK)
    112     return error;
    113   return NativeFileUtil::CreateDirectory(file_path, exclusive, recursive);
    114 }
    115 
    116 base::File::Error LocalFileUtil::GetFileInfo(
    117     FileSystemOperationContext* context,
    118     const FileSystemURL& url,
    119     base::File::Info* file_info,
    120     base::FilePath* platform_file_path) {
    121   base::FilePath file_path;
    122   base::File::Error error = GetLocalFilePath(context, url, &file_path);
    123   if (error != base::File::FILE_OK)
    124     return error;
    125   // We should not follow symbolic links in sandboxed file system.
    126   if (base::IsLink(file_path))
    127     return base::File::FILE_ERROR_NOT_FOUND;
    128 
    129   error = NativeFileUtil::GetFileInfo(file_path, file_info);
    130   if (error == base::File::FILE_OK)
    131     *platform_file_path = file_path;
    132   return error;
    133 }
    134 
    135 scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator> LocalFileUtil::
    136     CreateFileEnumerator(
    137         FileSystemOperationContext* context,
    138         const FileSystemURL& root_url) {
    139   base::FilePath file_path;
    140   if (GetLocalFilePath(context, root_url, &file_path) !=
    141       base::File::FILE_OK) {
    142     return make_scoped_ptr(new EmptyFileEnumerator)
    143         .PassAs<FileSystemFileUtil::AbstractFileEnumerator>();
    144   }
    145   return make_scoped_ptr(new LocalFileEnumerator(
    146       file_path, root_url.path(),
    147       base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES))
    148       .PassAs<FileSystemFileUtil::AbstractFileEnumerator>();
    149 }
    150 
    151 base::File::Error LocalFileUtil::GetLocalFilePath(
    152     FileSystemOperationContext* context,
    153     const FileSystemURL& url,
    154     base::FilePath* local_file_path) {
    155   DCHECK(local_file_path);
    156   DCHECK(url.is_valid());
    157   if (url.path().empty()) {
    158     // Root direcory case, which should not be accessed.
    159     return base::File::FILE_ERROR_ACCESS_DENIED;
    160   }
    161   *local_file_path = url.path();
    162   return base::File::FILE_OK;
    163 }
    164 
    165 base::File::Error LocalFileUtil::Touch(
    166     FileSystemOperationContext* context,
    167     const FileSystemURL& url,
    168     const base::Time& last_access_time,
    169     const base::Time& last_modified_time) {
    170   base::FilePath file_path;
    171   base::File::Error error = GetLocalFilePath(context, url, &file_path);
    172   if (error != base::File::FILE_OK)
    173     return error;
    174   return NativeFileUtil::Touch(file_path, last_access_time, last_modified_time);
    175 }
    176 
    177 base::File::Error LocalFileUtil::Truncate(
    178     FileSystemOperationContext* context,
    179     const FileSystemURL& url,
    180     int64 length) {
    181   base::FilePath file_path;
    182   base::File::Error error = GetLocalFilePath(context, url, &file_path);
    183   if (error != base::File::FILE_OK)
    184     return error;
    185   return NativeFileUtil::Truncate(file_path, length);
    186 }
    187 
    188 base::File::Error LocalFileUtil::CopyOrMoveFile(
    189     FileSystemOperationContext* context,
    190     const FileSystemURL& src_url,
    191     const FileSystemURL& dest_url,
    192     CopyOrMoveOption option,
    193     bool copy) {
    194   base::FilePath src_file_path;
    195   base::File::Error error = GetLocalFilePath(context, src_url, &src_file_path);
    196   if (error != base::File::FILE_OK)
    197     return error;
    198 
    199   base::FilePath dest_file_path;
    200   error = GetLocalFilePath(context, dest_url, &dest_file_path);
    201   if (error != base::File::FILE_OK)
    202     return error;
    203 
    204   return NativeFileUtil::CopyOrMoveFile(
    205       src_file_path,
    206       dest_file_path,
    207       option,
    208       storage::NativeFileUtil::CopyOrMoveModeForDestination(dest_url, copy));
    209 }
    210 
    211 base::File::Error LocalFileUtil::CopyInForeignFile(
    212     FileSystemOperationContext* context,
    213     const base::FilePath& src_file_path,
    214     const FileSystemURL& dest_url) {
    215   if (src_file_path.empty())
    216     return base::File::FILE_ERROR_INVALID_OPERATION;
    217 
    218   base::FilePath dest_file_path;
    219   base::File::Error error =
    220       GetLocalFilePath(context, dest_url, &dest_file_path);
    221   if (error != base::File::FILE_OK)
    222     return error;
    223   return NativeFileUtil::CopyOrMoveFile(
    224       src_file_path,
    225       dest_file_path,
    226       FileSystemOperation::OPTION_NONE,
    227       storage::NativeFileUtil::CopyOrMoveModeForDestination(dest_url,
    228                                                             true /* copy */));
    229 }
    230 
    231 base::File::Error LocalFileUtil::DeleteFile(
    232     FileSystemOperationContext* context,
    233     const FileSystemURL& url) {
    234   base::FilePath file_path;
    235   base::File::Error error = GetLocalFilePath(context, url, &file_path);
    236   if (error != base::File::FILE_OK)
    237     return error;
    238   return NativeFileUtil::DeleteFile(file_path);
    239 }
    240 
    241 base::File::Error LocalFileUtil::DeleteDirectory(
    242     FileSystemOperationContext* context,
    243     const FileSystemURL& url) {
    244   base::FilePath file_path;
    245   base::File::Error error = GetLocalFilePath(context, url, &file_path);
    246   if (error != base::File::FILE_OK)
    247     return error;
    248   return NativeFileUtil::DeleteDirectory(file_path);
    249 }
    250 
    251 storage::ScopedFile LocalFileUtil::CreateSnapshotFile(
    252     FileSystemOperationContext* context,
    253     const FileSystemURL& url,
    254     base::File::Error* error,
    255     base::File::Info* file_info,
    256     base::FilePath* platform_path) {
    257   DCHECK(file_info);
    258   // We're just returning the local file information.
    259   *error = GetFileInfo(context, url, file_info, platform_path);
    260   if (*error == base::File::FILE_OK && file_info->is_directory)
    261     *error = base::File::FILE_ERROR_NOT_A_FILE;
    262   return storage::ScopedFile();
    263 }
    264 
    265 }  // namespace storage
    266