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_file_io_host.h"
6 
7 #include <utility>
8 
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/memory/weak_ptr.h"
12 #include "base/sequenced_task_runner.h"
13 #include "base/task/post_task.h"
14 #include "base/task/thread_pool.h"
15 #include "content/browser/renderer_host/pepper/pepper_file_ref_host.h"
16 #include "content/browser/renderer_host/pepper/pepper_file_system_browser_host.h"
17 #include "content/browser/renderer_host/pepper/pepper_security_helper.h"
18 #include "content/common/view_messages.h"
19 #include "content/public/browser/browser_task_traits.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "content/public/browser/content_browser_client.h"
22 #include "content/public/browser/render_process_host.h"
23 #include "content/public/browser/storage_partition.h"
24 #include "content/public/common/content_client.h"
25 #include "ipc/ipc_platform_file.h"
26 #include "ppapi/c/pp_errors.h"
27 #include "ppapi/c/ppb_file_io.h"
28 #include "ppapi/host/dispatch_host_message.h"
29 #include "ppapi/host/ppapi_host.h"
30 #include "ppapi/proxy/ppapi_messages.h"
31 #include "ppapi/shared_impl/file_system_util.h"
32 #include "ppapi/shared_impl/file_type_conversion.h"
33 #include "ppapi/shared_impl/time_conversion.h"
34 #include "storage/browser/file_system/file_observers.h"
35 #include "storage/browser/file_system/file_system_context.h"
36 #include "storage/browser/file_system/file_system_operation_runner.h"
37 #include "storage/browser/file_system/task_runner_bound_observer_list.h"
38 #include "storage/common/file_system/file_system_util.h"
39 
40 namespace content {
41 
42 using ppapi::FileIOStateManager;
43 using ppapi::PPTimeToTime;
44 
45 namespace {
46 
GetUIThreadStuffForInternalFileSystems(int render_process_id)47 PepperFileIOHost::UIThreadStuff GetUIThreadStuffForInternalFileSystems(
48     int render_process_id) {
49   PepperFileIOHost::UIThreadStuff stuff;
50   DCHECK_CURRENTLY_ON(BrowserThread::UI);
51   RenderProcessHost* host = RenderProcessHost::FromID(render_process_id);
52   if (host) {
53     stuff.resolved_render_process_id = host->GetProcess().Pid();
54     StoragePartition* storage_partition = host->GetStoragePartition();
55     if (storage_partition)
56       stuff.file_system_context = storage_partition->GetFileSystemContext();
57   }
58   return stuff;
59 }
60 
GetResolvedRenderProcessId(int render_process_id)61 base::ProcessId GetResolvedRenderProcessId(int render_process_id) {
62   DCHECK_CURRENTLY_ON(BrowserThread::UI);
63   RenderProcessHost* host = RenderProcessHost::FromID(render_process_id);
64   if (!host)
65     return base::kNullProcessId;
66   return host->GetProcess().Pid();
67 }
68 
GetPluginAllowedToCallRequestOSFileHandle(int render_process_id,const GURL & document_url)69 bool GetPluginAllowedToCallRequestOSFileHandle(int render_process_id,
70                                                const GURL& document_url) {
71   DCHECK_CURRENTLY_ON(BrowserThread::UI);
72   ContentBrowserClient* client = GetContentClient()->browser();
73   RenderProcessHost* host = RenderProcessHost::FromID(render_process_id);
74   if (!host)
75     return false;
76   return client->IsPluginAllowedToCallRequestOSFileHandle(
77       host->GetBrowserContext(), document_url);
78 }
79 
FileOpenForWrite(int32_t open_flags)80 bool FileOpenForWrite(int32_t open_flags) {
81   return (open_flags & (PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_APPEND)) != 0;
82 }
83 
FileCloser(base::File auto_close)84 void FileCloser(base::File auto_close) {
85 }
86 
DidCloseFile(base::OnceClosure on_close_callback)87 void DidCloseFile(base::OnceClosure on_close_callback) {
88   if (!on_close_callback.is_null())
89     std::move(on_close_callback).Run();
90 }
91 
DidOpenFile(base::WeakPtr<PepperFileIOHost> file_host,scoped_refptr<base::SequencedTaskRunner> task_runner,storage::FileSystemOperation::OpenFileCallback callback,base::File file,base::OnceClosure on_close_callback)92 void DidOpenFile(base::WeakPtr<PepperFileIOHost> file_host,
93                  scoped_refptr<base::SequencedTaskRunner> task_runner,
94                  storage::FileSystemOperation::OpenFileCallback callback,
95                  base::File file,
96                  base::OnceClosure on_close_callback) {
97   if (file_host) {
98     std::move(callback).Run(std::move(file), std::move(on_close_callback));
99   } else {
100     task_runner->PostTaskAndReply(
101         FROM_HERE, base::BindOnce(&FileCloser, std::move(file)),
102         base::BindOnce(&DidCloseFile, std::move(on_close_callback)));
103   }
104 }
105 
106 }  // namespace
107 
PepperFileIOHost(BrowserPpapiHostImpl * host,PP_Instance instance,PP_Resource resource)108 PepperFileIOHost::PepperFileIOHost(BrowserPpapiHostImpl* host,
109                                    PP_Instance instance,
110                                    PP_Resource resource)
111     : ResourceHost(host->GetPpapiHost(), instance, resource),
112       browser_ppapi_host_(host),
113       task_runner_(base::ThreadPool::CreateSequencedTaskRunner(
114           {base::MayBlock(), base::TaskPriority::USER_VISIBLE,
115            base::TaskShutdownBehavior::BLOCK_SHUTDOWN})),
116       file_(task_runner_.get()),
117       open_flags_(0),
118       file_system_type_(PP_FILESYSTEMTYPE_INVALID),
119       max_written_offset_(0),
120       check_quota_(false) {
121   int unused;
122   if (!host->GetRenderFrameIDsForInstance(
123           instance, &render_process_id_, &unused)) {
124     render_process_id_ = -1;
125   }
126 }
127 
~PepperFileIOHost()128 PepperFileIOHost::~PepperFileIOHost() {}
129 
OnResourceMessageReceived(const IPC::Message & msg,ppapi::host::HostMessageContext * context)130 int32_t PepperFileIOHost::OnResourceMessageReceived(
131     const IPC::Message& msg,
132     ppapi::host::HostMessageContext* context) {
133   PPAPI_BEGIN_MESSAGE_MAP(PepperFileIOHost, msg)
134     PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileIO_Open, OnHostMsgOpen)
135     PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileIO_Touch, OnHostMsgTouch)
136     PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileIO_SetLength,
137                                       OnHostMsgSetLength)
138     PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FileIO_Flush,
139                                         OnHostMsgFlush)
140     PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileIO_Close, OnHostMsgClose)
141     PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FileIO_RequestOSFileHandle,
142                                         OnHostMsgRequestOSFileHandle)
143   PPAPI_END_MESSAGE_MAP()
144   return PP_ERROR_FAILED;
145 }
146 
UIThreadStuff()147 PepperFileIOHost::UIThreadStuff::UIThreadStuff() {
148   resolved_render_process_id = base::kNullProcessId;
149 }
150 
151 PepperFileIOHost::UIThreadStuff::UIThreadStuff(const UIThreadStuff& other) =
152     default;
153 
~UIThreadStuff()154 PepperFileIOHost::UIThreadStuff::~UIThreadStuff() {}
155 
OnHostMsgOpen(ppapi::host::HostMessageContext * context,PP_Resource file_ref_resource,int32_t open_flags)156 int32_t PepperFileIOHost::OnHostMsgOpen(
157     ppapi::host::HostMessageContext* context,
158     PP_Resource file_ref_resource,
159     int32_t open_flags) {
160   int32_t rv = state_manager_.CheckOperationState(
161       FileIOStateManager::OPERATION_EXCLUSIVE, false);
162   if (rv != PP_OK)
163     return rv;
164 
165   int platform_file_flags = 0;
166   if (!ppapi::PepperFileOpenFlagsToPlatformFileFlags(open_flags,
167                                                      &platform_file_flags))
168     return PP_ERROR_BADARGUMENT;
169 
170   ppapi::host::ResourceHost* resource_host =
171       host()->GetResourceHost(file_ref_resource);
172   if (!resource_host || !resource_host->IsFileRefHost())
173     return PP_ERROR_BADRESOURCE;
174   PepperFileRefHost* file_ref_host =
175       static_cast<PepperFileRefHost*>(resource_host);
176   if (file_ref_host->GetFileSystemType() == PP_FILESYSTEMTYPE_INVALID)
177     return PP_ERROR_FAILED;
178 
179   file_system_host_ = file_ref_host->GetFileSystemHost();
180 
181   open_flags_ = open_flags;
182   file_system_type_ = file_ref_host->GetFileSystemType();
183   file_system_url_ = file_ref_host->GetFileSystemURL();
184 
185   // For external file systems, if there is a valid FileSystemURL, then treat
186   // it like internal file systems and access it via the FileSystemURL.
187   bool is_internal_type = (file_system_type_ != PP_FILESYSTEMTYPE_EXTERNAL) ||
188                           file_system_url_.is_valid();
189 
190   if (is_internal_type) {
191     if (!file_system_url_.is_valid())
192       return PP_ERROR_BADARGUMENT;
193 
194     // Not all external file systems are fully supported yet.
195     // Whitelist the supported ones.
196     if (file_system_url_.mount_type() == storage::kFileSystemTypeExternal) {
197       switch (file_system_url_.type()) {
198         case storage::kFileSystemTypeNativeMedia:
199         case storage::kFileSystemTypeDeviceMedia:
200           break;
201         default:
202           return PP_ERROR_NOACCESS;
203       }
204     }
205     if (!CanOpenFileSystemURLWithPepperFlags(
206             open_flags, render_process_id_, file_system_url_))
207       return PP_ERROR_NOACCESS;
208     base::PostTaskAndReplyWithResult(
209         FROM_HERE, {BrowserThread::UI},
210         base::BindOnce(&GetUIThreadStuffForInternalFileSystems,
211                        render_process_id_),
212         base::BindOnce(
213             &PepperFileIOHost::GotUIThreadStuffForInternalFileSystems,
214             AsWeakPtr(), context->MakeReplyMessageContext(),
215             platform_file_flags));
216   } else {
217     base::FilePath path = file_ref_host->GetExternalFilePath();
218     if (!CanOpenWithPepperFlags(open_flags, render_process_id_, path))
219       return PP_ERROR_NOACCESS;
220     base::PostTaskAndReplyWithResult(
221         FROM_HERE, {BrowserThread::UI},
222         base::BindOnce(&GetResolvedRenderProcessId, render_process_id_),
223         base::BindOnce(&PepperFileIOHost::GotResolvedRenderProcessId,
224                        AsWeakPtr(), context->MakeReplyMessageContext(), path,
225                        platform_file_flags));
226   }
227   state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
228   return PP_OK_COMPLETIONPENDING;
229 }
230 
GotUIThreadStuffForInternalFileSystems(ppapi::host::ReplyMessageContext reply_context,int platform_file_flags,UIThreadStuff ui_thread_stuff)231 void PepperFileIOHost::GotUIThreadStuffForInternalFileSystems(
232     ppapi::host::ReplyMessageContext reply_context,
233     int platform_file_flags,
234     UIThreadStuff ui_thread_stuff) {
235   DCHECK_CURRENTLY_ON(BrowserThread::IO);
236   file_system_context_ = ui_thread_stuff.file_system_context;
237   resolved_render_process_id_ = ui_thread_stuff.resolved_render_process_id;
238   if (resolved_render_process_id_ == base::kNullProcessId ||
239       !file_system_context_.get()) {
240     reply_context.params.set_result(PP_ERROR_FAILED);
241     SendOpenErrorReply(reply_context);
242     return;
243   }
244 
245   if (!file_system_context_->GetFileSystemBackend(file_system_url_.type())) {
246     reply_context.params.set_result(PP_ERROR_FAILED);
247     SendOpenErrorReply(reply_context);
248     return;
249   }
250 
251   DCHECK(file_system_host_.get());
252   DCHECK(file_system_host_->GetFileSystemOperationRunner());
253 
254   file_system_host_->GetFileSystemOperationRunner()->OpenFile(
255       file_system_url_, platform_file_flags,
256       base::BindOnce(&DidOpenFile, AsWeakPtr(), task_runner_,
257                      base::BindOnce(&PepperFileIOHost::DidOpenInternalFile,
258                                     AsWeakPtr(), reply_context)));
259 }
260 
DidOpenInternalFile(ppapi::host::ReplyMessageContext reply_context,base::File file,base::OnceClosure on_close_callback)261 void PepperFileIOHost::DidOpenInternalFile(
262     ppapi::host::ReplyMessageContext reply_context,
263     base::File file,
264     base::OnceClosure on_close_callback) {
265   if (file.IsValid()) {
266     on_close_callback_ = std::move(on_close_callback);
267 
268     if (FileOpenForWrite(open_flags_) && file_system_host_->ChecksQuota()) {
269       check_quota_ = true;
270       file_system_host_->OpenQuotaFile(
271           this, file_system_url_,
272           base::BindOnce(&PepperFileIOHost::DidOpenQuotaFile, AsWeakPtr(),
273                          reply_context, std::move(file)));
274       return;
275     }
276   }
277 
278   DCHECK(!file_.IsValid());
279   base::File::Error error =
280       file.IsValid() ? base::File::FILE_OK : file.error_details();
281   file_.SetFile(std::move(file));
282   SendFileOpenReply(reply_context, error);
283 }
284 
GotResolvedRenderProcessId(ppapi::host::ReplyMessageContext reply_context,base::FilePath path,int file_flags,base::ProcessId resolved_render_process_id)285 void PepperFileIOHost::GotResolvedRenderProcessId(
286     ppapi::host::ReplyMessageContext reply_context,
287     base::FilePath path,
288     int file_flags,
289     base::ProcessId resolved_render_process_id) {
290   DCHECK_CURRENTLY_ON(BrowserThread::IO);
291   resolved_render_process_id_ = resolved_render_process_id;
292   file_.CreateOrOpen(path, file_flags,
293                      base::BindOnce(&PepperFileIOHost::OnLocalFileOpened,
294                                     AsWeakPtr(), reply_context, path));
295 }
296 
OnHostMsgTouch(ppapi::host::HostMessageContext * context,PP_Time last_access_time,PP_Time last_modified_time)297 int32_t PepperFileIOHost::OnHostMsgTouch(
298     ppapi::host::HostMessageContext* context,
299     PP_Time last_access_time,
300     PP_Time last_modified_time) {
301   int32_t rv = state_manager_.CheckOperationState(
302       FileIOStateManager::OPERATION_EXCLUSIVE, true);
303   if (rv != PP_OK)
304     return rv;
305 
306   if (!file_.SetTimes(
307           PPTimeToTime(last_access_time), PPTimeToTime(last_modified_time),
308           base::BindOnce(&PepperFileIOHost::ExecutePlatformGeneralCallback,
309                          AsWeakPtr(), context->MakeReplyMessageContext()))) {
310     return PP_ERROR_FAILED;
311   }
312 
313   state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
314   return PP_OK_COMPLETIONPENDING;
315 }
316 
OnHostMsgSetLength(ppapi::host::HostMessageContext * context,int64_t length)317 int32_t PepperFileIOHost::OnHostMsgSetLength(
318     ppapi::host::HostMessageContext* context,
319     int64_t length) {
320   int32_t rv = state_manager_.CheckOperationState(
321       FileIOStateManager::OPERATION_EXCLUSIVE, true);
322   if (rv != PP_OK)
323     return rv;
324   if (length < 0)
325     return PP_ERROR_BADARGUMENT;
326 
327   // Quota checks are performed on the plugin side, in order to use the same
328   // quota reservation and request system as Write.
329 
330   if (!file_.SetLength(
331           length,
332           base::BindOnce(&PepperFileIOHost::ExecutePlatformGeneralCallback,
333                          AsWeakPtr(), context->MakeReplyMessageContext()))) {
334     return PP_ERROR_FAILED;
335   }
336 
337   state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
338   return PP_OK_COMPLETIONPENDING;
339 }
340 
OnHostMsgFlush(ppapi::host::HostMessageContext * context)341 int32_t PepperFileIOHost::OnHostMsgFlush(
342     ppapi::host::HostMessageContext* context) {
343   int32_t rv = state_manager_.CheckOperationState(
344       FileIOStateManager::OPERATION_EXCLUSIVE, true);
345   if (rv != PP_OK)
346     return rv;
347 
348   if (!file_.Flush(
349           base::BindOnce(&PepperFileIOHost::ExecutePlatformGeneralCallback,
350                          AsWeakPtr(), context->MakeReplyMessageContext()))) {
351     return PP_ERROR_FAILED;
352   }
353 
354   state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
355   return PP_OK_COMPLETIONPENDING;
356 }
357 
OnHostMsgClose(ppapi::host::HostMessageContext * context,const ppapi::FileGrowth & file_growth)358 int32_t PepperFileIOHost::OnHostMsgClose(
359     ppapi::host::HostMessageContext* context,
360     const ppapi::FileGrowth& file_growth) {
361   if (check_quota_) {
362     file_system_host_->CloseQuotaFile(this, file_growth);
363     check_quota_ = false;
364   }
365 
366   if (file_.IsValid()) {
367     file_.Close(base::BindOnce(&PepperFileIOHost::DidCloseFile, AsWeakPtr()));
368   }
369   return PP_OK;
370 }
371 
DidOpenQuotaFile(ppapi::host::ReplyMessageContext reply_context,base::File file,int64_t max_written_offset)372 void PepperFileIOHost::DidOpenQuotaFile(
373     ppapi::host::ReplyMessageContext reply_context,
374     base::File file,
375     int64_t max_written_offset) {
376   DCHECK(!file_.IsValid());
377   DCHECK(file.IsValid());
378   max_written_offset_ = max_written_offset;
379   file_.SetFile(std::move(file));
380 
381   SendFileOpenReply(reply_context, base::File::FILE_OK);
382 }
383 
DidCloseFile(base::File::Error)384 void PepperFileIOHost::DidCloseFile(base::File::Error /*error*/) {
385   // Silently ignore if we fail to close the file.
386   if (!on_close_callback_.is_null()) {
387     std::move(on_close_callback_).Run();
388   }
389 }
390 
OnHostMsgRequestOSFileHandle(ppapi::host::HostMessageContext * context)391 int32_t PepperFileIOHost::OnHostMsgRequestOSFileHandle(
392     ppapi::host::HostMessageContext* context) {
393   if (open_flags_ != PP_FILEOPENFLAG_READ && file_system_host_->ChecksQuota())
394     return PP_ERROR_FAILED;
395 
396   GURL document_url =
397       browser_ppapi_host_->GetDocumentURLForInstance(pp_instance());
398   base::PostTaskAndReplyWithResult(
399       FROM_HERE, {BrowserThread::UI},
400       base::BindOnce(&GetPluginAllowedToCallRequestOSFileHandle,
401                      render_process_id_, document_url),
402       base::BindOnce(
403           &PepperFileIOHost::GotPluginAllowedToCallRequestOSFileHandle,
404           AsWeakPtr(), context->MakeReplyMessageContext()));
405   return PP_OK_COMPLETIONPENDING;
406 }
407 
GotPluginAllowedToCallRequestOSFileHandle(ppapi::host::ReplyMessageContext reply_context,bool plugin_allowed)408 void PepperFileIOHost::GotPluginAllowedToCallRequestOSFileHandle(
409     ppapi::host::ReplyMessageContext reply_context,
410     bool plugin_allowed) {
411   DCHECK_CURRENTLY_ON(BrowserThread::IO);
412   if (!browser_ppapi_host_->external_plugin() ||
413       host()->permissions().HasPermission(ppapi::PERMISSION_PRIVATE) ||
414       plugin_allowed) {
415     if (!AddFileToReplyContext(open_flags_, &reply_context))
416       reply_context.params.set_result(PP_ERROR_FAILED);
417   } else {
418     reply_context.params.set_result(PP_ERROR_NOACCESS);
419   }
420   host()->SendReply(reply_context,
421                     PpapiPluginMsg_FileIO_RequestOSFileHandleReply());
422 }
423 
ExecutePlatformGeneralCallback(ppapi::host::ReplyMessageContext reply_context,base::File::Error error_code)424 void PepperFileIOHost::ExecutePlatformGeneralCallback(
425     ppapi::host::ReplyMessageContext reply_context,
426     base::File::Error error_code) {
427   reply_context.params.set_result(ppapi::FileErrorToPepperError(error_code));
428   host()->SendReply(reply_context, PpapiPluginMsg_FileIO_GeneralReply());
429   state_manager_.SetOperationFinished();
430 }
431 
OnLocalFileOpened(ppapi::host::ReplyMessageContext reply_context,const base::FilePath & path,base::File::Error error_code)432 void PepperFileIOHost::OnLocalFileOpened(
433     ppapi::host::ReplyMessageContext reply_context,
434     const base::FilePath& path,
435     base::File::Error error_code) {
436 #if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_BSD)
437   // Quarantining a file before its contents are available is only supported on
438   // Windows and Linux.
439   if (!FileOpenForWrite(open_flags_) || error_code != base::File::FILE_OK) {
440     SendFileOpenReply(reply_context, error_code);
441     return;
442   }
443 
444   base::PostTaskAndReplyWithResult(
445       task_runner_.get(), FROM_HERE,
446       base::BindOnce(
447           &download::QuarantineFile, path,
448           browser_ppapi_host_->GetDocumentURLForInstance(pp_instance()), GURL(),
449           std::string()),
450       base::BindOnce(&PepperFileIOHost::OnLocalFileQuarantined, AsWeakPtr(),
451                      reply_context, path));
452 #else
453   SendFileOpenReply(reply_context, error_code);
454 #endif
455 }
456 
457 #if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_BSD)
OnLocalFileQuarantined(ppapi::host::ReplyMessageContext reply_context,const base::FilePath & path,download::QuarantineFileResult quarantine_result)458 void PepperFileIOHost::OnLocalFileQuarantined(
459     ppapi::host::ReplyMessageContext reply_context,
460     const base::FilePath& path,
461     download::QuarantineFileResult quarantine_result) {
462   base::File::Error file_error =
463       (quarantine_result == download::QuarantineFileResult::OK
464            ? base::File::FILE_OK
465            : base::File::FILE_ERROR_SECURITY);
466   if (file_error != base::File::FILE_OK && file_.IsValid())
467     file_.Close(base::FileProxy::StatusCallback());
468   SendFileOpenReply(reply_context, file_error);
469 }
470 #endif
471 
SendFileOpenReply(ppapi::host::ReplyMessageContext reply_context,base::File::Error error_code)472 void PepperFileIOHost::SendFileOpenReply(
473     ppapi::host::ReplyMessageContext reply_context,
474     base::File::Error error_code) {
475   int32_t pp_error = ppapi::FileErrorToPepperError(error_code);
476   if (file_.IsValid() && !AddFileToReplyContext(open_flags_, &reply_context))
477     pp_error = PP_ERROR_FAILED;
478 
479   PP_Resource quota_file_system = 0;
480   if (pp_error == PP_OK) {
481     state_manager_.SetOpenSucceed();
482     // A non-zero resource id signals the plugin side to check quota.
483     if (check_quota_)
484       quota_file_system = file_system_host_->pp_resource();
485   }
486 
487   reply_context.params.set_result(pp_error);
488   host()->SendReply(
489       reply_context,
490       PpapiPluginMsg_FileIO_OpenReply(quota_file_system, max_written_offset_));
491   state_manager_.SetOperationFinished();
492 }
493 
SendOpenErrorReply(ppapi::host::ReplyMessageContext reply_context)494 void PepperFileIOHost::SendOpenErrorReply(
495     ppapi::host::ReplyMessageContext reply_context) {
496   host()->SendReply(reply_context, PpapiPluginMsg_FileIO_OpenReply(0, 0));
497 }
498 
AddFileToReplyContext(int32_t open_flags,ppapi::host::ReplyMessageContext * reply_context) const499 bool PepperFileIOHost::AddFileToReplyContext(
500     int32_t open_flags,
501     ppapi::host::ReplyMessageContext* reply_context) const {
502   IPC::PlatformFileForTransit transit_file =
503       IPC::GetPlatformFileForTransit(file_.GetPlatformFile(), false);
504   if (transit_file == IPC::InvalidPlatformFileForTransit())
505     return false;
506 
507   ppapi::proxy::SerializedHandle file_handle;
508   // A non-zero resource id signals NaClIPCAdapter to create a NaClQuotaDesc.
509   PP_Resource quota_file_io = check_quota_ ? pp_resource() : 0;
510   file_handle.set_file_handle(transit_file, open_flags, quota_file_io);
511   reply_context->params.AppendHandle(std::move(file_handle));
512   return true;
513 }
514 
515 }  // namespace content
516