// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "ppapi/proxy/file_ref_resource.h" #include "base/numerics/safe_conversions.h" #include "ppapi/c/pp_directory_entry.h" #include "ppapi/c/pp_instance.h" #include "ppapi/c/pp_resource.h" #include "ppapi/proxy/ppapi_messages.h" #include "ppapi/shared_impl/array_writer.h" #include "ppapi/shared_impl/file_ref_util.h" #include "ppapi/shared_impl/resource.h" #include "ppapi/shared_impl/resource_tracker.h" #include "ppapi/shared_impl/var.h" #include "ppapi/thunk/enter.h" #include "ppapi/thunk/ppb_file_system_api.h" namespace ppapi { namespace proxy { FileRefResource::FileRefResource( Connection connection, PP_Instance instance, const FileRefCreateInfo& create_info) : PluginResource(connection, instance), create_info_(create_info), file_system_resource_(create_info.file_system_plugin_resource) { if (uses_internal_paths()) { // If path ends with a slash, then normalize it away unless path is // the root path. int path_size = base::checked_cast(create_info_.internal_path.size()); if (path_size > 1 && create_info_.internal_path.at(path_size - 1) == '/') create_info_.internal_path.erase(path_size - 1, 1); path_var_ = new StringVar(create_info_.internal_path); create_info_.display_name = GetNameForInternalFilePath( create_info_.internal_path); } else { DCHECK(!create_info_.display_name.empty()); } name_var_ = new StringVar(create_info_.display_name); if (create_info_.browser_pending_host_resource_id != 0 && create_info_.renderer_pending_host_resource_id != 0) { AttachToPendingHost(BROWSER, create_info_.browser_pending_host_resource_id); AttachToPendingHost(RENDERER, create_info_.renderer_pending_host_resource_id); } else { CHECK_EQ(0, create_info_.browser_pending_host_resource_id); CHECK_EQ(0, create_info_.renderer_pending_host_resource_id); CHECK(uses_internal_paths()); SendCreate(BROWSER, PpapiHostMsg_FileRef_CreateForFileAPI( create_info.file_system_plugin_resource, create_info.internal_path)); SendCreate(RENDERER, PpapiHostMsg_FileRef_CreateForFileAPI( create_info.file_system_plugin_resource, create_info.internal_path)); } } FileRefResource::~FileRefResource() { } // static PP_Resource FileRefResource::CreateFileRef( Connection connection, PP_Instance instance, const FileRefCreateInfo& create_info) { // If we have a valid file_system resource, ensure that its type matches that // of the fs_type parameter. if (create_info.file_system_plugin_resource != 0) { thunk::EnterResourceNoLock enter( create_info.file_system_plugin_resource, true); if (enter.failed()) return 0; if (enter.object()->GetType() != create_info.file_system_type) { NOTREACHED() << "file system type mismatch with resource"; return 0; } } if (create_info.file_system_type == PP_FILESYSTEMTYPE_LOCALPERSISTENT || create_info.file_system_type == PP_FILESYSTEMTYPE_LOCALTEMPORARY) { if (!IsValidInternalPath(create_info.internal_path)) return 0; } return (new FileRefResource(connection, instance, create_info))->GetReference(); } thunk::PPB_FileRef_API* FileRefResource::AsPPB_FileRef_API() { return this; } PP_FileSystemType FileRefResource::GetFileSystemType() const { return create_info_.file_system_type; } PP_Var FileRefResource::GetName() const { return name_var_->GetPPVar(); } PP_Var FileRefResource::GetPath() const { if (!uses_internal_paths()) return PP_MakeUndefined(); return path_var_->GetPPVar(); } PP_Resource FileRefResource::GetParent() { if (!uses_internal_paths()) return 0; size_t pos = create_info_.internal_path.rfind('/'); CHECK(pos != std::string::npos); if (pos == 0) pos++; std::string parent_path = create_info_.internal_path.substr(0, pos); ppapi::FileRefCreateInfo parent_info; parent_info.file_system_type = create_info_.file_system_type; parent_info.internal_path = parent_path; parent_info.display_name = GetNameForInternalFilePath(parent_path); parent_info.file_system_plugin_resource = create_info_.file_system_plugin_resource; return (new FileRefResource(connection(), pp_instance(), parent_info))->GetReference(); } int32_t FileRefResource::MakeDirectory( int32_t make_directory_flags, scoped_refptr callback) { Call( BROWSER, PpapiHostMsg_FileRef_MakeDirectory(make_directory_flags), base::Bind(&FileRefResource::RunTrackedCallback, this, callback)); return PP_OK_COMPLETIONPENDING; } int32_t FileRefResource::Touch(PP_Time last_access_time, PP_Time last_modified_time, scoped_refptr callback) { Call( BROWSER, PpapiHostMsg_FileRef_Touch(last_access_time, last_modified_time), base::Bind(&FileRefResource::RunTrackedCallback, this, callback)); return PP_OK_COMPLETIONPENDING; } int32_t FileRefResource::Delete(scoped_refptr callback) { Call( BROWSER, PpapiHostMsg_FileRef_Delete(), base::Bind(&FileRefResource::RunTrackedCallback, this, callback)); return PP_OK_COMPLETIONPENDING; } int32_t FileRefResource::Rename(PP_Resource new_file_ref, scoped_refptr callback) { Call( BROWSER, PpapiHostMsg_FileRef_Rename(new_file_ref), base::Bind(&FileRefResource::RunTrackedCallback, this, callback)); return PP_OK_COMPLETIONPENDING; } int32_t FileRefResource::Query(PP_FileInfo* info, scoped_refptr callback) { if (info == NULL) return PP_ERROR_BADARGUMENT; Call( BROWSER, PpapiHostMsg_FileRef_Query(), base::Bind(&FileRefResource::OnQueryReply, this, info, callback)); return PP_OK_COMPLETIONPENDING; } int32_t FileRefResource::ReadDirectoryEntries( const PP_ArrayOutput& output, scoped_refptr callback) { Call( BROWSER, PpapiHostMsg_FileRef_ReadDirectoryEntries(), base::Bind(&FileRefResource::OnDirectoryEntriesReply, this, output, callback)); return PP_OK_COMPLETIONPENDING; } const FileRefCreateInfo& FileRefResource::GetCreateInfo() const { return create_info_; } PP_Var FileRefResource::GetAbsolutePath() { if (!absolute_path_var_.get()) { std::string absolute_path; int32_t result = SyncCall( BROWSER, PpapiHostMsg_FileRef_GetAbsolutePath(), &absolute_path); if (result != PP_OK) return PP_MakeUndefined(); absolute_path_var_ = new StringVar(absolute_path); } return absolute_path_var_->GetPPVar(); } void FileRefResource::RunTrackedCallback( scoped_refptr callback, const ResourceMessageReplyParams& params) { if (TrackedCallback::IsPending(callback)) callback->Run(params.result()); } void FileRefResource::OnQueryReply( PP_FileInfo* out_info, scoped_refptr callback, const ResourceMessageReplyParams& params, const PP_FileInfo& info) { if (!TrackedCallback::IsPending(callback)) return; if (params.result() == PP_OK) *out_info = info; callback->Run(params.result()); } void FileRefResource::OnDirectoryEntriesReply( const PP_ArrayOutput& output, scoped_refptr callback, const ResourceMessageReplyParams& params, const std::vector& infos, const std::vector& file_types) { if (!TrackedCallback::IsPending(callback)) return; if (params.result() == PP_OK) { ArrayWriter writer(output); if (!writer.is_valid()) { callback->Run(PP_ERROR_BADARGUMENT); return; } std::vector entries; for (size_t i = 0; i < infos.size(); ++i) { PP_DirectoryEntry entry; entry.file_ref = FileRefResource::CreateFileRef(connection(), pp_instance(), infos[i]); entry.file_type = file_types[i]; entries.push_back(entry); } writer.StoreVector(entries); } callback->Run(params.result()); } bool FileRefResource::uses_internal_paths() const { return (create_info_.file_system_type != PP_FILESYSTEMTYPE_EXTERNAL) || !create_info_.internal_path.empty(); } } // namespace proxy } // namespace ppapi