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 #ifndef PPAPI_PROXY_FILE_IO_RESOURCE_H_ 6 #define PPAPI_PROXY_FILE_IO_RESOURCE_H_ 7 8 #include <string> 9 10 #include "base/memory/ref_counted.h" 11 #include "base/memory/scoped_ptr.h" 12 #include "ppapi/c/private/pp_file_handle.h" 13 #include "ppapi/proxy/connection.h" 14 #include "ppapi/proxy/plugin_resource.h" 15 #include "ppapi/proxy/ppapi_proxy_export.h" 16 #include "ppapi/shared_impl/file_io_state_manager.h" 17 #include "ppapi/shared_impl/resource.h" 18 #include "ppapi/shared_impl/scoped_pp_resource.h" 19 #include "ppapi/thunk/ppb_file_io_api.h" 20 21 namespace ppapi { 22 23 class TrackedCallback; 24 25 namespace proxy { 26 27 class PPAPI_PROXY_EXPORT FileIOResource 28 : public PluginResource, 29 public thunk::PPB_FileIO_API { 30 public: 31 FileIOResource(Connection connection, PP_Instance instance); 32 virtual ~FileIOResource(); 33 34 // Resource overrides. 35 virtual thunk::PPB_FileIO_API* AsPPB_FileIO_API() OVERRIDE; 36 37 // PPB_FileIO_API implementation. 38 virtual int32_t Open(PP_Resource file_ref, 39 int32_t open_flags, 40 scoped_refptr<TrackedCallback> callback) OVERRIDE; 41 virtual int32_t Query(PP_FileInfo* info, 42 scoped_refptr<TrackedCallback> callback) OVERRIDE; 43 virtual int32_t Touch(PP_Time last_access_time, 44 PP_Time last_modified_time, 45 scoped_refptr<TrackedCallback> callback) OVERRIDE; 46 virtual int32_t Read(int64_t offset, 47 char* buffer, 48 int32_t bytes_to_read, 49 scoped_refptr<TrackedCallback> callback) OVERRIDE; 50 virtual int32_t ReadToArray(int64_t offset, 51 int32_t max_read_length, 52 PP_ArrayOutput* array_output, 53 scoped_refptr<TrackedCallback> callback) OVERRIDE; 54 virtual int32_t Write(int64_t offset, 55 const char* buffer, 56 int32_t bytes_to_write, 57 scoped_refptr<TrackedCallback> callback) OVERRIDE; 58 virtual int32_t SetLength(int64_t length, 59 scoped_refptr<TrackedCallback> callback) OVERRIDE; 60 virtual int32_t Flush(scoped_refptr<TrackedCallback> callback) OVERRIDE; 61 virtual void Close() OVERRIDE; 62 virtual int32_t RequestOSFileHandle( 63 PP_FileHandle* handle, 64 scoped_refptr<TrackedCallback> callback) OVERRIDE; 65 66 private: 67 // FileHandleHolder is used to guarantee that file operations will have a 68 // valid FD to operate on, even if they're in a different thread. 69 // If instead we just passed the raw FD, the FD could be closed before the 70 // file operation has a chance to run. It could interact with an invalid FD, 71 // or worse, the FD value could be reused if another file is opened quickly 72 // (POSIX is required to provide the lowest available value when opening a 73 // file). This could result in strange problems such as writing data to the 74 // wrong file. 75 // 76 // Operations that run on a background thread should hold one of these to 77 // ensure they have a valid file descriptor. The file handle is only closed 78 // when the last reference to the FileHandleHolder is removed, so we are 79 // guaranteed to operate on the correct file descriptor. It *is* still 80 // possible that the FileIOResource will be destroyed and "Abort" callbacks 81 // just before the operation does its task (e.g., Reading). In that case, we 82 // might for example Read from a file even though the FileIO has been 83 // destroyed and the plugin's callback got a PP_ERROR_ABORTED result. In the 84 // case of a write, we could write some data to the file despite the plugin 85 // receiving a PP_ERROR_ABORTED instead of a successful result. 86 class FileHandleHolder : public base::RefCountedThreadSafe<FileHandleHolder> { 87 public: 88 explicit FileHandleHolder(PP_FileHandle file_handle_); 89 PP_FileHandle raw_handle() { 90 return raw_handle_; 91 } 92 static bool IsValid( 93 const scoped_refptr<FileIOResource::FileHandleHolder>& handle); 94 private: 95 friend class base::RefCountedThreadSafe<FileHandleHolder>; 96 ~FileHandleHolder(); 97 PP_FileHandle raw_handle_; 98 }; 99 100 // Class to perform file query operations across multiple threads. 101 class QueryOp : public base::RefCountedThreadSafe<QueryOp> { 102 public: 103 explicit QueryOp(scoped_refptr<FileHandleHolder> file_handle); 104 105 // Queries the file. Called on the file thread (non-blocking) or the plugin 106 // thread (blocking). This should not be called when we hold the proxy lock. 107 int32_t DoWork(); 108 109 const base::PlatformFileInfo& file_info() const { return file_info_; } 110 111 private: 112 friend class base::RefCountedThreadSafe<QueryOp>; 113 ~QueryOp(); 114 115 scoped_refptr<FileHandleHolder> file_handle_; 116 base::PlatformFileInfo file_info_; 117 }; 118 119 // Class to perform file read operations across multiple threads. 120 class ReadOp : public base::RefCountedThreadSafe<ReadOp> { 121 public: 122 ReadOp(scoped_refptr<FileHandleHolder> file_handle, 123 int64_t offset, 124 int32_t bytes_to_read); 125 126 // Reads the file. Called on the file thread (non-blocking) or the plugin 127 // thread (blocking). This should not be called when we hold the proxy lock. 128 int32_t DoWork(); 129 130 char* buffer() const { return buffer_.get(); } 131 132 private: 133 friend class base::RefCountedThreadSafe<ReadOp>; 134 ~ReadOp(); 135 136 scoped_refptr<FileHandleHolder> file_handle_; 137 int64_t offset_; 138 int32_t bytes_to_read_; 139 scoped_ptr<char[]> buffer_; 140 }; 141 142 int32_t ReadValidated(int64_t offset, 143 int32_t bytes_to_read, 144 const PP_ArrayOutput& array_output, 145 scoped_refptr<TrackedCallback> callback); 146 147 // Completion tasks for file operations that are done in the plugin. 148 int32_t OnQueryComplete(scoped_refptr<QueryOp> query_op, 149 PP_FileInfo* info, 150 int32_t result); 151 int32_t OnReadComplete(scoped_refptr<ReadOp> read_op, 152 PP_ArrayOutput array_output, 153 int32_t result); 154 155 // Reply message handlers for operations that are done in the host. 156 void OnPluginMsgGeneralComplete(scoped_refptr<TrackedCallback> callback, 157 const ResourceMessageReplyParams& params); 158 void OnPluginMsgOpenFileComplete(scoped_refptr<TrackedCallback> callback, 159 const ResourceMessageReplyParams& params); 160 void OnPluginMsgRequestOSFileHandleComplete( 161 scoped_refptr<TrackedCallback> callback, 162 PP_FileHandle* output_handle, 163 const ResourceMessageReplyParams& params); 164 165 scoped_refptr<FileHandleHolder> file_handle_; 166 PP_FileSystemType file_system_type_; 167 scoped_refptr<Resource> file_system_resource_; 168 bool called_close_; 169 FileIOStateManager state_manager_; 170 171 scoped_refptr<Resource> file_ref_; 172 173 DISALLOW_COPY_AND_ASSIGN(FileIOResource); 174 }; 175 176 } // namespace proxy 177 } // namespace ppapi 178 179 #endif // PPAPI_PROXY_FILE_IO_RESOURCE_H_ 180