Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(183)

Side by Side Diff: content/renderer/pepper/ppb_file_ref_impl.cc

Issue 21966004: Pepper: Move FileRef to the "new" resource proxy. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Another rebase Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 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/renderer/pepper/ppb_file_ref_impl.h"
6
7 #include "base/files/file_util_proxy.h"
8 #include "base/platform_file.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "content/child/fileapi/file_system_dispatcher.h"
12 #include "content/common/view_messages.h"
13 #include "content/renderer/pepper/common.h"
14 #include "content/renderer/pepper/pepper_file_system_host.h"
15 #include "content/renderer/pepper/plugin_module.h"
16 #include "content/renderer/pepper/renderer_ppapi_host_impl.h"
17 #include "content/renderer/render_thread_impl.h"
18 #include "net/base/escape.h"
19 #include "ppapi/c/pp_errors.h"
20 #include "ppapi/c/ppb_file_io.h"
21 #include "ppapi/host/ppapi_host.h"
22 #include "ppapi/shared_impl/file_type_conversion.h"
23 #include "ppapi/shared_impl/time_conversion.h"
24 #include "ppapi/shared_impl/var.h"
25 #include "ppapi/thunk/enter.h"
26 #include "ppapi/thunk/ppb_file_system_api.h"
27 #include "url/gurl.h"
28 #include "webkit/common/fileapi/directory_entry.h"
29 #include "webkit/common/fileapi/file_system_util.h"
30
31 using ppapi::HostResource;
32 using ppapi::PPB_FileRef_CreateInfo;
33 using ppapi::PPTimeToTime;
34 using ppapi::StringVar;
35 using ppapi::TrackedCallback;
36 using ppapi::thunk::EnterResourceNoLock;
37 using ppapi::thunk::PPB_FileRef_API;
38 using ppapi::thunk::PPB_FileSystem_API;
39
40 namespace content {
41
42 namespace {
43
44 bool IsValidLocalPath(const std::string& path) {
45 // The path must start with '/'
46 if (path.empty() || path[0] != '/')
47 return false;
48
49 // The path must contain valid UTF-8 characters.
50 if (!IsStringUTF8(path))
51 return false;
52
53 #if defined(OS_WIN)
54 base::FilePath::StringType path_win(path.begin(), path.end());
55 base::FilePath file_path(path_win);
56 #else
57 base::FilePath file_path(path);
58 #endif
59 if (file_path.ReferencesParent())
60 return false;
61
62 return true;
63 }
64
65 void TrimTrailingSlash(std::string* path) {
66 // If this path ends with a slash, then normalize it away unless path is the
67 // root path.
68 if (path->size() > 1 && path->at(path->size() - 1) == '/')
69 path->erase(path->size() - 1, 1);
70 }
71
72 std::string GetNameForExternalFilePath(const base::FilePath& in_path) {
73 const base::FilePath::StringType& path = in_path.value();
74 size_t pos = path.rfind(base::FilePath::kSeparators[0]);
75 CHECK(pos != base::FilePath::StringType::npos);
76 #if defined(OS_WIN)
77 return WideToUTF8(path.substr(pos + 1));
78 #elif defined(OS_POSIX)
79 return path.substr(pos + 1);
80 #else
81 #error "Unsupported platform."
82 #endif
83 }
84
85 std::string GetNameForVirtualFilePath(const std::string& path) {
86 if (path.size() == 1 && path[0] == '/')
87 return path;
88
89 // There should always be a leading slash at least!
90 size_t pos = path.rfind('/');
91 CHECK(pos != std::string::npos);
92 return path.substr(pos + 1);
93 }
94
95 void IgnoreCloseCallback(base::PlatformFileError error_code) {
96 }
97
98 void PlatformFileInfoToPPFileInfo(
99 const base::PlatformFileInfo& file_info,
100 PP_FileSystemType file_system_type,
101 PP_FileInfo* info) {
102 DCHECK(info);
103 ppapi::PlatformFileInfoToPepperFileInfo(file_info, file_system_type, info);
104 }
105
106 void GetFileInfoCallback(
107 scoped_refptr<base::TaskRunner> task_runner,
108 base::PlatformFile file,
109 linked_ptr<PP_FileInfo> info,
110 scoped_refptr<TrackedCallback> callback,
111 base::PlatformFileError error_code,
112 const base::PlatformFileInfo& file_info) {
113 base::FileUtilProxy::Close(
114 task_runner.get(), file, base::Bind(&IgnoreCloseCallback));
115
116 if (!TrackedCallback::IsPending(callback))
117 return;
118
119 int32_t pp_error = ppapi::PlatformFileErrorToPepperError(error_code);
120 if (pp_error != PP_OK) {
121 callback->Run(pp_error);
122 return;
123 }
124
125 PlatformFileInfoToPPFileInfo(
126 file_info, PP_FILESYSTEMTYPE_EXTERNAL, info.get());
127
128 callback->Run(PP_OK);
129 }
130
131 void QueryCallback(scoped_refptr<base::TaskRunner> task_runner,
132 linked_ptr<PP_FileInfo> info,
133 scoped_refptr<TrackedCallback> callback,
134 base::PlatformFileError error_code,
135 base::PassPlatformFile passed_file) {
136 if (!TrackedCallback::IsPending(callback))
137 return;
138
139 int32_t pp_error = ppapi::PlatformFileErrorToPepperError(error_code);
140 if (pp_error != PP_OK) {
141 callback->Run(pp_error);
142 return;
143 }
144 base::PlatformFile file = passed_file.ReleaseValue();
145
146 if (!base::FileUtilProxy::GetFileInfoFromPlatformFile(
147 task_runner.get(),
148 file,
149 base::Bind(
150 &GetFileInfoCallback, task_runner, file, info, callback))) {
151 base::FileUtilProxy::Close(
152 task_runner.get(), file, base::Bind(&IgnoreCloseCallback));
153 callback->Run(PP_ERROR_FAILED);
154 }
155 }
156
157 void DidReadMetadata(
158 scoped_refptr<ppapi::TrackedCallback> callback,
159 linked_ptr<PP_FileInfo> info,
160 PP_FileSystemType file_system_type,
161 const base::PlatformFileInfo& file_info) {
162 if (!TrackedCallback::IsPending(callback))
163 return;
164
165 PlatformFileInfoToPPFileInfo(file_info, file_system_type, info.get());
166 callback->Run(PP_OK);
167 }
168
169 void DidReadDirectory(
170 scoped_refptr<ppapi::TrackedCallback> callback,
171 PPB_FileRef_Impl* dir_ref,
172 linked_ptr<std::vector<ppapi::PPB_FileRef_CreateInfo> > dir_files,
173 linked_ptr<std::vector<PP_FileType> > dir_file_types,
174 const std::vector<fileapi::DirectoryEntry>& entries,
175 bool has_more) {
176 if (!TrackedCallback::IsPending(callback))
177 return;
178
179 // The current filesystem backend always returns false.
180 DCHECK(!has_more);
181
182 DCHECK(dir_ref);
183 DCHECK(dir_files.get());
184 DCHECK(dir_file_types.get());
185
186 std::string dir_path = dir_ref->GetCreateInfo().path;
187 if (dir_path.empty() || dir_path[dir_path.size() - 1] != '/')
188 dir_path += '/';
189
190 for (size_t i = 0; i < entries.size(); ++i) {
191 const fileapi::DirectoryEntry& entry = entries[i];
192 scoped_refptr<PPB_FileRef_Impl> file_ref(PPB_FileRef_Impl::CreateInternal(
193 dir_ref->pp_instance(),
194 dir_ref->file_system_resource(),
195 dir_path + fileapi::FilePathToString(base::FilePath(entry.name))));
196 dir_files->push_back(file_ref->GetCreateInfo());
197 dir_file_types->push_back(
198 entry.is_directory ? PP_FILETYPE_DIRECTORY : PP_FILETYPE_REGULAR);
199 // Add a ref count on behalf of the plugin side.
200 file_ref->GetReference();
201 }
202 CHECK_EQ(dir_files->size(), dir_file_types->size());
203
204 callback->Run(PP_OK);
205 }
206
207 void DidFinishFileOperation(
208 scoped_refptr<ppapi::TrackedCallback> callback,
209 base::PlatformFileError error_code) {
210 if (callback->completed())
211 return;
212 callback->Run(ppapi::PlatformFileErrorToPepperError(error_code));
213 }
214
215 } // namespace
216
217 PPB_FileRef_Impl::PPB_FileRef_Impl(const PPB_FileRef_CreateInfo& info,
218 PP_Resource file_system)
219 : PPB_FileRef_Shared(ppapi::OBJECT_IS_IMPL, info),
220 file_system_(file_system),
221 external_file_system_path_(),
222 routing_id_(MSG_ROUTING_NONE) {
223 if (RenderThreadImpl::current()) { // NULL in tests.
224 routing_id_ = RenderThreadImpl::current()->GenerateRoutingID();
225 ChildThread::current()->AddRoute(routing_id_, this);
226 }
227 }
228
229 PPB_FileRef_Impl::PPB_FileRef_Impl(const PPB_FileRef_CreateInfo& info,
230 const base::FilePath& external_file_path)
231 : PPB_FileRef_Shared(ppapi::OBJECT_IS_IMPL, info),
232 file_system_(),
233 external_file_system_path_(external_file_path),
234 routing_id_(MSG_ROUTING_NONE) {
235 if (RenderThreadImpl::current()) { // NULL in tests.
236 routing_id_ = RenderThreadImpl::current()->GenerateRoutingID();
237 ChildThread::current()->AddRoute(routing_id_, this);
238 }
239 }
240
241 PPB_FileRef_Impl::~PPB_FileRef_Impl() {
242 if (RenderThreadImpl::current())
243 ChildThread::current()->RemoveRoute(routing_id_);
244 }
245
246 // static
247 PPB_FileRef_Impl* PPB_FileRef_Impl::CreateInternal(PP_Instance instance,
248 PP_Resource pp_file_system,
249 const std::string& path) {
250 PepperFileSystemHost* fs_host = GetFileSystemHostInternal(
251 instance, pp_file_system);
252 if (!fs_host)
253 return 0;
254
255 PP_FileSystemType type = fs_host->GetType();
256 if (type != PP_FILESYSTEMTYPE_LOCALPERSISTENT &&
257 type != PP_FILESYSTEMTYPE_LOCALTEMPORARY &&
258 type != PP_FILESYSTEMTYPE_EXTERNAL &&
259 type != PP_FILESYSTEMTYPE_ISOLATED)
260 return 0;
261
262 PPB_FileRef_CreateInfo info;
263 info.resource = HostResource::MakeInstanceOnly(instance);
264 info.file_system_plugin_resource = pp_file_system;
265 info.file_system_type = type;
266
267 // Validate the path.
268 info.path = path;
269 if (!IsValidLocalPath(info.path))
270 return 0;
271 TrimTrailingSlash(&info.path);
272
273 info.name = GetNameForVirtualFilePath(info.path);
274
275 PPB_FileRef_Impl* file_ref = new PPB_FileRef_Impl(info, pp_file_system);
276
277 RendererPpapiHostImpl* renderer_host =
278 RendererPpapiHostImpl::GetForPPInstance(instance);
279 if (renderer_host && renderer_host->IsRunningInProcess())
280 file_ref->AddFileSystemRefCount();
281 return file_ref;
282 }
283
284 // static
285 PPB_FileRef_Impl* PPB_FileRef_Impl::CreateExternal(
286 PP_Instance instance,
287 const base::FilePath& external_file_path,
288 const std::string& display_name) {
289 PPB_FileRef_CreateInfo info;
290 info.resource = HostResource::MakeInstanceOnly(instance);
291 info.file_system_plugin_resource = 0;
292 info.file_system_type = PP_FILESYSTEMTYPE_EXTERNAL;
293 if (display_name.empty())
294 info.name = GetNameForExternalFilePath(external_file_path);
295 else
296 info.name = display_name;
297
298 return new PPB_FileRef_Impl(info, external_file_path);
299 }
300
301 PP_Resource PPB_FileRef_Impl::GetParent() {
302 if (GetFileSystemType() == PP_FILESYSTEMTYPE_EXTERNAL)
303 return 0;
304
305 const std::string& virtual_path = GetCreateInfo().path;
306
307 // There should always be a leading slash at least!
308 size_t pos = virtual_path.rfind('/');
309 CHECK(pos != std::string::npos);
310
311 // If the path is "/foo", then we want to include the slash.
312 if (pos == 0)
313 pos++;
314 std::string parent_path = virtual_path.substr(0, pos);
315
316 scoped_refptr<PPB_FileRef_Impl> parent_ref(
317 CreateInternal(pp_instance(), file_system_, parent_path));
318 if (!parent_ref.get())
319 return 0;
320 return parent_ref->GetReference();
321 }
322
323 int32_t PPB_FileRef_Impl::MakeDirectory(
324 PP_Bool make_ancestors,
325 scoped_refptr<TrackedCallback> callback) {
326 if (!IsValidNonExternalFileSystem())
327 return PP_ERROR_NOACCESS;
328
329 FileSystemDispatcher* file_system_dispatcher =
330 ChildThread::current()->file_system_dispatcher();
331 file_system_dispatcher->CreateDirectory(
332 GetFileSystemURL(), false /* exclusive */, PP_ToBool(make_ancestors),
333 base::Bind(&DidFinishFileOperation, callback));
334 return PP_OK_COMPLETIONPENDING;
335 }
336
337 int32_t PPB_FileRef_Impl::Touch(PP_Time last_access_time,
338 PP_Time last_modified_time,
339 scoped_refptr<TrackedCallback> callback) {
340 if (!IsValidNonExternalFileSystem())
341 return PP_ERROR_NOACCESS;
342
343 FileSystemDispatcher* file_system_dispatcher =
344 ChildThread::current()->file_system_dispatcher();
345 file_system_dispatcher->TouchFile(
346 GetFileSystemURL(),
347 PPTimeToTime(last_access_time),
348 PPTimeToTime(last_modified_time),
349 base::Bind(&DidFinishFileOperation, callback));
350 return PP_OK_COMPLETIONPENDING;
351 }
352
353 int32_t PPB_FileRef_Impl::Delete(scoped_refptr<TrackedCallback> callback) {
354 if (!IsValidNonExternalFileSystem())
355 return PP_ERROR_NOACCESS;
356
357 FileSystemDispatcher* file_system_dispatcher =
358 ChildThread::current()->file_system_dispatcher();
359 file_system_dispatcher->Remove(
360 GetFileSystemURL(),
361 false /* recursive */,
362 base::Bind(&DidFinishFileOperation, callback));
363 return PP_OK_COMPLETIONPENDING;
364 }
365
366 int32_t PPB_FileRef_Impl::Rename(PP_Resource new_pp_file_ref,
367 scoped_refptr<TrackedCallback> callback) {
368 EnterResourceNoLock<PPB_FileRef_API> enter(new_pp_file_ref, true);
369 if (enter.failed())
370 return PP_ERROR_BADRESOURCE;
371 PPB_FileRef_Impl* new_file_ref =
372 static_cast<PPB_FileRef_Impl*>(enter.object());
373
374 if (!IsValidNonExternalFileSystem() ||
375 file_system_ != new_file_ref->file_system_)
376 return PP_ERROR_NOACCESS;
377
378 // TODO(viettrungluu): Also cancel when the new file ref is destroyed?
379 // http://crbug.com/67624
380 FileSystemDispatcher* file_system_dispatcher =
381 ChildThread::current()->file_system_dispatcher();
382 file_system_dispatcher->Move(
383 GetFileSystemURL(), new_file_ref->GetFileSystemURL(),
384 base::Bind(&DidFinishFileOperation, callback));
385 return PP_OK_COMPLETIONPENDING;
386 }
387
388 PP_Var PPB_FileRef_Impl::GetAbsolutePath() {
389 if (GetFileSystemType() != PP_FILESYSTEMTYPE_EXTERNAL)
390 return GetPath();
391 if (!external_path_var_.get()) {
392 external_path_var_ =
393 new StringVar(external_file_system_path_.AsUTF8Unsafe());
394 }
395 return external_path_var_->GetPPVar();
396 }
397
398 base::FilePath PPB_FileRef_Impl::GetSystemPath() const {
399 if (GetFileSystemType() != PP_FILESYSTEMTYPE_EXTERNAL) {
400 NOTREACHED();
401 return base::FilePath();
402 }
403 return external_file_system_path_;
404 }
405
406 GURL PPB_FileRef_Impl::GetFileSystemURL() const {
407 if (GetFileSystemType() != PP_FILESYSTEMTYPE_LOCALPERSISTENT &&
408 GetFileSystemType() != PP_FILESYSTEMTYPE_LOCALTEMPORARY &&
409 GetFileSystemType() != PP_FILESYSTEMTYPE_EXTERNAL &&
410 GetFileSystemType() != PP_FILESYSTEMTYPE_ISOLATED) {
411 NOTREACHED();
412 return GURL();
413 }
414
415 const std::string& virtual_path = GetCreateInfo().path;
416 CHECK(!virtual_path.empty()); // Should always be at least "/".
417
418 // Since |virtual_path_| starts with a '/', it looks like an absolute path.
419 // We need to trim off the '/' before calling Resolve, as FileSystem URLs
420 // start with a storage type identifier that looks like a path segment.
421
422 PepperFileSystemHost* host = GetFileSystemHost();
423 if (!host)
424 return GURL();
425
426 return GURL(host->GetRootUrl()).Resolve(net::EscapePath(
427 virtual_path.substr(1)));
428 }
429
430 bool PPB_FileRef_Impl::OnMessageReceived(const IPC::Message& msg) {
431 bool handled = true;
432 IPC_BEGIN_MESSAGE_MAP(PPB_FileRef_Impl, msg)
433 IPC_MESSAGE_HANDLER(ViewMsg_AsyncOpenPepperFile_ACK, OnAsyncFileOpened)
434 IPC_MESSAGE_UNHANDLED(handled = false)
435 IPC_END_MESSAGE_MAP()
436 return handled;
437 }
438
439 void PPB_FileRef_Impl::OnAsyncFileOpened(
440 base::PlatformFileError error_code,
441 IPC::PlatformFileForTransit file_for_transit,
442 int message_id) {
443 AsyncOpenFileCallback* callback =
444 pending_async_open_files_.Lookup(message_id);
445 DCHECK(callback);
446 pending_async_open_files_.Remove(message_id);
447
448 base::PlatformFile file =
449 IPC::PlatformFileForTransitToPlatformFile(file_for_transit);
450 callback->Run(error_code, base::PassPlatformFile(&file));
451 // Make sure we won't leak file handle if the requester has died.
452 if (file != base::kInvalidPlatformFileValue) {
453 base::FileUtilProxy::Close(
454 RenderThreadImpl::current()->GetFileThreadMessageLoopProxy().get(),
455 file,
456 base::FileUtilProxy::StatusCallback());
457 }
458 delete callback;
459 }
460
461 bool PPB_FileRef_Impl::IsValidNonExternalFileSystem() const {
462 PepperFileSystemHost* host = GetFileSystemHost();
463 return HasValidFileSystem() && host &&
464 host->GetType() != PP_FILESYSTEMTYPE_EXTERNAL;
465 }
466
467 bool PPB_FileRef_Impl::HasValidFileSystem() const {
468 PepperFileSystemHost* host = GetFileSystemHost();
469 return host && host->IsOpened();
470 }
471
472 int32_t PPB_FileRef_Impl::Query(PP_FileInfo* info,
473 scoped_refptr<TrackedCallback> callback) {
474 NOTREACHED();
475 return PP_ERROR_FAILED;
476 }
477
478 int32_t PPB_FileRef_Impl::QueryInHost(
479 linked_ptr<PP_FileInfo> info,
480 scoped_refptr<TrackedCallback> callback) {
481 if (!file_system_) {
482 // External file system
483 // We have to do something totally different for external file systems.
484
485 // TODO(teravest): Use the SequencedWorkerPool instead.
486 scoped_refptr<base::TaskRunner> task_runner =
487 RenderThreadImpl::current()->GetFileThreadMessageLoopProxy();
488
489 int message_id = pending_async_open_files_.Add(new AsyncOpenFileCallback(
490 base::Bind(&QueryCallback, task_runner, info, callback)));
491 RenderThreadImpl::current()->Send(new ViewHostMsg_AsyncOpenPepperFile(
492 routing_id_,
493 GetSystemPath(),
494 PP_FILEOPENFLAG_READ,
495 message_id));
496 } else {
497 // Non-external file system
498 if (!HasValidFileSystem())
499 return PP_ERROR_NOACCESS;
500
501 PP_FileSystemType file_system_type = GetFileSystemHost()->GetType();
502 FileSystemDispatcher* file_system_dispatcher =
503 ChildThread::current()->file_system_dispatcher();
504 file_system_dispatcher->ReadMetadata(
505 GetFileSystemURL(),
506 base::Bind(&DidReadMetadata, callback, info, file_system_type),
507 base::Bind(&DidFinishFileOperation, callback));
508 }
509 return PP_OK_COMPLETIONPENDING;
510 }
511
512 int32_t PPB_FileRef_Impl::ReadDirectoryEntries(
513 const PP_ArrayOutput& output,
514 scoped_refptr<TrackedCallback> callback) {
515 NOTREACHED();
516 return PP_ERROR_FAILED;
517 }
518
519 int32_t PPB_FileRef_Impl::ReadDirectoryEntriesInHost(
520 linked_ptr<std::vector<ppapi::PPB_FileRef_CreateInfo> > files,
521 linked_ptr<std::vector<PP_FileType> > file_types,
522 scoped_refptr<TrackedCallback> callback) {
523 if (!IsValidNonExternalFileSystem())
524 return PP_ERROR_NOACCESS;
525
526 // TODO(yzshen): Passing base::Unretained(this) to the callback could
527 // be dangerous.
528 FileSystemDispatcher* file_system_dispatcher =
529 ChildThread::current()->file_system_dispatcher();
530 file_system_dispatcher->ReadDirectory(
531 GetFileSystemURL(),
532 base::Bind(&DidReadDirectory,
533 callback, base::Unretained(this), files, file_types),
534 base::Bind(&DidFinishFileOperation, callback));
535 return PP_OK_COMPLETIONPENDING;
536 }
537
538 PepperFileSystemHost* PPB_FileRef_Impl::GetFileSystemHost() const {
539 return GetFileSystemHostInternal(pp_instance(), file_system_);
540 }
541
542 PepperFileSystemHost* PPB_FileRef_Impl::GetFileSystemHostInternal(
543 PP_Instance instance, PP_Resource resource) {
544 const ppapi::host::PpapiHost* ppapi_host =
545 RendererPpapiHost::GetForPPInstance(instance)->GetPpapiHost();
546 if (!resource || !ppapi_host)
547 return NULL;
548 ppapi::host::ResourceHost* resource_host =
549 ppapi_host->GetResourceHost(resource);
550 if (resource_host && resource_host->IsFileSystemHost())
551 return static_cast<PepperFileSystemHost*>(resource_host);
552 return NULL;
553 }
554
555 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/pepper/ppb_file_ref_impl.h ('k') | content/renderer/pepper/resource_creation_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698