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