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 "ppapi/proxy/file_ref_resource.h" 6 7#include "ppapi/c/pp_directory_entry.h" 8#include "ppapi/c/pp_instance.h" 9#include "ppapi/c/pp_resource.h" 10#include "ppapi/proxy/ppapi_messages.h" 11#include "ppapi/shared_impl/array_writer.h" 12#include "ppapi/shared_impl/file_ref_util.h" 13#include "ppapi/shared_impl/resource.h" 14#include "ppapi/shared_impl/resource_tracker.h" 15#include "ppapi/shared_impl/var.h" 16#include "ppapi/thunk/enter.h" 17#include "ppapi/thunk/ppb_file_system_api.h" 18 19namespace ppapi { 20namespace proxy { 21 22FileRefResource::FileRefResource( 23 Connection connection, 24 PP_Instance instance, 25 const FileRefCreateInfo& create_info) 26 : PluginResource(connection, instance), 27 create_info_(create_info), 28 file_system_resource_(create_info.file_system_plugin_resource) { 29 if (uses_internal_paths()) { 30 // If path ends with a slash, then normalize it away unless path is 31 // the root path. 32 int path_size = create_info_.internal_path.size(); 33 if (path_size > 1 && create_info_.internal_path.at(path_size - 1) == '/') 34 create_info_.internal_path.erase(path_size - 1, 1); 35 36 path_var_ = new StringVar(create_info_.internal_path); 37 create_info_.display_name = GetNameForInternalFilePath( 38 create_info_.internal_path); 39 } else { 40 DCHECK(!create_info_.display_name.empty()); 41 } 42 name_var_ = new StringVar(create_info_.display_name); 43 44 if (create_info_.browser_pending_host_resource_id != 0 && 45 create_info_.renderer_pending_host_resource_id != 0) { 46 AttachToPendingHost(BROWSER, create_info_.browser_pending_host_resource_id); 47 AttachToPendingHost(RENDERER, 48 create_info_.renderer_pending_host_resource_id); 49 } else { 50 CHECK_EQ(0, create_info_.browser_pending_host_resource_id); 51 CHECK_EQ(0, create_info_.renderer_pending_host_resource_id); 52 CHECK(uses_internal_paths()); 53 SendCreate(BROWSER, PpapiHostMsg_FileRef_CreateForFileAPI( 54 create_info.file_system_plugin_resource, 55 create_info.internal_path)); 56 SendCreate(RENDERER, PpapiHostMsg_FileRef_CreateForFileAPI( 57 create_info.file_system_plugin_resource, 58 create_info.internal_path)); 59 } 60} 61 62FileRefResource::~FileRefResource() { 63} 64 65// static 66PP_Resource FileRefResource::CreateFileRef( 67 Connection connection, 68 PP_Instance instance, 69 const FileRefCreateInfo& create_info) { 70 // If we have a valid file_system resource, ensure that its type matches that 71 // of the fs_type parameter. 72 if (create_info.file_system_plugin_resource != 0) { 73 thunk::EnterResourceNoLock<thunk::PPB_FileSystem_API> enter( 74 create_info.file_system_plugin_resource, true); 75 if (enter.failed()) 76 return 0; 77 if (enter.object()->GetType() != create_info.file_system_type) { 78 NOTREACHED() << "file system type mismatch with resource"; 79 return 0; 80 } 81 } 82 83 if (create_info.file_system_type == PP_FILESYSTEMTYPE_LOCALPERSISTENT || 84 create_info.file_system_type == PP_FILESYSTEMTYPE_LOCALTEMPORARY) { 85 if (!IsValidInternalPath(create_info.internal_path)) 86 return 0; 87 } 88 return (new FileRefResource(connection, 89 instance, 90 create_info))->GetReference(); 91} 92 93thunk::PPB_FileRef_API* FileRefResource::AsPPB_FileRef_API() { 94 return this; 95} 96 97PP_FileSystemType FileRefResource::GetFileSystemType() const { 98 return create_info_.file_system_type; 99} 100 101PP_Var FileRefResource::GetName() const { 102 return name_var_->GetPPVar(); 103} 104 105PP_Var FileRefResource::GetPath() const { 106 if (!uses_internal_paths()) 107 return PP_MakeUndefined(); 108 return path_var_->GetPPVar(); 109} 110 111PP_Resource FileRefResource::GetParent() { 112 if (!uses_internal_paths()) 113 return 0; 114 115 size_t pos = create_info_.internal_path.rfind('/'); 116 CHECK(pos != std::string::npos); 117 if (pos == 0) 118 pos++; 119 std::string parent_path = create_info_.internal_path.substr(0, pos); 120 121 ppapi::FileRefCreateInfo parent_info; 122 parent_info.file_system_type = create_info_.file_system_type; 123 parent_info.internal_path = parent_path; 124 parent_info.display_name = GetNameForInternalFilePath(parent_path); 125 parent_info.file_system_plugin_resource = 126 create_info_.file_system_plugin_resource; 127 128 return (new FileRefResource(connection(), 129 pp_instance(), 130 parent_info))->GetReference(); 131} 132 133int32_t FileRefResource::MakeDirectory( 134 int32_t make_directory_flags, 135 scoped_refptr<TrackedCallback> callback) { 136 Call<PpapiPluginMsg_FileRef_MakeDirectoryReply>( 137 BROWSER, 138 PpapiHostMsg_FileRef_MakeDirectory(make_directory_flags), 139 base::Bind(&FileRefResource::RunTrackedCallback, this, callback)); 140 return PP_OK_COMPLETIONPENDING; 141} 142 143int32_t FileRefResource::Touch(PP_Time last_access_time, 144 PP_Time last_modified_time, 145 scoped_refptr<TrackedCallback> callback) { 146 Call<PpapiPluginMsg_FileRef_TouchReply>( 147 BROWSER, 148 PpapiHostMsg_FileRef_Touch(last_access_time, 149 last_modified_time), 150 base::Bind(&FileRefResource::RunTrackedCallback, this, callback)); 151 return PP_OK_COMPLETIONPENDING; 152} 153 154int32_t FileRefResource::Delete(scoped_refptr<TrackedCallback> callback) { 155 Call<PpapiPluginMsg_FileRef_DeleteReply>( 156 BROWSER, 157 PpapiHostMsg_FileRef_Delete(), 158 base::Bind(&FileRefResource::RunTrackedCallback, this, callback)); 159 return PP_OK_COMPLETIONPENDING; 160} 161 162int32_t FileRefResource::Rename(PP_Resource new_file_ref, 163 scoped_refptr<TrackedCallback> callback) { 164 Call<PpapiPluginMsg_FileRef_RenameReply>( 165 BROWSER, 166 PpapiHostMsg_FileRef_Rename(new_file_ref), 167 base::Bind(&FileRefResource::RunTrackedCallback, this, callback)); 168 return PP_OK_COMPLETIONPENDING; 169} 170 171int32_t FileRefResource::Query(PP_FileInfo* info, 172 scoped_refptr<TrackedCallback> callback) { 173 if (info == NULL) 174 return PP_ERROR_BADARGUMENT; 175 176 Call<PpapiPluginMsg_FileRef_QueryReply>( 177 BROWSER, 178 PpapiHostMsg_FileRef_Query(), 179 base::Bind(&FileRefResource::OnQueryReply, this, info, callback)); 180 return PP_OK_COMPLETIONPENDING; 181} 182 183int32_t FileRefResource::ReadDirectoryEntries( 184 const PP_ArrayOutput& output, 185 scoped_refptr<TrackedCallback> callback) { 186 Call<PpapiPluginMsg_FileRef_ReadDirectoryEntriesReply>( 187 BROWSER, 188 PpapiHostMsg_FileRef_ReadDirectoryEntries(), 189 base::Bind(&FileRefResource::OnDirectoryEntriesReply, 190 this, output, callback)); 191 return PP_OK_COMPLETIONPENDING; 192} 193 194const FileRefCreateInfo& FileRefResource::GetCreateInfo() const { 195 return create_info_; 196} 197 198PP_Var FileRefResource::GetAbsolutePath() { 199 if (!absolute_path_var_.get()) { 200 std::string absolute_path; 201 int32_t result = SyncCall<PpapiPluginMsg_FileRef_GetAbsolutePathReply>( 202 BROWSER, PpapiHostMsg_FileRef_GetAbsolutePath(), &absolute_path); 203 if (result != PP_OK) 204 return PP_MakeUndefined(); 205 absolute_path_var_ = new StringVar(absolute_path); 206 } 207 return absolute_path_var_->GetPPVar(); 208} 209 210void FileRefResource::RunTrackedCallback( 211 scoped_refptr<TrackedCallback> callback, 212 const ResourceMessageReplyParams& params) { 213 if (TrackedCallback::IsPending(callback)) 214 callback->Run(params.result()); 215} 216 217void FileRefResource::OnQueryReply( 218 PP_FileInfo* out_info, 219 scoped_refptr<TrackedCallback> callback, 220 const ResourceMessageReplyParams& params, 221 const PP_FileInfo& info) { 222 if (!TrackedCallback::IsPending(callback)) 223 return; 224 225 if (params.result() == PP_OK) 226 *out_info = info; 227 callback->Run(params.result()); 228} 229 230void FileRefResource::OnDirectoryEntriesReply( 231 const PP_ArrayOutput& output, 232 scoped_refptr<TrackedCallback> callback, 233 const ResourceMessageReplyParams& params, 234 const std::vector<ppapi::FileRefCreateInfo>& infos, 235 const std::vector<PP_FileType>& file_types) { 236 if (!TrackedCallback::IsPending(callback)) 237 return; 238 239 if (params.result() == PP_OK) { 240 ArrayWriter writer(output); 241 if (!writer.is_valid()) { 242 callback->Run(PP_ERROR_BADARGUMENT); 243 return; 244 } 245 246 std::vector<PP_DirectoryEntry> entries; 247 for (size_t i = 0; i < infos.size(); ++i) { 248 PP_DirectoryEntry entry; 249 entry.file_ref = FileRefResource::CreateFileRef(connection(), 250 pp_instance(), 251 infos[i]); 252 entry.file_type = file_types[i]; 253 entries.push_back(entry); 254 } 255 256 writer.StoreVector(entries); 257 } 258 callback->Run(params.result()); 259} 260 261bool FileRefResource::uses_internal_paths() const { 262 return (create_info_.file_system_type != PP_FILESYSTEMTYPE_EXTERNAL) || 263 !create_info_.internal_path.empty(); 264} 265 266} // namespace proxy 267} // namespace ppapi 268