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