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