Home | History | Annotate | Download | only in pepper
      1 // Copyright 2013 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 "content/browser/renderer_host/pepper/pepper_internal_file_ref_backend.h"
      6 
      7 #include <string>
      8 
      9 #include "base/callback.h"
     10 #include "base/file_util.h"
     11 #include "base/files/file_util_proxy.h"
     12 #include "content/browser/child_process_security_policy_impl.h"
     13 #include "content/browser/fileapi/browser_file_system_helper.h"
     14 #include "content/browser/renderer_host/pepper/pepper_file_system_browser_host.h"
     15 #include "content/public/browser/browser_context.h"
     16 #include "content/public/browser/browser_thread.h"
     17 #include "content/public/browser/render_process_host.h"
     18 #include "content/public/browser/storage_partition.h"
     19 #include "net/base/escape.h"
     20 #include "ppapi/c/pp_errors.h"
     21 #include "ppapi/c/pp_file_info.h"
     22 #include "ppapi/c/pp_instance.h"
     23 #include "ppapi/c/pp_resource.h"
     24 #include "ppapi/host/dispatch_host_message.h"
     25 #include "ppapi/host/ppapi_host.h"
     26 #include "ppapi/proxy/ppapi_messages.h"
     27 #include "ppapi/shared_impl/file_ref_create_info.h"
     28 #include "ppapi/shared_impl/file_ref_util.h"
     29 #include "ppapi/shared_impl/file_type_conversion.h"
     30 #include "ppapi/shared_impl/scoped_pp_var.h"
     31 #include "ppapi/shared_impl/time_conversion.h"
     32 #include "ppapi/shared_impl/var.h"
     33 #include "ppapi/thunk/enter.h"
     34 #include "ppapi/thunk/ppb_file_ref_api.h"
     35 #include "ppapi/thunk/ppb_file_system_api.h"
     36 #include "webkit/browser/fileapi/file_system_operation.h"
     37 #include "webkit/browser/fileapi/file_system_operation_runner.h"
     38 #include "webkit/browser/fileapi/file_system_url.h"
     39 #include "webkit/common/fileapi/file_system_util.h"
     40 
     41 using ppapi::host::PpapiHost;
     42 using ppapi::host::ResourceHost;
     43 
     44 namespace content {
     45 
     46 PepperInternalFileRefBackend::PepperInternalFileRefBackend(
     47     PpapiHost* host,
     48     int render_process_id,
     49     base::WeakPtr<PepperFileSystemBrowserHost> fs_host,
     50     const std::string& path) : host_(host),
     51                                render_process_id_(render_process_id),
     52                                fs_host_(fs_host),
     53                                fs_type_(fs_host->GetType()),
     54                                path_(path),
     55                                weak_factory_(this) {
     56   ppapi::NormalizeInternalPath(&path_);
     57 }
     58 
     59 PepperInternalFileRefBackend::~PepperInternalFileRefBackend() {
     60 }
     61 
     62 fileapi::FileSystemURL PepperInternalFileRefBackend::GetFileSystemURL() const {
     63   if (!fs_url_.is_valid() && fs_host_.get() && fs_host_->IsOpened()) {
     64     GURL fs_path = fs_host_->GetRootUrl().Resolve(
     65         net::EscapePath(path_.substr(1)));
     66     fs_url_ = GetFileSystemContext()->CrackURL(fs_path);
     67   }
     68   return fs_url_;
     69 }
     70 
     71 std::string PepperInternalFileRefBackend::GetFileSystemURLSpec() const {
     72   if (fs_host_.get() && fs_host_->IsOpened() &&
     73       fs_host_->GetRootUrl().is_valid()) {
     74     return fs_host_->GetRootUrl().Resolve(
     75         net::EscapePath(path_.substr(1))).spec();
     76   }
     77   return std::string();
     78 }
     79 
     80 base::FilePath PepperInternalFileRefBackend::GetExternalPath() const {
     81   return base::FilePath();
     82 }
     83 
     84 scoped_refptr<fileapi::FileSystemContext>
     85 PepperInternalFileRefBackend::GetFileSystemContext() const {
     86   // TODO(teravest): Make this work for CRX file systems.
     87   if (!fs_host_.get())
     88     return NULL;
     89   return fs_host_->GetFileSystemContext();
     90 }
     91 
     92 void PepperInternalFileRefBackend::DidFinish(
     93     ppapi::host::ReplyMessageContext context,
     94     const IPC::Message& msg,
     95     base::PlatformFileError error) {
     96   context.params.set_result(ppapi::PlatformFileErrorToPepperError(error));
     97   host_->SendReply(context, msg);
     98 }
     99 
    100 int32_t PepperInternalFileRefBackend::MakeDirectory(
    101     ppapi::host::ReplyMessageContext reply_context,
    102     bool make_ancestors) {
    103   if (!GetFileSystemURL().is_valid())
    104     return PP_ERROR_FAILED;
    105 
    106   GetFileSystemContext()->operation_runner()->CreateDirectory(
    107       GetFileSystemURL(),
    108       false,
    109       make_ancestors,
    110       base::Bind(&PepperInternalFileRefBackend::DidFinish,
    111                  weak_factory_.GetWeakPtr(),
    112                  reply_context,
    113                  PpapiPluginMsg_FileRef_MakeDirectoryReply()));
    114   return PP_OK_COMPLETIONPENDING;
    115 }
    116 
    117 int32_t PepperInternalFileRefBackend::Touch(
    118     ppapi::host::ReplyMessageContext reply_context,
    119     PP_Time last_access_time,
    120     PP_Time last_modified_time) {
    121   if (!GetFileSystemURL().is_valid())
    122     return PP_ERROR_FAILED;
    123 
    124   GetFileSystemContext()->operation_runner()->TouchFile(
    125       GetFileSystemURL(),
    126       ppapi::PPTimeToTime(last_access_time),
    127       ppapi::PPTimeToTime(last_modified_time),
    128       base::Bind(&PepperInternalFileRefBackend::DidFinish,
    129                  weak_factory_.GetWeakPtr(),
    130                  reply_context,
    131                  PpapiPluginMsg_FileRef_TouchReply()));
    132   return PP_OK_COMPLETIONPENDING;
    133 }
    134 
    135 int32_t PepperInternalFileRefBackend::Delete(
    136     ppapi::host::ReplyMessageContext reply_context) {
    137   if (!GetFileSystemURL().is_valid())
    138     return PP_ERROR_FAILED;
    139 
    140   GetFileSystemContext()->operation_runner()->Remove(
    141       GetFileSystemURL(),
    142       false,
    143       base::Bind(&PepperInternalFileRefBackend::DidFinish,
    144                  weak_factory_.GetWeakPtr(),
    145                  reply_context,
    146                  PpapiPluginMsg_FileRef_DeleteReply()));
    147   return PP_OK_COMPLETIONPENDING;
    148 }
    149 
    150 int32_t PepperInternalFileRefBackend::Rename(
    151     ppapi::host::ReplyMessageContext reply_context,
    152     PepperFileRefHost* new_file_ref) {
    153   if (!GetFileSystemURL().is_valid())
    154     return PP_ERROR_FAILED;
    155 
    156   fileapi::FileSystemURL new_url = new_file_ref->GetFileSystemURL();
    157   if (!new_url.is_valid())
    158     return PP_ERROR_FAILED;
    159   if (!new_url.IsInSameFileSystem(GetFileSystemURL()))
    160     return PP_ERROR_FAILED;
    161 
    162   GetFileSystemContext()->operation_runner()->Move(
    163       GetFileSystemURL(),
    164       new_url,
    165       base::Bind(&PepperInternalFileRefBackend::DidFinish,
    166                  weak_factory_.GetWeakPtr(),
    167                  reply_context,
    168                  PpapiPluginMsg_FileRef_RenameReply()));
    169   return PP_OK_COMPLETIONPENDING;
    170 }
    171 
    172 int32_t PepperInternalFileRefBackend::Query(
    173     ppapi::host::ReplyMessageContext reply_context) {
    174   if (!GetFileSystemURL().is_valid())
    175     return PP_ERROR_FAILED;
    176 
    177   GetFileSystemContext()->operation_runner()->GetMetadata(
    178       GetFileSystemURL(),
    179       base::Bind(&PepperInternalFileRefBackend::GetMetadataComplete,
    180                  weak_factory_.GetWeakPtr(),
    181                  reply_context));
    182   return PP_OK_COMPLETIONPENDING;
    183 }
    184 
    185 void PepperInternalFileRefBackend::GetMetadataComplete(
    186     ppapi::host::ReplyMessageContext reply_context,
    187     base::PlatformFileError error,
    188     const base::PlatformFileInfo& file_info) {
    189   reply_context.params.set_result(ppapi::PlatformFileErrorToPepperError(error));
    190 
    191   PP_FileInfo pp_file_info;
    192   if (error == base::PLATFORM_FILE_OK)
    193     ppapi::PlatformFileInfoToPepperFileInfo(file_info, fs_type_, &pp_file_info);
    194   else
    195     memset(&pp_file_info, 0, sizeof(pp_file_info));
    196 
    197   host_->SendReply(reply_context,
    198                    PpapiPluginMsg_FileRef_QueryReply(pp_file_info));
    199 }
    200 
    201 int32_t PepperInternalFileRefBackend::ReadDirectoryEntries(
    202     ppapi::host::ReplyMessageContext reply_context) {
    203   if (!GetFileSystemURL().is_valid())
    204     return PP_ERROR_FAILED;
    205 
    206   GetFileSystemContext()->operation_runner()->ReadDirectory(
    207       GetFileSystemURL(),
    208       base::Bind(&PepperInternalFileRefBackend::ReadDirectoryComplete,
    209                  weak_factory_.GetWeakPtr(),
    210                  reply_context));
    211   return PP_OK_COMPLETIONPENDING;
    212 }
    213 
    214 void PepperInternalFileRefBackend::ReadDirectoryComplete(
    215     ppapi::host::ReplyMessageContext context,
    216     base::PlatformFileError error,
    217     const fileapi::FileSystemOperation::FileEntryList& file_list,
    218     bool has_more) {
    219   // The current filesystem backend always returns false.
    220   DCHECK(!has_more);
    221 
    222   context.params.set_result(ppapi::PlatformFileErrorToPepperError(error));
    223 
    224   std::vector<ppapi::FileRef_CreateInfo> infos;
    225   std::vector<PP_FileType> file_types;
    226   if (error == base::PLATFORM_FILE_OK && fs_host_.get()) {
    227     std::string dir_path = path_;
    228     if (dir_path.empty() || dir_path[dir_path.size() - 1] != '/')
    229       dir_path += '/';
    230 
    231     for (fileapi::FileSystemOperation::FileEntryList::const_iterator it =
    232          file_list.begin(); it != file_list.end(); ++it) {
    233       if (it->is_directory)
    234         file_types.push_back(PP_FILETYPE_DIRECTORY);
    235       else
    236         file_types.push_back(PP_FILETYPE_REGULAR);
    237 
    238       ppapi::FileRef_CreateInfo info;
    239       info.file_system_type = fs_type_;
    240       info.file_system_plugin_resource = fs_host_->pp_resource();
    241       std::string path =
    242           dir_path + fileapi::FilePathToString(base::FilePath(it->name));
    243       info.internal_path = path;
    244       info.display_name = ppapi::GetNameForInternalFilePath(path);
    245       infos.push_back(info);
    246     }
    247   }
    248 
    249   host_->SendReply(context,
    250       PpapiPluginMsg_FileRef_ReadDirectoryEntriesReply(infos, file_types));
    251 }
    252 
    253 int32_t PepperInternalFileRefBackend::GetAbsolutePath(
    254     ppapi::host::ReplyMessageContext reply_context) {
    255   host_->SendReply(reply_context,
    256       PpapiPluginMsg_FileRef_GetAbsolutePathReply(path_));
    257   return PP_OK_COMPLETIONPENDING;
    258 }
    259 
    260 int32_t PepperInternalFileRefBackend::CanRead() const {
    261   fileapi::FileSystemURL url = GetFileSystemURL();
    262   if (!FileSystemURLIsValid(GetFileSystemContext().get(), url))
    263     return PP_ERROR_FAILED;
    264   if (!ChildProcessSecurityPolicyImpl::GetInstance()->
    265           CanReadFileSystemFile(render_process_id_, url)) {
    266     return PP_ERROR_NOACCESS;
    267   }
    268   return PP_OK;
    269 }
    270 
    271 int32_t PepperInternalFileRefBackend::CanWrite() const {
    272   fileapi::FileSystemURL url = GetFileSystemURL();
    273   if (!FileSystemURLIsValid(GetFileSystemContext().get(), url))
    274     return PP_ERROR_FAILED;
    275   if (!ChildProcessSecurityPolicyImpl::GetInstance()->
    276           CanWriteFileSystemFile(render_process_id_, url)) {
    277     return PP_ERROR_NOACCESS;
    278   }
    279   return PP_OK;
    280 }
    281 
    282 int32_t PepperInternalFileRefBackend::CanCreate() const {
    283   fileapi::FileSystemURL url = GetFileSystemURL();
    284   if (!FileSystemURLIsValid(GetFileSystemContext().get(), url))
    285     return PP_ERROR_FAILED;
    286   if (!ChildProcessSecurityPolicyImpl::GetInstance()->
    287           CanCreateFileSystemFile(render_process_id_, url)) {
    288     return PP_ERROR_NOACCESS;
    289   }
    290   return PP_OK;
    291 }
    292 
    293 int32_t PepperInternalFileRefBackend::CanReadWrite() const {
    294   fileapi::FileSystemURL url = GetFileSystemURL();
    295   if (!FileSystemURLIsValid(GetFileSystemContext().get(), url))
    296     return PP_ERROR_FAILED;
    297   ChildProcessSecurityPolicyImpl* policy =
    298       ChildProcessSecurityPolicyImpl::GetInstance();
    299   if (!policy->CanReadFileSystemFile(render_process_id_, url) ||
    300       !policy->CanWriteFileSystemFile(render_process_id_, url)) {
    301     return PP_ERROR_NOACCESS;
    302   }
    303   return PP_OK;
    304 }
    305 
    306 }  // namespace content
    307