file_io_resource.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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 "ppapi/proxy/file_io_resource.h"
6
7#include "base/bind.h"
8#include "ipc/ipc_message.h"
9#include "ppapi/c/pp_errors.h"
10#include "ppapi/proxy/ppapi_messages.h"
11#include "ppapi/shared_impl/array_writer.h"
12#include "ppapi/shared_impl/ppapi_globals.h"
13#include "ppapi/shared_impl/resource_tracker.h"
14#include "ppapi/thunk/enter.h"
15#include "ppapi/thunk/ppb_file_ref_api.h"
16
17using ppapi::thunk::EnterResourceNoLock;
18using ppapi::thunk::PPB_FileIO_API;
19using ppapi::thunk::PPB_FileRef_API;
20
21namespace {
22
23// An adapter to let Read() share the same implementation with ReadToArray().
24void* DummyGetDataBuffer(void* user_data, uint32_t count, uint32_t size) {
25  return user_data;
26}
27
28}  // namespace
29
30namespace ppapi {
31namespace proxy {
32
33FileIOResource::FileIOResource(Connection connection, PP_Instance instance)
34    : PluginResource(connection, instance) {
35  SendCreate(RENDERER, PpapiHostMsg_FileIO_Create());
36}
37
38FileIOResource::~FileIOResource() {
39}
40
41PPB_FileIO_API* FileIOResource::AsPPB_FileIO_API() {
42  return this;
43}
44
45int32_t FileIOResource::Open(PP_Resource file_ref,
46                             int32_t open_flags,
47                             scoped_refptr<TrackedCallback> callback) {
48  EnterResourceNoLock<PPB_FileRef_API> enter(file_ref, true);
49  if (enter.failed())
50    return PP_ERROR_BADRESOURCE;
51
52  int32_t rv = state_manager_.CheckOperationState(
53      FileIOStateManager::OPERATION_EXCLUSIVE, false);
54  if (rv != PP_OK)
55    return rv;
56
57  Call<PpapiPluginMsg_FileIO_OpenReply>(RENDERER,
58      PpapiHostMsg_FileIO_Open(
59          enter.resource()->host_resource().host_resource(),
60          open_flags),
61      base::Bind(&FileIOResource::OnPluginMsgOpenFileComplete, this,
62                 callback));
63
64  state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
65  return PP_OK_COMPLETIONPENDING;
66}
67
68int32_t FileIOResource::Query(PP_FileInfo* info,
69                              scoped_refptr<TrackedCallback> callback) {
70  int32_t rv = state_manager_.CheckOperationState(
71      FileIOStateManager::OPERATION_EXCLUSIVE, true);
72  if (rv != PP_OK)
73    return rv;
74
75  Call<PpapiPluginMsg_FileIO_QueryReply>(RENDERER,
76      PpapiHostMsg_FileIO_Query(),
77      base::Bind(&FileIOResource::OnPluginMsgQueryComplete, this,
78                 callback, info));
79
80  state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
81  return PP_OK_COMPLETIONPENDING;
82}
83
84int32_t FileIOResource::Touch(PP_Time last_access_time,
85                              PP_Time last_modified_time,
86                              scoped_refptr<TrackedCallback> callback) {
87  int32_t rv = state_manager_.CheckOperationState(
88      FileIOStateManager::OPERATION_EXCLUSIVE, true);
89  if (rv != PP_OK)
90    return rv;
91
92  Call<PpapiPluginMsg_FileIO_GeneralReply>(RENDERER,
93      PpapiHostMsg_FileIO_Touch(last_access_time, last_modified_time),
94      base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this,
95                 callback));
96
97  state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
98  return PP_OK_COMPLETIONPENDING;
99}
100
101int32_t FileIOResource::Read(int64_t offset,
102                             char* buffer,
103                             int32_t bytes_to_read,
104                             scoped_refptr<TrackedCallback> callback) {
105  int32_t rv = state_manager_.CheckOperationState(
106      FileIOStateManager::OPERATION_READ, true);
107  if (rv != PP_OK)
108    return rv;
109
110  PP_ArrayOutput output_adapter;
111  output_adapter.GetDataBuffer = &DummyGetDataBuffer;
112  output_adapter.user_data = buffer;
113  state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_READ);
114  return ReadValidated(offset, bytes_to_read, output_adapter, callback);
115}
116
117int32_t FileIOResource::ReadToArray(int64_t offset,
118                                    int32_t max_read_length,
119                                    PP_ArrayOutput* array_output,
120                                    scoped_refptr<TrackedCallback> callback) {
121  DCHECK(array_output);
122  int32_t rv = state_manager_.CheckOperationState(
123      FileIOStateManager::OPERATION_READ, true);
124  if (rv != PP_OK)
125    return rv;
126
127  state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_READ);
128  return ReadValidated(offset, max_read_length, *array_output, callback);
129}
130
131int32_t FileIOResource::Write(int64_t offset,
132                              const char* buffer,
133                              int32_t bytes_to_write,
134                              scoped_refptr<TrackedCallback> callback) {
135  int32_t rv = state_manager_.CheckOperationState(
136      FileIOStateManager::OPERATION_WRITE, true);
137  if (rv != PP_OK)
138    return rv;
139
140  // TODO(brettw) it would be nice to use a shared memory buffer for large
141  // writes rather than having to copy to a string (which will involve a number
142  // of extra copies to serialize over IPC).
143  Call<PpapiPluginMsg_FileIO_GeneralReply>(RENDERER,
144      PpapiHostMsg_FileIO_Write(offset, std::string(buffer, bytes_to_write)),
145      base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this,
146                 callback));
147
148  state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_WRITE);
149  return PP_OK_COMPLETIONPENDING;
150}
151
152int32_t FileIOResource::SetLength(int64_t length,
153                                  scoped_refptr<TrackedCallback> callback) {
154  int32_t rv = state_manager_.CheckOperationState(
155      FileIOStateManager::OPERATION_EXCLUSIVE, true);
156  if (rv != PP_OK)
157    return rv;
158
159  Call<PpapiPluginMsg_FileIO_GeneralReply>(RENDERER,
160      PpapiHostMsg_FileIO_SetLength(length),
161      base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this,
162                 callback));
163
164  state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
165  return PP_OK_COMPLETIONPENDING;
166}
167
168int32_t FileIOResource::Flush(scoped_refptr<TrackedCallback> callback) {
169  int32_t rv = state_manager_.CheckOperationState(
170      FileIOStateManager::OPERATION_EXCLUSIVE, true);
171  if (rv != PP_OK)
172    return rv;
173
174  Call<PpapiPluginMsg_FileIO_GeneralReply>(RENDERER,
175      PpapiHostMsg_FileIO_Flush(),
176      base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this,
177                 callback));
178
179  state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
180  return PP_OK_COMPLETIONPENDING;
181}
182
183void FileIOResource::Close() {
184  Post(RENDERER, PpapiHostMsg_FileIO_Close());
185}
186
187int32_t FileIOResource::GetOSFileDescriptor() {
188  int32_t file_descriptor;
189  // Only available when running in process.
190  SyncCall<PpapiPluginMsg_FileIO_GetOSFileDescriptorReply>(
191      RENDERER, PpapiHostMsg_FileIO_GetOSFileDescriptor(), &file_descriptor);
192  return file_descriptor;
193}
194
195int32_t FileIOResource::WillWrite(int64_t offset,
196                                  int32_t bytes_to_write,
197                                  scoped_refptr<TrackedCallback> callback) {
198  Call<PpapiPluginMsg_FileIO_GeneralReply>(RENDERER,
199      PpapiHostMsg_FileIO_WillWrite(offset, bytes_to_write),
200      base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this,
201                 callback));
202  state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
203  return PP_OK_COMPLETIONPENDING;
204}
205
206int32_t FileIOResource::WillSetLength(int64_t length,
207                                      scoped_refptr<TrackedCallback> callback) {
208  Call<PpapiPluginMsg_FileIO_GeneralReply>(RENDERER,
209      PpapiHostMsg_FileIO_WillSetLength(length),
210      base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this,
211                 callback));
212  state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
213  return PP_OK_COMPLETIONPENDING;
214}
215
216int32_t FileIOResource::ReadValidated(int64_t offset,
217                                      int32_t bytes_to_read,
218                                      const PP_ArrayOutput& array_output,
219                                      scoped_refptr<TrackedCallback> callback) {
220  Call<PpapiPluginMsg_FileIO_ReadReply>(RENDERER,
221      PpapiHostMsg_FileIO_Read(offset, bytes_to_read),
222      base::Bind(&FileIOResource::OnPluginMsgReadComplete, this,
223                 callback, array_output));
224  return PP_OK_COMPLETIONPENDING;
225}
226
227int32_t FileIOResource::RequestOSFileHandle(
228    PP_FileHandle* handle,
229    scoped_refptr<TrackedCallback> callback) {
230  int32_t rv = state_manager_.CheckOperationState(
231      FileIOStateManager::OPERATION_EXCLUSIVE, true);
232  if (rv != PP_OK)
233    return rv;
234
235  Call<PpapiPluginMsg_FileIO_RequestOSFileHandleReply>(RENDERER,
236      PpapiHostMsg_FileIO_RequestOSFileHandle(),
237      base::Bind(&FileIOResource::OnPluginMsgRequestOSFileHandleComplete, this,
238                 callback, handle));
239
240  state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
241  return PP_OK_COMPLETIONPENDING;
242}
243
244void FileIOResource::OnPluginMsgGeneralComplete(
245    scoped_refptr<TrackedCallback> callback,
246    const ResourceMessageReplyParams& params) {
247  DCHECK(state_manager_.get_pending_operation() ==
248         FileIOStateManager::OPERATION_EXCLUSIVE ||
249         state_manager_.get_pending_operation() ==
250         FileIOStateManager::OPERATION_WRITE);
251  // End the operation now. The callback may perform another file operation.
252  state_manager_.SetOperationFinished();
253  callback->Run(params.result());
254}
255
256void FileIOResource::OnPluginMsgOpenFileComplete(
257    scoped_refptr<TrackedCallback> callback,
258    const ResourceMessageReplyParams& params) {
259  DCHECK(state_manager_.get_pending_operation() ==
260         FileIOStateManager::OPERATION_EXCLUSIVE);
261  if (params.result() == PP_OK)
262    state_manager_.SetOpenSucceed();
263  // End the operation now. The callback may perform another file operation.
264  state_manager_.SetOperationFinished();
265  callback->Run(params.result());
266}
267
268void FileIOResource::OnPluginMsgQueryComplete(
269    scoped_refptr<TrackedCallback> callback,
270    PP_FileInfo* output_info,
271    const ResourceMessageReplyParams& params,
272    const PP_FileInfo& info) {
273  DCHECK(state_manager_.get_pending_operation() ==
274         FileIOStateManager::OPERATION_EXCLUSIVE);
275  *output_info = info;
276  // End the operation now. The callback may perform another file operation.
277  state_manager_.SetOperationFinished();
278  callback->Run(params.result());
279}
280
281void FileIOResource::OnPluginMsgReadComplete(
282    scoped_refptr<TrackedCallback> callback,
283    PP_ArrayOutput array_output,
284    const ResourceMessageReplyParams& params,
285    const std::string& data) {
286  DCHECK(state_manager_.get_pending_operation() ==
287         FileIOStateManager::OPERATION_READ);
288
289  // The result code should contain the data size if it's positive.
290  int32_t result = params.result();
291  DCHECK((result < 0 && data.size() == 0) ||
292         result == static_cast<int32_t>(data.size()));
293
294  ArrayWriter output;
295  output.set_pp_array_output(array_output);
296  if (output.is_valid())
297    output.StoreArray(data.data(), std::max(0, result));
298  else
299    result = PP_ERROR_FAILED;
300
301  // End the operation now. The callback may perform another file operation.
302  state_manager_.SetOperationFinished();
303  callback->Run(result);
304}
305
306void FileIOResource::OnPluginMsgRequestOSFileHandleComplete(
307    scoped_refptr<TrackedCallback> callback,
308    PP_FileHandle* output_handle,
309    const ResourceMessageReplyParams& params) {
310  DCHECK(state_manager_.get_pending_operation() ==
311         FileIOStateManager::OPERATION_EXCLUSIVE);
312
313  if (!TrackedCallback::IsPending(callback)) {
314    state_manager_.SetOperationFinished();
315    return;
316  }
317
318  int32_t result = params.result();
319  IPC::PlatformFileForTransit transit_file;
320  if (!params.TakeFileHandleAtIndex(0, &transit_file))
321    result = PP_ERROR_FAILED;
322  *output_handle = IPC::PlatformFileForTransitToPlatformFile(transit_file);
323
324  // End the operation now. The callback may perform another file operation.
325  state_manager_.SetOperationFinished();
326  callback->Run(result);
327}
328
329}  // namespace proxy
330}  // namespace ppapi
331