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/files/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/render_process_host.h"
     17 #include "content/public/browser/storage_partition.h"
     18 #include "net/base/escape.h"
     19 #include "ppapi/c/pp_errors.h"
     20 #include "ppapi/c/pp_file_info.h"
     21 #include "ppapi/c/pp_instance.h"
     22 #include "ppapi/c/pp_resource.h"
     23 #include "ppapi/c/ppb_file_ref.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 "storage/browser/fileapi/file_system_operation.h"
     37 #include "storage/browser/fileapi/file_system_operation_runner.h"
     38 #include "storage/browser/fileapi/file_system_url.h"
     39 #include "storage/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)
     51     : host_(host),
     52       render_process_id_(render_process_id),
     53       fs_host_(fs_host),
     54       fs_type_(fs_host->GetType()),
     55       path_(path),
     56       weak_factory_(this) {
     57   ppapi::NormalizeInternalPath(&path_);
     58 }
     59 
     60 PepperInternalFileRefBackend::~PepperInternalFileRefBackend() {}
     61 
     62 storage::FileSystemURL PepperInternalFileRefBackend::GetFileSystemURL() const {
     63   if (!fs_url_.is_valid() && fs_host_.get() && fs_host_->IsOpened()) {
     64     GURL fs_path =
     65         fs_host_->GetRootUrl().Resolve(net::EscapePath(path_.substr(1)));
     66     scoped_refptr<storage::FileSystemContext> fs_context =
     67         GetFileSystemContext();
     68     if (fs_context.get())
     69       fs_url_ = fs_context->CrackURL(fs_path);
     70   }
     71   return fs_url_;
     72 }
     73 
     74 base::FilePath PepperInternalFileRefBackend::GetExternalFilePath() const {
     75   return base::FilePath();
     76 }
     77 
     78 scoped_refptr<storage::FileSystemContext>
     79 PepperInternalFileRefBackend::GetFileSystemContext() const {
     80   if (!fs_host_.get())
     81     return NULL;
     82   return fs_host_->GetFileSystemContext();
     83 }
     84 
     85 void PepperInternalFileRefBackend::DidFinish(
     86     ppapi::host::ReplyMessageContext context,
     87     const IPC::Message& msg,
     88     base::File::Error error) {
     89   context.params.set_result(ppapi::FileErrorToPepperError(error));
     90   host_->SendReply(context, msg);
     91 }
     92 
     93 int32_t PepperInternalFileRefBackend::MakeDirectory(
     94     ppapi::host::ReplyMessageContext reply_context,
     95     int32_t make_directory_flags) {
     96   if (!GetFileSystemURL().is_valid())
     97     return PP_ERROR_FAILED;
     98 
     99   GetFileSystemContext()->operation_runner()->CreateDirectory(
    100       GetFileSystemURL(),
    101       !!(make_directory_flags & PP_MAKEDIRECTORYFLAG_EXCLUSIVE),
    102       !!(make_directory_flags & PP_MAKEDIRECTORYFLAG_WITH_ANCESTORS),
    103       base::Bind(&PepperInternalFileRefBackend::DidFinish,
    104                  weak_factory_.GetWeakPtr(),
    105                  reply_context,
    106                  PpapiPluginMsg_FileRef_MakeDirectoryReply()));
    107   return PP_OK_COMPLETIONPENDING;
    108 }
    109 
    110 int32_t PepperInternalFileRefBackend::Touch(
    111     ppapi::host::ReplyMessageContext reply_context,
    112     PP_Time last_access_time,
    113     PP_Time last_modified_time) {
    114   if (!GetFileSystemURL().is_valid())
    115     return PP_ERROR_FAILED;
    116 
    117   GetFileSystemContext()->operation_runner()->TouchFile(
    118       GetFileSystemURL(),
    119       ppapi::PPTimeToTime(last_access_time),
    120       ppapi::PPTimeToTime(last_modified_time),
    121       base::Bind(&PepperInternalFileRefBackend::DidFinish,
    122                  weak_factory_.GetWeakPtr(),
    123                  reply_context,
    124                  PpapiPluginMsg_FileRef_TouchReply()));
    125   return PP_OK_COMPLETIONPENDING;
    126 }
    127 
    128 int32_t PepperInternalFileRefBackend::Delete(
    129     ppapi::host::ReplyMessageContext reply_context) {
    130   if (!GetFileSystemURL().is_valid())
    131     return PP_ERROR_FAILED;
    132 
    133   GetFileSystemContext()->operation_runner()->Remove(
    134       GetFileSystemURL(),
    135       false,
    136       base::Bind(&PepperInternalFileRefBackend::DidFinish,
    137                  weak_factory_.GetWeakPtr(),
    138                  reply_context,
    139                  PpapiPluginMsg_FileRef_DeleteReply()));
    140   return PP_OK_COMPLETIONPENDING;
    141 }
    142 
    143 int32_t PepperInternalFileRefBackend::Rename(
    144     ppapi::host::ReplyMessageContext reply_context,
    145     PepperFileRefHost* new_file_ref) {
    146   if (!GetFileSystemURL().is_valid())
    147     return PP_ERROR_FAILED;
    148 
    149   storage::FileSystemURL new_url = new_file_ref->GetFileSystemURL();
    150   if (!new_url.is_valid())
    151     return PP_ERROR_FAILED;
    152   if (!new_url.IsInSameFileSystem(GetFileSystemURL()))
    153     return PP_ERROR_FAILED;
    154 
    155   GetFileSystemContext()->operation_runner()->Move(
    156       GetFileSystemURL(),
    157       new_url,
    158       storage::FileSystemOperation::OPTION_NONE,
    159       base::Bind(&PepperInternalFileRefBackend::DidFinish,
    160                  weak_factory_.GetWeakPtr(),
    161                  reply_context,
    162                  PpapiPluginMsg_FileRef_RenameReply()));
    163   return PP_OK_COMPLETIONPENDING;
    164 }
    165 
    166 int32_t PepperInternalFileRefBackend::Query(
    167     ppapi::host::ReplyMessageContext reply_context) {
    168   if (!GetFileSystemURL().is_valid())
    169     return PP_ERROR_FAILED;
    170 
    171   GetFileSystemContext()->operation_runner()->GetMetadata(
    172       GetFileSystemURL(),
    173       base::Bind(&PepperInternalFileRefBackend::GetMetadataComplete,
    174                  weak_factory_.GetWeakPtr(),
    175                  reply_context));
    176   return PP_OK_COMPLETIONPENDING;
    177 }
    178 
    179 void PepperInternalFileRefBackend::GetMetadataComplete(
    180     ppapi::host::ReplyMessageContext reply_context,
    181     base::File::Error error,
    182     const base::File::Info& file_info) {
    183   reply_context.params.set_result(ppapi::FileErrorToPepperError(error));
    184 
    185   PP_FileInfo pp_file_info;
    186   if (error == base::File::FILE_OK)
    187     ppapi::FileInfoToPepperFileInfo(file_info, fs_type_, &pp_file_info);
    188   else
    189     memset(&pp_file_info, 0, sizeof(pp_file_info));
    190 
    191   host_->SendReply(reply_context,
    192                    PpapiPluginMsg_FileRef_QueryReply(pp_file_info));
    193 }
    194 
    195 int32_t PepperInternalFileRefBackend::ReadDirectoryEntries(
    196     ppapi::host::ReplyMessageContext reply_context) {
    197   if (!GetFileSystemURL().is_valid())
    198     return PP_ERROR_FAILED;
    199 
    200   storage::FileSystemOperation::FileEntryList* accumulated_file_list =
    201       new storage::FileSystemOperation::FileEntryList;
    202   GetFileSystemContext()->operation_runner()->ReadDirectory(
    203       GetFileSystemURL(),
    204       base::Bind(&PepperInternalFileRefBackend::ReadDirectoryComplete,
    205                  weak_factory_.GetWeakPtr(),
    206                  reply_context,
    207                  base::Owned(accumulated_file_list)));
    208   return PP_OK_COMPLETIONPENDING;
    209 }
    210 
    211 void PepperInternalFileRefBackend::ReadDirectoryComplete(
    212     ppapi::host::ReplyMessageContext context,
    213     storage::FileSystemOperation::FileEntryList* accumulated_file_list,
    214     base::File::Error error,
    215     const storage::FileSystemOperation::FileEntryList& file_list,
    216     bool has_more) {
    217   accumulated_file_list->insert(
    218       accumulated_file_list->end(), file_list.begin(), file_list.end());
    219   if (has_more)
    220     return;
    221 
    222   context.params.set_result(ppapi::FileErrorToPepperError(error));
    223 
    224   std::vector<ppapi::FileRefCreateInfo> infos;
    225   std::vector<PP_FileType> file_types;
    226   if (error == base::File::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 (storage::FileSystemOperation::FileEntryList::const_iterator it =
    232              accumulated_file_list->begin();
    233          it != accumulated_file_list->end();
    234          ++it) {
    235       if (it->is_directory)
    236         file_types.push_back(PP_FILETYPE_DIRECTORY);
    237       else
    238         file_types.push_back(PP_FILETYPE_REGULAR);
    239 
    240       ppapi::FileRefCreateInfo info;
    241       info.file_system_type = fs_type_;
    242       info.file_system_plugin_resource = fs_host_->pp_resource();
    243       std::string path =
    244           dir_path + storage::FilePathToString(base::FilePath(it->name));
    245       info.internal_path = path;
    246       info.display_name = ppapi::GetNameForInternalFilePath(path);
    247       infos.push_back(info);
    248     }
    249   }
    250 
    251   host_->SendReply(
    252       context,
    253       PpapiPluginMsg_FileRef_ReadDirectoryEntriesReply(infos, file_types));
    254 }
    255 
    256 int32_t PepperInternalFileRefBackend::GetAbsolutePath(
    257     ppapi::host::ReplyMessageContext reply_context) {
    258   host_->SendReply(reply_context,
    259                    PpapiPluginMsg_FileRef_GetAbsolutePathReply(path_));
    260   return PP_OK_COMPLETIONPENDING;
    261 }
    262 
    263 int32_t PepperInternalFileRefBackend::CanRead() const {
    264   storage::FileSystemURL url = GetFileSystemURL();
    265   if (!FileSystemURLIsValid(GetFileSystemContext().get(), url))
    266     return PP_ERROR_FAILED;
    267   if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFileSystemFile(
    268           render_process_id_, url)) {
    269     return PP_ERROR_NOACCESS;
    270   }
    271   return PP_OK;
    272 }
    273 
    274 int32_t PepperInternalFileRefBackend::CanWrite() const {
    275   storage::FileSystemURL url = GetFileSystemURL();
    276   if (!FileSystemURLIsValid(GetFileSystemContext().get(), url))
    277     return PP_ERROR_FAILED;
    278   if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanWriteFileSystemFile(
    279           render_process_id_, url)) {
    280     return PP_ERROR_NOACCESS;
    281   }
    282   return PP_OK;
    283 }
    284 
    285 int32_t PepperInternalFileRefBackend::CanCreate() const {
    286   storage::FileSystemURL url = GetFileSystemURL();
    287   if (!FileSystemURLIsValid(GetFileSystemContext().get(), url))
    288     return PP_ERROR_FAILED;
    289   if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanCreateFileSystemFile(
    290           render_process_id_, url)) {
    291     return PP_ERROR_NOACCESS;
    292   }
    293   return PP_OK;
    294 }
    295 
    296 int32_t PepperInternalFileRefBackend::CanReadWrite() const {
    297   storage::FileSystemURL url = GetFileSystemURL();
    298   if (!FileSystemURLIsValid(GetFileSystemContext().get(), url))
    299     return PP_ERROR_FAILED;
    300   ChildProcessSecurityPolicyImpl* policy =
    301       ChildProcessSecurityPolicyImpl::GetInstance();
    302   if (!policy->CanReadFileSystemFile(render_process_id_, url) ||
    303       !policy->CanWriteFileSystemFile(render_process_id_, url)) {
    304     return PP_ERROR_NOACCESS;
    305   }
    306   return PP_OK;
    307 }
    308 
    309 }  // namespace content
    310