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

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

Issue 11419131: Refactor FileIO to the new design (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Created 8 years 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
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/pepper_file_io_host.h"
6
7 #include "base/bind.h"
8 #include "base/callback_helpers.h"
9 #include "base/file_util_proxy.h"
10 #include "ppapi/c/pp_errors.h"
11 #include "ppapi/host/dispatch_host_message.h"
12 #include "ppapi/host/ppapi_host.h"
13 #include "ppapi/proxy/ppapi_messages.h"
14 #include "ppapi/shared_impl/file_type_conversion.h"
15 #include "ppapi/shared_impl/time_conversion.h"
16 #include "webkit/fileapi/file_system_callback_dispatcher.h"
17 #include "webkit/plugins/ppapi/file_callbacks.h"
18 #include "webkit/plugins/ppapi/host_globals.h"
19 #include "webkit/plugins/ppapi/ppapi_plugin_instance.h"
20 #include "webkit/plugins/ppapi/ppb_file_ref_impl.h"
21 #include "webkit/plugins/ppapi/quota_file_io.h"
22
23 namespace content {
24
25 using ppapi::PPTimeToTime;
26 using ppapi::TimeToPPTime;
27 using ppapi::thunk::PPB_FileRef_API;
28 using webkit::ppapi::PPB_FileRef_Impl;
29 using webkit::ppapi::PluginDelegate;
30
31 namespace {
32
33 // The maximum size we'll support reading in one chunk. The renderer process
34 // must allocate a buffer sized according to the request of the plugin. To
35 // keep things from getting out of control, we cap the read size to this value.
36 // This should generally be OK since the API specifies that it may perform a
37 // partial read.
38 static const int32_t kMaxReadSize = 32 * 1024 * 1024; // 32MB
39
40 typedef base::Callback<void (base::PlatformFileError)> PlatformGeneralCallback;
41
42 class PlatformGeneralCallbackTranslator
43 : public fileapi::FileSystemCallbackDispatcher {
44 public:
45 PlatformGeneralCallbackTranslator(const PlatformGeneralCallback& callback)
46 : callback_(callback) {}
47
48 virtual ~PlatformGeneralCallbackTranslator() {}
49
50 virtual void DidSucceed() OVERRIDE {
51 callback_.Run(base::PLATFORM_FILE_OK);
52 }
53
54 virtual void DidReadMetadata(const base::PlatformFileInfo& file_info,
55 const FilePath& platform_path) OVERRIDE {
56 NOTREACHED();
57 }
58
59 virtual void DidReadDirectory(
60 const std::vector<base::FileUtilProxy::Entry>& entries,
61 bool has_more) OVERRIDE {
62 NOTREACHED();
63 }
64
65 virtual void DidOpenFileSystem(const std::string& name,
66 const GURL& root) OVERRIDE {
67 NOTREACHED();
68 }
69
70 virtual void DidFail(base::PlatformFileError error_code) OVERRIDE {
71 callback_.Run(error_code);
72 }
73
74 virtual void DidWrite(int64 bytes, bool complete) OVERRIDE {
75 NOTREACHED();
76 }
77
78 virtual void DidOpenFile(base::PlatformFile file) OVERRIDE {
79 NOTREACHED();
80 }
81
82 private:
83 PlatformGeneralCallback callback_;
84 };
85
86 int32_t ErrorOrByteNumber(int32_t pp_error, int32_t byte_number) {
87 // On the plugin side, some callbacks expect a parameter that means different
88 // things depending on whether is negative or not. We translate for those
89 // callbacks here.
90 return pp_error == PP_OK ? byte_number : pp_error;
91 }
92
93 } // namespace
94
95 PepperFileIOHost::PepperFileIOHost(RendererPpapiHost* host,
96 PP_Instance instance,
97 PP_Resource resource)
98 : ResourceHost(host->GetPpapiHost(), instance, resource),
99 ppapi::PPB_FileIO_Shared(),
100 file_(base::kInvalidPlatformFileValue),
101 file_system_type_(PP_FILESYSTEMTYPE_INVALID),
102 weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
103 // TODO: eliminate plugin_delegate_ as it's no longer needed.
104 webkit::ppapi::PluginInstance* plugin_instance =
105 webkit::ppapi::HostGlobals::Get()->GetInstance(instance);
106 plugin_delegate_ = plugin_instance ? plugin_instance->delegate() : NULL;
107 }
108
109 PepperFileIOHost::~PepperFileIOHost() {
110 OnHostMsgClose(NULL);
111 }
112
113 int32_t PepperFileIOHost::OnResourceMessageReceived(
114 const IPC::Message& msg,
115 ppapi::host::HostMessageContext* context) {
116 IPC_BEGIN_MESSAGE_MAP(PepperFileIOHost, msg)
117 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileIO_Open,
118 OnHostMsgOpen)
119 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FileIO_Query,
120 OnHostMsgQuery)
121 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileIO_Touch,
122 OnHostMsgTouch)
123 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileIO_Read,
124 OnHostMsgRead)
125 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileIO_Write,
126 OnHostMsgWrite)
127 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileIO_SetLength,
128 OnHostMsgSetLength)
129 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FileIO_Flush,
130 OnHostMsgFlush)
131 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FileIO_Close,
132 OnHostMsgClose)
133 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileIO_WillWrite,
134 OnHostMsgWillWrite)
135 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileIO_WillSetLength,
136 OnHostMsgWillSetLength)
137 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FileIO_GetOSFileDescriptor,
138 OnHostMsgGetOSFileDescriptor)
139 IPC_END_MESSAGE_MAP()
140 return PP_ERROR_FAILED;
141 }
142
143 int32_t PepperFileIOHost::OnHostMsgOpen(
144 ppapi::host::HostMessageContext* context,
145 PP_Resource file_ref_resource,
146 int32_t open_flags) {
147 temp_reply_context_ = context->MakeReplyMessageContext();
148 return DoOpen(file_ref_resource, open_flags);
149 }
150
151 int32_t PepperFileIOHost::OnHostMsgQuery(
152 ppapi::host::HostMessageContext* context) {
153 temp_reply_context_ = context->MakeReplyMessageContext();
154 return DoQuery();
155 }
156
157 int32_t PepperFileIOHost::OnHostMsgTouch(
158 ppapi::host::HostMessageContext* context,
159 PP_Time last_access_time,
160 PP_Time last_modified_time) {
161 temp_reply_context_ = context->MakeReplyMessageContext();
162 return DoTouch(last_access_time, last_modified_time);
163 }
164
165 int32_t PepperFileIOHost::OnHostMsgRead(
166 ppapi::host::HostMessageContext* context,
167 int64_t offset,
168 int32_t bytes_to_read) {
169 // Validate bytes_to_read before allocating below. This value is coming from
170 // the untrusted plugin.
171 if (bytes_to_read < 0) {
172 ppapi::host::ReplyMessageContext reply_context =
173 context->MakeReplyMessageContext();
174 reply_context.params.set_result(PP_ERROR_FAILED);
175 host()->SendReply(reply_context,
176 PpapiPluginMsg_FileIO_ReadComplete(std::string()));
177 return PP_OK_COMPLETIONPENDING;
178 }
179
180 temp_reply_context_ = context->MakeReplyMessageContext();
181 return DoRead(offset, std::min(bytes_to_read, kMaxReadSize));
182 }
183
184 int32_t PepperFileIOHost::OnHostMsgWrite(
185 ppapi::host::HostMessageContext* context,
186 int64_t offset,
187 const std::string& buffer) {
188 temp_reply_context_ = context->MakeReplyMessageContext();
189 return DoWrite(offset, buffer.c_str(), buffer.size());
190 }
191
192 int32_t PepperFileIOHost::OnHostMsgSetLength(
193 ppapi::host::HostMessageContext* context,
194 int64_t length) {
195 temp_reply_context_ = context->MakeReplyMessageContext();
196 return DoSetLength(length);
197 }
198
199 int32_t PepperFileIOHost::OnHostMsgFlush(
200 ppapi::host::HostMessageContext* context) {
201 temp_reply_context_ = context->MakeReplyMessageContext();
202 return DoFlush();
203 }
204
205 int32_t PepperFileIOHost::OnHostMsgClose(
206 ppapi::host::HostMessageContext* context) {
207 if (file_ != base::kInvalidPlatformFileValue && plugin_delegate_) {
208 base::FileUtilProxy::Close(
209 plugin_delegate_->GetFileThreadMessageLoopProxy(),
210 file_,
211 base::ResetAndReturn(&notify_close_file_callback_));
212 file_ = base::kInvalidPlatformFileValue;
213 quota_file_io_.reset();
214 }
215 return PP_OK;
216 }
217
218 int32_t PepperFileIOHost::OnHostMsgWillWrite(
219 ppapi::host::HostMessageContext* context,
220 int64_t offset,
221 int32_t bytes_to_write) {
222 int32_t rv = CommonPreCondition(true, OPERATION_EXCLUSIVE);
223 if (rv != PP_OK)
224 return rv;
225
226 if (!quota_file_io_.get())
227 return PP_OK;
228
229 if (!quota_file_io_->WillWrite(
230 offset, bytes_to_write,
231 base::Bind(&PepperFileIOHost::ExecutePlatformWillWriteCallback,
232 weak_factory_.GetWeakPtr(),
233 context->MakeReplyMessageContext())))
234 return PP_ERROR_FAILED;
235
236 CommonPostCondition(OPERATION_EXCLUSIVE);
237 return PP_OK_COMPLETIONPENDING;
238 }
239
240 int32_t PepperFileIOHost::OnHostMsgWillSetLength(
241 ppapi::host::HostMessageContext* context,
242 int64_t length) {
243 int32_t rv = CommonPreCondition(true, OPERATION_EXCLUSIVE);
244 if (rv != PP_OK)
245 return rv;
246
247 if (!quota_file_io_.get())
248 return PP_OK;
249
250 if (!quota_file_io_->WillSetLength(
251 length,
252 base::Bind(&PepperFileIOHost::ExecutePlatformGeneralCallback,
253 weak_factory_.GetWeakPtr(),
254 context->MakeReplyMessageContext())))
255 return PP_ERROR_FAILED;
256
257 CommonPostCondition(OPERATION_EXCLUSIVE);
258 return PP_OK_COMPLETIONPENDING;
259 }
260
261 int32_t PepperFileIOHost::OnHostMsgGetOSFileDescriptor(
262 ppapi::host::HostMessageContext* context) {
263 //if (!host()->IsRunningInProcess())
264 // return PP_ERROR_FAILED;
265 int32_t fd =
266 #if defined(OS_POSIX)
267 file_;
268 #elif defined(OS_WIN)
269 reinterpret_cast<uintptr_t>(file_);
270 #else
271 -1; // Platform not supported.
272 #endif
273 // TODO: Pass file handle instead.
raymes1 2012/11/28 05:26:27 -Please add your username to all TODOs -TODO(victo
victorhsieh 2012/11/28 07:11:04 Sure. I'll try to fix the TODO in this week befor
274 host()->SendReply(context->MakeReplyMessageContext(),
275 PpapiPluginMsg_FileIO_GetOSFileDescriptorReply(fd));
276 return PP_OK_COMPLETIONPENDING;
277 }
278
279 int32_t PepperFileIOHost::CommonPreCondition(bool should_be_open,
280 OperationType new_op) {
281 if (!plugin_delegate_)
282 return PP_ERROR_FAILED;
283 return PPB_FileIO_Shared::CommonPreCondition(should_be_open, new_op);
284 }
285
286 int32_t PepperFileIOHost::OpenValidated(
287 PP_Resource file_ref_resource,
288 PPB_FileRef_API* file_ref_api,
289 int32_t open_flags) {
290 int flags = 0;
291 if (!::ppapi::PepperFileOpenFlagsToPlatformFileFlags(open_flags, &flags))
292 return PP_ERROR_BADARGUMENT;
293
294 PP_FileSystemType type = file_ref_api->GetFileSystemType();
295 if (type != PP_FILESYSTEMTYPE_LOCALPERSISTENT &&
296 type != PP_FILESYSTEMTYPE_LOCALTEMPORARY &&
297 type != PP_FILESYSTEMTYPE_EXTERNAL)
298 return PP_ERROR_FAILED;
299 file_system_type_ = type;
300
301 PPB_FileRef_Impl* file_ref = static_cast<PPB_FileRef_Impl*>(file_ref_api);
302 if (file_ref->HasValidFileSystem()) {
303 file_system_url_ = file_ref->GetFileSystemURL();
304 if (!plugin_delegate_->AsyncOpenFileSystemURL(
305 file_system_url_, flags,
306 base::Bind(
307 &PepperFileIOHost::ExecutePlatformOpenFileSystemURLCallback,
308 weak_factory_.GetWeakPtr(),
309 temp_reply_context_)))
310 return PP_ERROR_FAILED;
311 } else {
312 if (file_system_type_ != PP_FILESYSTEMTYPE_EXTERNAL)
313 return PP_ERROR_FAILED;
314 if (!plugin_delegate_->AsyncOpenFile(
315 file_ref->GetSystemPath(), flags,
316 base::Bind(&PepperFileIOHost::ExecutePlatformOpenFileCallback,
317 weak_factory_.GetWeakPtr(),
318 temp_reply_context_)))
319 return PP_ERROR_FAILED;
320 }
321
322 return PP_OK_COMPLETIONPENDING;
323 }
324
325 int32_t PepperFileIOHost::QueryValidated() {
326 if (!base::FileUtilProxy::GetFileInfoFromPlatformFile(
327 plugin_delegate_->GetFileThreadMessageLoopProxy(), file_,
328 base::Bind(&PepperFileIOHost::ExecutePlatformQueryCallback,
329 weak_factory_.GetWeakPtr(),
330 temp_reply_context_)))
331 return PP_ERROR_FAILED;
332
333 return PP_OK_COMPLETIONPENDING;
334 }
335
336 int32_t PepperFileIOHost::TouchValidated(
337 PP_Time last_access_time,
338 PP_Time last_modified_time) {
339 if (file_system_type_ != PP_FILESYSTEMTYPE_EXTERNAL) {
340 if (!plugin_delegate_->Touch(
341 file_system_url_,
342 PPTimeToTime(last_access_time),
343 PPTimeToTime(last_modified_time),
344 new PlatformGeneralCallbackTranslator(
345 base::Bind(&PepperFileIOHost::ExecutePlatformGeneralCallback,
346 weak_factory_.GetWeakPtr(),
347 temp_reply_context_))))
348 return PP_ERROR_FAILED;
349 return PP_OK_COMPLETIONPENDING;
350 }
351
352 // TODO(nhiroki): fix a failure of FileIO.Touch for an external filesystem on
353 // Mac and Linux due to sandbox restrictions (http://crbug.com/101128).
354 if (!base::FileUtilProxy::Touch(
355 plugin_delegate_->GetFileThreadMessageLoopProxy(),
356 file_, PPTimeToTime(last_access_time),
357 PPTimeToTime(last_modified_time),
358 base::Bind(&PepperFileIOHost::ExecutePlatformGeneralCallback,
359 weak_factory_.GetWeakPtr(),
360 temp_reply_context_)))
361 return PP_ERROR_FAILED;
362
363 return PP_OK_COMPLETIONPENDING;
364 }
365
366 int32_t PepperFileIOHost::ReadValidated(
367 int64_t offset,
368 int32_t max_read_length) {
369 if (!base::FileUtilProxy::Read(
370 plugin_delegate_->GetFileThreadMessageLoopProxy(), file_, offset,
371 max_read_length,
372 base::Bind(&PepperFileIOHost::ExecutePlatformReadCallback,
373 weak_factory_.GetWeakPtr(),
374 temp_reply_context_)))
375 return PP_ERROR_FAILED;
376
377 return PP_OK_COMPLETIONPENDING;
378 }
379
380 int32_t PepperFileIOHost::WriteValidated(
381 int64_t offset,
382 const char* buffer,
383 int32_t bytes_to_write) {
384 if (quota_file_io_.get()) {
385 if (!quota_file_io_->Write(
386 offset, buffer, bytes_to_write,
387 base::Bind(&PepperFileIOHost::ExecutePlatformWriteCallback,
388 weak_factory_.GetWeakPtr(),
389 temp_reply_context_)))
390 return PP_ERROR_FAILED;
391 } else {
392 if (!base::FileUtilProxy::Write(
393 plugin_delegate_->GetFileThreadMessageLoopProxy(), file_, offset,
394 buffer, bytes_to_write,
395 base::Bind(&PepperFileIOHost::ExecutePlatformWriteCallback,
396 weak_factory_.GetWeakPtr(),
397 temp_reply_context_)))
398 return PP_ERROR_FAILED;
399 }
400
401 return PP_OK_COMPLETIONPENDING;
402 }
403
404 int32_t PepperFileIOHost::SetLengthValidated(
405 int64_t length) {
406 if (file_system_type_ != PP_FILESYSTEMTYPE_EXTERNAL) {
407 if (!plugin_delegate_->SetLength(
408 file_system_url_, length,
409 new PlatformGeneralCallbackTranslator(
410 base::Bind(&PepperFileIOHost::ExecutePlatformGeneralCallback,
411 weak_factory_.GetWeakPtr(),
412 temp_reply_context_))))
413 return PP_ERROR_FAILED;
414 } else {
415 // TODO(nhiroki): fix a failure of FileIO.SetLength for an external
416 // filesystem on Mac due to sandbox restrictions (http://crbug.com/156077).
417 if (!base::FileUtilProxy::Truncate(
418 plugin_delegate_->GetFileThreadMessageLoopProxy(), file_, length,
419 base::Bind(&PepperFileIOHost::ExecutePlatformGeneralCallback,
420 weak_factory_.GetWeakPtr(),
421 temp_reply_context_)))
422 return PP_ERROR_FAILED;
423 }
424
425 return PP_OK_COMPLETIONPENDING;
426 }
427
428 int32_t PepperFileIOHost::FlushValidated() {
429 if (!base::FileUtilProxy::Flush(
430 plugin_delegate_->GetFileThreadMessageLoopProxy(), file_,
431 base::Bind(&PepperFileIOHost::ExecutePlatformGeneralCallback,
432 weak_factory_.GetWeakPtr(),
433 temp_reply_context_)))
434 return PP_ERROR_FAILED;
435
436 return PP_OK_COMPLETIONPENDING;
437 }
438
439 void PepperFileIOHost::ExecutePlatformGeneralCallback(
440 ppapi::host::ReplyMessageContext reply_context,
441 base::PlatformFileError error_code) {
442 reply_context.params.set_result(
443 ::ppapi::PlatformFileErrorToPepperError(error_code));
444 host()->SendReply(reply_context, PpapiPluginMsg_FileIO_GeneralComplete());
445 SetOpFinished();
446 }
447
448 void PepperFileIOHost::ExecutePlatformOpenFileCallback(
449 ppapi::host::ReplyMessageContext reply_context,
450 base::PlatformFileError error_code,
451 base::PassPlatformFile file) {
452 int32_t pp_error = ::ppapi::PlatformFileErrorToPepperError(error_code);
453 if (pp_error == PP_OK)
454 SetOpenSucceed();
455
456 DCHECK(file_ == base::kInvalidPlatformFileValue);
457 file_ = file.ReleaseValue();
458
459 DCHECK(!quota_file_io_.get());
460 if (file_ != base::kInvalidPlatformFileValue &&
461 (file_system_type_ == PP_FILESYSTEMTYPE_LOCALTEMPORARY ||
462 file_system_type_ == PP_FILESYSTEMTYPE_LOCALPERSISTENT)) {
463 quota_file_io_.reset(new webkit::ppapi::QuotaFileIO(
464 pp_instance(), file_, file_system_url_, file_system_type_));
465 }
466
467 reply_context.params.set_result(pp_error);
468 host()->SendReply(reply_context, PpapiPluginMsg_FileIO_OpenFileComplete());
469 SetOpFinished();
470 }
471
472 void PepperFileIOHost::ExecutePlatformOpenFileSystemURLCallback(
473 ppapi::host::ReplyMessageContext reply_context,
474 base::PlatformFileError error_code,
475 base::PassPlatformFile file,
476 const PluginDelegate::NotifyCloseFileCallback& callback) {
477 if (error_code == base::PLATFORM_FILE_OK)
478 notify_close_file_callback_ = callback;
479 ExecutePlatformOpenFileCallback(reply_context, error_code, file);
480 }
481
482 void PepperFileIOHost::ExecutePlatformQueryCallback(
483 ppapi::host::ReplyMessageContext reply_context,
484 base::PlatformFileError error_code,
485 const base::PlatformFileInfo& file_info) {
486 PP_FileInfo pp_info;
487 pp_info.size = file_info.size;
488 pp_info.creation_time = TimeToPPTime(file_info.creation_time);
489 pp_info.last_access_time = TimeToPPTime(file_info.last_accessed);
490 pp_info.last_modified_time = TimeToPPTime(file_info.last_modified);
491 pp_info.system_type = file_system_type_;
492 if (file_info.is_directory)
493 pp_info.type = PP_FILETYPE_DIRECTORY;
494 else
495 pp_info.type = PP_FILETYPE_REGULAR;
496
497 int32_t pp_error = ::ppapi::PlatformFileErrorToPepperError(error_code);
498 reply_context.params.set_result(pp_error);
499 host()->SendReply(reply_context,
500 PpapiPluginMsg_FileIO_QueryComplete(pp_info));
501 SetOpFinished();
502 }
503
504 void PepperFileIOHost::ExecutePlatformReadCallback(
505 ppapi::host::ReplyMessageContext reply_context,
506 base::PlatformFileError error_code,
507 const char* data, int bytes_read) {
508 int32_t pp_error = ::ppapi::PlatformFileErrorToPepperError(error_code);
509
510 // Only send the amount of data in the string that was actually read.
511 std::string buffer;
512 if (pp_error == PP_OK)
513 buffer.append(data, bytes_read);
514 reply_context.params.set_result(ErrorOrByteNumber(pp_error, bytes_read));
515 host()->SendReply(reply_context, PpapiPluginMsg_FileIO_ReadComplete(buffer));
516 SetOpFinished();
517 }
518
519 void PepperFileIOHost::ExecutePlatformWriteCallback(
520 ppapi::host::ReplyMessageContext reply_context,
521 base::PlatformFileError error_code,
522 int bytes_written) {
523 int32_t pp_error = ::ppapi::PlatformFileErrorToPepperError(error_code);
524 reply_context.params.set_result(ErrorOrByteNumber(pp_error, bytes_written));
525 host()->SendReply(reply_context, PpapiPluginMsg_FileIO_GeneralComplete());
526 SetOpFinished();
527 }
528
529 void PepperFileIOHost::ExecutePlatformWillWriteCallback(
530 ppapi::host::ReplyMessageContext reply_context,
531 base::PlatformFileError error_code,
532 int bytes_written) {
533 // On the plugin side, the callback expects a parameter with different meaning
534 // depends on whether is negative or not. It is the result here. We
535 // translate for the callback.
536 int32_t pp_error = ::ppapi::PlatformFileErrorToPepperError(error_code);
537 reply_context.params.set_result(ErrorOrByteNumber(pp_error, bytes_written));
538 host()->SendReply(reply_context, PpapiPluginMsg_FileIO_GeneralComplete());
539 SetOpFinished();
540 }
541
542 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698