OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2011 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/shared_impl/file_io_impl.h" |
| 6 |
| 7 #include <string.h> |
| 8 |
| 9 #include "base/bind.h" |
| 10 #include "base/logging.h" |
| 11 #include "base/message_loop.h" |
| 12 #include "ppapi/c/pp_errors.h" |
| 13 #include "ppapi/shared_impl/file_type_conversion.h" |
| 14 #include "ppapi/shared_impl/time_conversion.h" |
| 15 #include "ppapi/thunk/enter.h" |
| 16 #include "ppapi/thunk/ppb_file_ref_api.h" |
| 17 |
| 18 namespace ppapi { |
| 19 |
| 20 using thunk::EnterResourceNoLock; |
| 21 using thunk::PPB_FileIO_API; |
| 22 using thunk::PPB_FileRef_API; |
| 23 |
| 24 FileIOImpl::CallbackEntry::CallbackEntry() |
| 25 : read_buffer(NULL), |
| 26 info(NULL) { |
| 27 } |
| 28 |
| 29 FileIOImpl::CallbackEntry::CallbackEntry(const CallbackEntry& entry) |
| 30 : callback(entry.callback), |
| 31 read_buffer(entry.read_buffer), |
| 32 info(entry.info) { |
| 33 } |
| 34 |
| 35 FileIOImpl::CallbackEntry::~CallbackEntry() { |
| 36 } |
| 37 |
| 38 FileIOImpl::FileIOImpl(PP_Instance instance) |
| 39 : Resource(instance), |
| 40 file_system_type_(PP_FILESYSTEMTYPE_INVALID), |
| 41 file_open_(false), |
| 42 pending_op_(OPERATION_NONE) { |
| 43 } |
| 44 |
| 45 FileIOImpl::FileIOImpl(const HostResource& host_resource) |
| 46 : Resource(host_resource), |
| 47 file_system_type_(PP_FILESYSTEMTYPE_INVALID), |
| 48 file_open_(false), |
| 49 pending_op_(OPERATION_NONE) { |
| 50 } |
| 51 |
| 52 FileIOImpl::~FileIOImpl() { |
| 53 // The callbacks list should have been cleared by LastPluginRefWasDeleted. |
| 54 DCHECK(callbacks_.empty()); |
| 55 } |
| 56 |
| 57 void FileIOImpl::LastPluginRefWasDeleted() { |
| 58 // Abort all pending callbacks. Do this by posting a task to avoid reentering |
| 59 // the plugin's Release() call that probably deleted this object. |
| 60 for (size_t i = 0; i < callbacks_.size(); i++) { |
| 61 MessageLoop::current()->PostTask(FROM_HERE, base::Bind( |
| 62 callbacks_[i].callback.func, callbacks_[i].callback.user_data, |
| 63 static_cast<int32_t>(PP_ERROR_ABORTED))); |
| 64 } |
| 65 callbacks_.erase(callbacks_.begin(), callbacks_.end()); |
| 66 } |
| 67 |
| 68 thunk::PPB_FileIO_API* FileIOImpl::AsPPB_FileIO_API() { |
| 69 return this; |
| 70 } |
| 71 |
| 72 int32_t FileIOImpl::Open(PP_Resource file_ref, |
| 73 int32_t open_flags, |
| 74 PP_CompletionCallback callback) { |
| 75 EnterResourceNoLock<PPB_FileRef_API> enter(file_ref, true); |
| 76 if (enter.failed()) |
| 77 return PP_ERROR_BADRESOURCE; |
| 78 |
| 79 int32_t rv = CommonCallValidation(false, OPERATION_EXCLUSIVE, callback); |
| 80 if (rv != PP_OK) |
| 81 return rv; |
| 82 |
| 83 PP_FileSystemType type = enter.object()->GetFileSystemType(); |
| 84 if (type != PP_FILESYSTEMTYPE_LOCALPERSISTENT && |
| 85 type != PP_FILESYSTEMTYPE_LOCALTEMPORARY && |
| 86 type != PP_FILESYSTEMTYPE_EXTERNAL) |
| 87 return PP_ERROR_FAILED; |
| 88 file_system_type_ = type; |
| 89 |
| 90 return OpenValidated(file_ref, enter.object(), open_flags, callback); |
| 91 } |
| 92 |
| 93 int32_t FileIOImpl::Query(PP_FileInfo* info, PP_CompletionCallback callback) { |
| 94 int32_t rv = CommonCallValidation(true, OPERATION_EXCLUSIVE, callback); |
| 95 if (rv != PP_OK) |
| 96 return rv; |
| 97 if (!info) |
| 98 return PP_ERROR_BADARGUMENT; |
| 99 return QueryValidated(info, callback); |
| 100 } |
| 101 |
| 102 int32_t FileIOImpl::Touch(PP_Time last_access_time, |
| 103 PP_Time last_modified_time, |
| 104 PP_CompletionCallback callback) { |
| 105 int32_t rv = CommonCallValidation(true, OPERATION_EXCLUSIVE, callback); |
| 106 if (rv != PP_OK) |
| 107 return rv; |
| 108 return TouchValidated(last_access_time, last_modified_time, callback); |
| 109 } |
| 110 |
| 111 int32_t FileIOImpl::Read(int64_t offset, |
| 112 char* buffer, |
| 113 int32_t bytes_to_read, |
| 114 PP_CompletionCallback callback) { |
| 115 int32_t rv = CommonCallValidation(true, OPERATION_READ, callback); |
| 116 if (rv != PP_OK) |
| 117 return rv; |
| 118 return ReadValidated(offset, buffer, bytes_to_read, callback); |
| 119 } |
| 120 |
| 121 int32_t FileIOImpl::Write(int64_t offset, |
| 122 const char* buffer, |
| 123 int32_t bytes_to_write, |
| 124 PP_CompletionCallback callback) { |
| 125 int32_t rv = CommonCallValidation(true, OPERATION_WRITE, callback); |
| 126 if (rv != PP_OK) |
| 127 return rv; |
| 128 return WriteValidated(offset, buffer, bytes_to_write, callback); |
| 129 } |
| 130 |
| 131 int32_t FileIOImpl::SetLength(int64_t length, |
| 132 PP_CompletionCallback callback) { |
| 133 int32_t rv = CommonCallValidation(true, OPERATION_EXCLUSIVE, callback); |
| 134 if (rv != PP_OK) |
| 135 return rv; |
| 136 return SetLengthValidated(length, callback); |
| 137 } |
| 138 |
| 139 int32_t FileIOImpl::Flush(PP_CompletionCallback callback) { |
| 140 int32_t rv = CommonCallValidation(true, OPERATION_EXCLUSIVE, callback); |
| 141 if (rv != PP_OK) |
| 142 return rv; |
| 143 return FlushValidated(callback); |
| 144 } |
| 145 |
| 146 void FileIOImpl::ExecuteGeneralCallback(int32_t pp_error) { |
| 147 RunAndRemoveFirstPendingCallback(pp_error); |
| 148 } |
| 149 |
| 150 void FileIOImpl::ExecuteOpenFileCallback(int32_t pp_error) { |
| 151 if (pp_error == PP_OK) |
| 152 file_open_ = true; |
| 153 ExecuteGeneralCallback(pp_error); |
| 154 } |
| 155 |
| 156 void FileIOImpl::ExecuteQueryCallback(int32_t pp_error, |
| 157 const PP_FileInfo& info) { |
| 158 if (pending_op_ != OPERATION_EXCLUSIVE || callbacks_.empty() || |
| 159 !callbacks_.front().info) { |
| 160 NOTREACHED(); |
| 161 return; |
| 162 } |
| 163 *callbacks_.front().info = info; |
| 164 RunAndRemoveFirstPendingCallback(pp_error); |
| 165 } |
| 166 |
| 167 void FileIOImpl::ExecuteReadCallback(int32_t pp_error, const char* data) { |
| 168 if (pending_op_ != OPERATION_READ || callbacks_.empty()) { |
| 169 NOTREACHED(); |
| 170 return; |
| 171 } |
| 172 |
| 173 char* read_buffer = callbacks_.front().read_buffer; |
| 174 DCHECK(data); |
| 175 DCHECK(read_buffer); |
| 176 |
| 177 // The result code contains the number of bytes if it's positive. |
| 178 if (pp_error > 0) |
| 179 memcpy(read_buffer, data, pp_error); |
| 180 RunAndRemoveFirstPendingCallback(pp_error); |
| 181 } |
| 182 |
| 183 int32_t FileIOImpl::CommonCallValidation(bool should_be_open, |
| 184 OperationType new_op, |
| 185 PP_CompletionCallback callback) { |
| 186 // Only asynchronous operation is supported. |
| 187 if (!callback.func) |
| 188 return PP_ERROR_BLOCKS_MAIN_THREAD; |
| 189 |
| 190 if (should_be_open) { |
| 191 if (!file_open_) |
| 192 return PP_ERROR_FAILED; |
| 193 } else { |
| 194 if (file_open_) |
| 195 return PP_ERROR_FAILED; |
| 196 } |
| 197 |
| 198 if (pending_op_ != OPERATION_NONE && |
| 199 (pending_op_ != new_op || pending_op_ == OPERATION_EXCLUSIVE)) { |
| 200 return PP_ERROR_INPROGRESS; |
| 201 } |
| 202 |
| 203 return PP_OK; |
| 204 } |
| 205 |
| 206 void FileIOImpl::RegisterCallback(OperationType op, |
| 207 PP_CompletionCallback callback, |
| 208 char* read_buffer, |
| 209 PP_FileInfo* info) { |
| 210 DCHECK(callback.func); |
| 211 DCHECK(pending_op_ == OPERATION_NONE || |
| 212 (pending_op_ != OPERATION_EXCLUSIVE && pending_op_ == op)); |
| 213 |
| 214 CallbackEntry entry; |
| 215 entry.callback = callback; |
| 216 entry.read_buffer = read_buffer; |
| 217 entry.info = info; |
| 218 callbacks_.push_back(entry); |
| 219 |
| 220 pending_op_ = op; |
| 221 } |
| 222 |
| 223 void FileIOImpl::RunAndRemoveFirstPendingCallback(int32_t result) { |
| 224 DCHECK(!callbacks_.empty()); |
| 225 |
| 226 CallbackEntry front = callbacks_.front(); |
| 227 callbacks_.pop_front(); |
| 228 if (callbacks_.empty()) |
| 229 pending_op_ = OPERATION_NONE; |
| 230 |
| 231 PP_RunCompletionCallback(&front.callback, result); |
| 232 } |
| 233 |
| 234 } // namespace ppapi |
OLD | NEW |