Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "webkit/plugins/ppapi/ppb_file_io_impl.h" | 5 #include "webkit/plugins/ppapi/ppb_file_io_impl.h" |
|
michaeln
2011/07/20 21:28:33
Are any plugins using the file descriptor base API
kinuko
2011/07/21 14:34:08
I guessed you meant this but also wished there mig
| |
| 6 | 6 |
| 7 #include "base/callback.h" | |
| 8 #include "base/file_util.h" | 7 #include "base/file_util.h" |
| 9 #include "base/file_util_proxy.h" | 8 #include "base/file_util_proxy.h" |
| 10 #include "base/message_loop_proxy.h" | 9 #include "base/message_loop_proxy.h" |
| 11 #include "base/platform_file.h" | 10 #include "base/platform_file.h" |
| 12 #include "base/logging.h" | 11 #include "base/logging.h" |
| 13 #include "base/time.h" | 12 #include "base/time.h" |
| 14 #include "ppapi/c/ppb_file_io.h" | 13 #include "ppapi/c/ppb_file_io.h" |
| 15 #include "ppapi/c/trusted/ppb_file_io_trusted.h" | 14 #include "ppapi/c/trusted/ppb_file_io_trusted.h" |
| 16 #include "ppapi/c/pp_completion_callback.h" | 15 #include "ppapi/c/pp_completion_callback.h" |
| 17 #include "ppapi/c/pp_errors.h" | 16 #include "ppapi/c/pp_errors.h" |
| 18 #include "ppapi/shared_impl/time_conversion.h" | 17 #include "ppapi/shared_impl/time_conversion.h" |
| 19 #include "ppapi/thunk/enter.h" | 18 #include "ppapi/thunk/enter.h" |
| 20 #include "ppapi/thunk/ppb_file_ref_api.h" | 19 #include "ppapi/thunk/ppb_file_ref_api.h" |
| 20 #include "webkit/fileapi/file_system_util.h" | |
| 21 #include "webkit/plugins/ppapi/common.h" | 21 #include "webkit/plugins/ppapi/common.h" |
| 22 #include "webkit/plugins/ppapi/file_type_conversions.h" | 22 #include "webkit/plugins/ppapi/file_type_conversions.h" |
| 23 #include "webkit/plugins/ppapi/plugin_module.h" | 23 #include "webkit/plugins/ppapi/plugin_module.h" |
| 24 #include "webkit/plugins/ppapi/ppapi_plugin_instance.h" | 24 #include "webkit/plugins/ppapi/ppapi_plugin_instance.h" |
| 25 #include "webkit/plugins/ppapi/ppb_file_ref_impl.h" | 25 #include "webkit/plugins/ppapi/ppb_file_ref_impl.h" |
| 26 #include "webkit/plugins/ppapi/resource_tracker.h" | 26 #include "webkit/plugins/ppapi/resource_tracker.h" |
| 27 #include "webkit/quota/quota_client.h" | |
| 27 | 28 |
| 28 using ppapi::PPTimeToTime; | 29 using ppapi::PPTimeToTime; |
| 29 using ppapi::TimeToPPTime; | 30 using ppapi::TimeToPPTime; |
| 30 using ppapi::thunk::EnterResourceNoLock; | 31 using ppapi::thunk::EnterResourceNoLock; |
| 31 using ppapi::thunk::PPB_FileIO_API; | 32 using ppapi::thunk::PPB_FileIO_API; |
| 32 using ppapi::thunk::PPB_FileRef_API; | 33 using ppapi::thunk::PPB_FileRef_API; |
| 33 | 34 |
| 34 namespace webkit { | 35 namespace webkit { |
| 35 namespace ppapi { | 36 namespace ppapi { |
| 36 | 37 |
| 38 namespace { | |
| 39 quota::StorageType PPFileSystemTypeToQuotaStorageType(PP_FileSystemType type) { | |
| 40 switch (type) { | |
| 41 case PP_FILESYSTEMTYPE_LOCALPERSISTENT: | |
| 42 return quota::kStorageTypePersistent; | |
| 43 case PP_FILESYSTEMTYPE_LOCALTEMPORARY: | |
| 44 return quota::kStorageTypeTemporary; | |
| 45 default: | |
| 46 return quota::kStorageTypeUnknown; | |
| 47 } | |
| 48 NOTREACHED(); | |
| 49 } | |
| 50 } // namespace | |
| 51 | |
| 52 PPB_FileIO_Impl::PendingOperation::PendingOperation() | |
| 53 : type(UNKNOWN), offset(0), buffer(NULL), bytes_to_write(0) {} | |
| 54 | |
| 37 PPB_FileIO_Impl::CallbackEntry::CallbackEntry() | 55 PPB_FileIO_Impl::CallbackEntry::CallbackEntry() |
| 38 : read_buffer(NULL) { | 56 : read_buffer(NULL) { |
| 39 } | 57 } |
| 40 | 58 |
| 41 PPB_FileIO_Impl::CallbackEntry::CallbackEntry(const CallbackEntry& entry) | 59 PPB_FileIO_Impl::CallbackEntry::CallbackEntry(const CallbackEntry& entry) |
| 42 : callback(entry.callback), | 60 : callback(entry.callback), |
| 43 read_buffer(entry.read_buffer) { | 61 read_buffer(entry.read_buffer) { |
| 44 } | 62 } |
| 45 | 63 |
| 46 PPB_FileIO_Impl::CallbackEntry::~CallbackEntry() { | 64 PPB_FileIO_Impl::CallbackEntry::~CallbackEntry() { |
| 47 } | 65 } |
| 48 | 66 |
| 49 PPB_FileIO_Impl::PPB_FileIO_Impl(PluginInstance* instance) | 67 PPB_FileIO_Impl::PPB_FileIO_Impl(PluginInstance* instance) |
| 50 : Resource(instance), | 68 : Resource(instance), |
| 51 ALLOW_THIS_IN_INITIALIZER_LIST(callback_factory_(this)), | 69 ALLOW_THIS_IN_INITIALIZER_LIST(callback_factory_(this)), |
| 52 file_(base::kInvalidPlatformFileValue), | 70 file_(base::kInvalidPlatformFileValue), |
| 71 file_size_(-1), | |
| 72 cached_available_space_(0), | |
| 53 pending_op_(OPERATION_NONE), | 73 pending_op_(OPERATION_NONE), |
| 54 info_(NULL) { | 74 info_(NULL), |
| 75 pending_setlength_length_(-1) { | |
| 55 } | 76 } |
| 56 | 77 |
| 57 PPB_FileIO_Impl::~PPB_FileIO_Impl() { | 78 PPB_FileIO_Impl::~PPB_FileIO_Impl() { |
| 58 Close(); | 79 Close(); |
| 59 } | 80 } |
| 60 | 81 |
| 61 PPB_FileIO_API* PPB_FileIO_Impl::AsPPB_FileIO_API() { | 82 PPB_FileIO_API* PPB_FileIO_Impl::AsPPB_FileIO_API() { |
| 62 return this; | 83 return this; |
| 63 } | 84 } |
| 64 | 85 |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 81 file_system_type_ = file_ref->GetFileSystemType(); | 102 file_system_type_ = file_ref->GetFileSystemType(); |
| 82 switch (file_system_type_) { | 103 switch (file_system_type_) { |
| 83 case PP_FILESYSTEMTYPE_EXTERNAL: | 104 case PP_FILESYSTEMTYPE_EXTERNAL: |
| 84 if (!instance()->delegate()->AsyncOpenFile( | 105 if (!instance()->delegate()->AsyncOpenFile( |
| 85 file_ref->GetSystemPath(), flags, | 106 file_ref->GetSystemPath(), flags, |
| 86 callback_factory_.NewCallback( | 107 callback_factory_.NewCallback( |
| 87 &PPB_FileIO_Impl::AsyncOpenFileCallback))) | 108 &PPB_FileIO_Impl::AsyncOpenFileCallback))) |
| 88 return PP_ERROR_FAILED; | 109 return PP_ERROR_FAILED; |
| 89 break; | 110 break; |
| 90 case PP_FILESYSTEMTYPE_LOCALPERSISTENT: | 111 case PP_FILESYSTEMTYPE_LOCALPERSISTENT: |
| 91 case PP_FILESYSTEMTYPE_LOCALTEMPORARY: | 112 case PP_FILESYSTEMTYPE_LOCALTEMPORARY: { |
| 113 GURL root_url = file_ref->GetFileSystemURL(); | |
| 92 if (!instance()->delegate()->AsyncOpenFileSystemURL( | 114 if (!instance()->delegate()->AsyncOpenFileSystemURL( |
| 93 file_ref->GetFileSystemURL(), flags, | 115 root_url, flags, |
| 94 callback_factory_.NewCallback( | 116 callback_factory_.NewCallback( |
| 95 &PPB_FileIO_Impl::AsyncOpenFileCallback))) | 117 &PPB_FileIO_Impl::AsyncOpenFileCallback))) |
| 96 return PP_ERROR_FAILED; | 118 return PP_ERROR_FAILED; |
| 119 origin_url_ = GURL(root_url.path()).GetOrigin(); | |
| 97 break; | 120 break; |
| 121 } | |
| 98 default: | 122 default: |
| 99 return PP_ERROR_FAILED; | 123 return PP_ERROR_FAILED; |
| 100 } | 124 } |
| 101 | 125 |
| 102 RegisterCallback(OPERATION_EXCLUSIVE, callback, NULL); | 126 RegisterCallback(&callbacks_, OPERATION_EXCLUSIVE, callback, NULL); |
| 103 return PP_OK_COMPLETIONPENDING; | 127 return PP_OK_COMPLETIONPENDING; |
| 104 } | 128 } |
| 105 | 129 |
| 106 int32_t PPB_FileIO_Impl::Query(PP_FileInfo* info, | 130 int32_t PPB_FileIO_Impl::Query(PP_FileInfo* info, |
| 107 PP_CompletionCallback callback) { | 131 PP_CompletionCallback callback) { |
| 108 int32_t rv = CommonCallValidation(true, OPERATION_EXCLUSIVE, callback); | 132 int32_t rv = CommonCallValidation(true, OPERATION_EXCLUSIVE, callback); |
| 109 if (rv != PP_OK) | 133 if (rv != PP_OK) |
| 110 return rv; | 134 return rv; |
| 111 | 135 |
| 112 if (!info) | 136 if (!info) |
| 113 return PP_ERROR_BADARGUMENT; | 137 return PP_ERROR_BADARGUMENT; |
| 114 | 138 |
| 115 DCHECK(!info_); // If |info_|, a callback should be pending (caught above). | 139 DCHECK(!info_); // If |info_|, a callback should be pending (caught above). |
| 116 info_ = info; | 140 info_ = info; |
| 117 | 141 |
| 118 if (!base::FileUtilProxy::GetFileInfoFromPlatformFile( | 142 if (!base::FileUtilProxy::GetFileInfoFromPlatformFile( |
| 119 instance()->delegate()->GetFileThreadMessageLoopProxy(), file_, | 143 instance()->delegate()->GetFileThreadMessageLoopProxy(), file_, |
| 120 callback_factory_.NewCallback(&PPB_FileIO_Impl::QueryInfoCallback))) | 144 callback_factory_.NewCallback(&PPB_FileIO_Impl::QueryInfoCallback))) |
| 121 return PP_ERROR_FAILED; | 145 return PP_ERROR_FAILED; |
| 122 | 146 |
| 123 RegisterCallback(OPERATION_EXCLUSIVE, callback, NULL); | 147 RegisterCallback(&callbacks_, OPERATION_EXCLUSIVE, callback, NULL); |
| 124 return PP_OK_COMPLETIONPENDING; | 148 return PP_OK_COMPLETIONPENDING; |
| 125 } | 149 } |
| 126 | 150 |
| 127 int32_t PPB_FileIO_Impl::Touch(PP_Time last_access_time, | 151 int32_t PPB_FileIO_Impl::Touch(PP_Time last_access_time, |
| 128 PP_Time last_modified_time, | 152 PP_Time last_modified_time, |
| 129 PP_CompletionCallback callback) { | 153 PP_CompletionCallback callback) { |
| 130 int32_t rv = CommonCallValidation(true, OPERATION_EXCLUSIVE, callback); | 154 int32_t rv = CommonCallValidation(true, OPERATION_EXCLUSIVE, callback); |
| 131 if (rv != PP_OK) | 155 if (rv != PP_OK) |
| 132 return rv; | 156 return rv; |
| 133 | 157 |
| 134 if (!base::FileUtilProxy::Touch( | 158 if (!base::FileUtilProxy::Touch( |
| 135 instance()->delegate()->GetFileThreadMessageLoopProxy(), | 159 instance()->delegate()->GetFileThreadMessageLoopProxy(), |
| 136 file_, PPTimeToTime(last_access_time), | 160 file_, PPTimeToTime(last_access_time), |
| 137 PPTimeToTime(last_modified_time), | 161 PPTimeToTime(last_modified_time), |
| 138 callback_factory_.NewCallback(&PPB_FileIO_Impl::StatusCallback))) | 162 callback_factory_.NewCallback(&PPB_FileIO_Impl::StatusCallback))) |
| 139 return PP_ERROR_FAILED; | 163 return PP_ERROR_FAILED; |
| 140 | 164 |
| 141 RegisterCallback(OPERATION_EXCLUSIVE, callback, NULL); | 165 RegisterCallback(&callbacks_, OPERATION_EXCLUSIVE, callback, NULL); |
| 142 return PP_OK_COMPLETIONPENDING; | 166 return PP_OK_COMPLETIONPENDING; |
| 143 } | 167 } |
| 144 | 168 |
| 145 int32_t PPB_FileIO_Impl::Read(int64_t offset, | 169 int32_t PPB_FileIO_Impl::Read(int64_t offset, |
| 146 char* buffer, | 170 char* buffer, |
| 147 int32_t bytes_to_read, | 171 int32_t bytes_to_read, |
| 148 PP_CompletionCallback callback) { | 172 PP_CompletionCallback callback) { |
| 149 int32_t rv = CommonCallValidation(true, OPERATION_READ, callback); | 173 int32_t rv = CommonCallValidation(true, OPERATION_READ, callback); |
| 150 if (rv != PP_OK) | 174 if (rv != PP_OK) |
| 151 return rv; | 175 return rv; |
| 152 | 176 |
| 153 if (!base::FileUtilProxy::Read( | 177 if (!base::FileUtilProxy::Read( |
| 154 instance()->delegate()->GetFileThreadMessageLoopProxy(), | 178 instance()->delegate()->GetFileThreadMessageLoopProxy(), |
| 155 file_, offset, bytes_to_read, | 179 file_, offset, bytes_to_read, |
| 156 callback_factory_.NewCallback(&PPB_FileIO_Impl::ReadCallback))) | 180 callback_factory_.NewCallback(&PPB_FileIO_Impl::ReadCallback))) |
| 157 return PP_ERROR_FAILED; | 181 return PP_ERROR_FAILED; |
| 158 | 182 |
| 159 RegisterCallback(OPERATION_READ, callback, buffer); | 183 RegisterCallback(&callbacks_, OPERATION_READ, callback, buffer); |
| 160 return PP_OK_COMPLETIONPENDING; | 184 return PP_OK_COMPLETIONPENDING; |
| 161 } | 185 } |
| 162 | 186 |
| 163 int32_t PPB_FileIO_Impl::Write(int64_t offset, | 187 int32_t PPB_FileIO_Impl::Write(int64_t offset, |
| 164 const char* buffer, | 188 const char* buffer, |
| 165 int32_t bytes_to_write, | 189 int32_t bytes_to_write, |
| 166 PP_CompletionCallback callback) { | 190 PP_CompletionCallback callback) { |
| 167 int32_t rv = CommonCallValidation(true, OPERATION_WRITE, callback); | 191 int32_t rv = CommonCallValidation(true, OPERATION_WRITE, callback); |
| 168 if (rv != PP_OK) | 192 if (rv != PP_OK) |
| 169 return rv; | 193 return rv; |
| 170 | 194 |
| 171 if (!base::FileUtilProxy::Write( | 195 int64_t expected_growth = offset + bytes_to_write - file_size_; |
| 172 instance()->delegate()->GetFileThreadMessageLoopProxy(), | |
| 173 file_, offset, buffer, bytes_to_write, | |
| 174 callback_factory_.NewCallback(&PPB_FileIO_Impl::WriteCallback))) | |
| 175 return PP_ERROR_FAILED; | |
| 176 | 196 |
| 177 RegisterCallback(OPERATION_WRITE, callback, NULL); | 197 if (!DoesRequireQuotaCheck() || |
| 198 expected_growth <= cached_available_space_) { | |
| 199 // we're ok to go. | |
| 200 if (!base::FileUtilProxy::Write( | |
| 201 instance()->delegate()->GetFileThreadMessageLoopProxy(), | |
| 202 file_, offset, buffer, bytes_to_write, | |
| 203 callback_factory_.NewCallback(&PPB_FileIO_Impl::WriteCallback))) { | |
| 204 return PP_ERROR_FAILED; | |
| 205 } | |
| 206 pending_write_offset_.push(offset); | |
| 207 RegisterCallback(&callbacks_, OPERATION_WRITE, callback, NULL); | |
| 208 return PP_OK_COMPLETIONPENDING; | |
| 209 } | |
| 210 | |
| 211 // Enqueue this request and query the quota. | |
| 212 PendingOperation op; | |
| 213 op.type = PendingOperation::WRITE; | |
| 214 op.offset = offset; | |
| 215 op.buffer = buffer; | |
| 216 op.bytes_to_write = bytes_to_write; | |
| 217 QueryAvailableSpace(op); | |
| 218 | |
| 219 RegisterCallback(&pending_quota_check_callbacks_, | |
|
yzshen1
2011/07/20 20:50:36
The problem is that write operations may be execut
kinuko
2011/07/21 14:34:08
I changed the code to either always or never queue
| |
| 220 OPERATION_WRITE, callback, NULL); | |
| 178 return PP_OK_COMPLETIONPENDING; | 221 return PP_OK_COMPLETIONPENDING; |
| 179 } | 222 } |
| 180 | 223 |
| 181 int32_t PPB_FileIO_Impl::SetLength(int64_t length, | 224 int32_t PPB_FileIO_Impl::SetLength(int64_t length, |
| 182 PP_CompletionCallback callback) { | 225 PP_CompletionCallback callback) { |
| 183 int32_t rv = CommonCallValidation(true, OPERATION_EXCLUSIVE, callback); | 226 int32_t rv = CommonCallValidation(true, OPERATION_EXCLUSIVE, callback); |
| 184 if (rv != PP_OK) | 227 if (rv != PP_OK) |
| 185 return rv; | 228 return rv; |
| 186 | 229 |
| 187 if (!base::FileUtilProxy::Truncate( | 230 DCHECK_EQ(-1, pending_setlength_length_); |
| 188 instance()->delegate()->GetFileThreadMessageLoopProxy(), | 231 int64_t expected_growth = length - file_size_; |
| 189 file_, length, | |
| 190 callback_factory_.NewCallback(&PPB_FileIO_Impl::StatusCallback))) | |
| 191 return PP_ERROR_FAILED; | |
| 192 | 232 |
| 193 RegisterCallback(OPERATION_EXCLUSIVE, callback, NULL); | 233 if (!DoesRequireQuotaCheck() || |
| 234 expected_growth <= cached_available_space_) { | |
| 235 if (!base::FileUtilProxy::Truncate( | |
| 236 instance()->delegate()->GetFileThreadMessageLoopProxy(), | |
| 237 file_, length, | |
| 238 callback_factory_.NewCallback( | |
| 239 &PPB_FileIO_Impl::SetLengthCallback))) { | |
| 240 return PP_ERROR_FAILED; | |
| 241 } | |
| 242 pending_setlength_length_ = length; | |
| 243 RegisterCallback(&callbacks_, OPERATION_EXCLUSIVE, callback, NULL); | |
| 244 return PP_OK_COMPLETIONPENDING; | |
| 245 } | |
| 246 | |
| 247 // Enqueue this request and query the quota. | |
| 248 PendingOperation op; | |
| 249 op.type = PendingOperation::SETLENGTH; | |
| 250 op.length = length; | |
| 251 QueryAvailableSpace(op); | |
| 252 | |
| 253 RegisterCallback(&pending_quota_check_callbacks_, | |
| 254 OPERATION_EXCLUSIVE, callback, NULL); | |
| 194 return PP_OK_COMPLETIONPENDING; | 255 return PP_OK_COMPLETIONPENDING; |
| 195 } | 256 } |
| 196 | 257 |
| 197 int32_t PPB_FileIO_Impl::Flush(PP_CompletionCallback callback) { | 258 int32_t PPB_FileIO_Impl::Flush(PP_CompletionCallback callback) { |
| 198 int32_t rv = CommonCallValidation(true, OPERATION_EXCLUSIVE, callback); | 259 int32_t rv = CommonCallValidation(true, OPERATION_EXCLUSIVE, callback); |
| 199 if (rv != PP_OK) | 260 if (rv != PP_OK) |
| 200 return rv; | 261 return rv; |
| 201 | 262 |
| 202 if (!base::FileUtilProxy::Flush( | 263 if (!base::FileUtilProxy::Flush( |
| 203 instance()->delegate()->GetFileThreadMessageLoopProxy(), file_, | 264 instance()->delegate()->GetFileThreadMessageLoopProxy(), file_, |
| 204 callback_factory_.NewCallback(&PPB_FileIO_Impl::StatusCallback))) | 265 callback_factory_.NewCallback(&PPB_FileIO_Impl::StatusCallback))) |
| 205 return PP_ERROR_FAILED; | 266 return PP_ERROR_FAILED; |
| 206 | 267 |
| 207 RegisterCallback(OPERATION_EXCLUSIVE, callback, NULL); | 268 RegisterCallback(&callbacks_, OPERATION_EXCLUSIVE, callback, NULL); |
| 208 return PP_OK_COMPLETIONPENDING; | 269 return PP_OK_COMPLETIONPENDING; |
| 209 } | 270 } |
| 210 | 271 |
| 211 void PPB_FileIO_Impl::Close() { | 272 void PPB_FileIO_Impl::Close() { |
| 212 if (file_ != base::kInvalidPlatformFileValue) { | 273 if (file_ != base::kInvalidPlatformFileValue) { |
| 213 base::FileUtilProxy::Close( | 274 base::FileUtilProxy::Close( |
| 214 instance()->delegate()->GetFileThreadMessageLoopProxy(), file_, NULL); | 275 instance()->delegate()->GetFileThreadMessageLoopProxy(), file_, NULL); |
| 215 file_ = base::kInvalidPlatformFileValue; | 276 file_ = base::kInvalidPlatformFileValue; |
| 216 } | 277 } |
| 217 } | 278 } |
| 218 | 279 |
| 219 int32_t PPB_FileIO_Impl::GetOSFileDescriptor() { | 280 int32_t PPB_FileIO_Impl::GetOSFileDescriptor() { |
| 220 #if defined(OS_POSIX) | 281 #if defined(OS_POSIX) |
| 221 return file_; | 282 return file_; |
| 222 #elif defined(OS_WIN) | 283 #elif defined(OS_WIN) |
| 223 return reinterpret_cast<uintptr_t>(file_); | 284 return reinterpret_cast<uintptr_t>(file_); |
| 224 #else | 285 #else |
| 225 #error "Platform not supported." | 286 #error "Platform not supported." |
| 226 #endif | 287 #endif |
| 227 } | 288 } |
| 228 | 289 |
| 229 int32_t PPB_FileIO_Impl::WillWrite(int64_t offset, | 290 int32_t PPB_FileIO_Impl::WillWrite(int64_t offset, |
| 230 int32_t bytes_to_write, | 291 int32_t bytes_to_write, |
| 231 PP_CompletionCallback callback) { | 292 PP_CompletionCallback callback) { |
| 232 // TODO(dumi): implement me | 293 // TODO(dumi): implement me |
| 294 // Request quota. | |
|
michaeln
2011/07/20 21:28:33
Given the shape of the trusted APIs (there's a Wil
kinuko
2011/07/21 14:34:08
Hmm the successive write or truncate may fail, so
| |
| 233 return PP_OK; | 295 return PP_OK; |
| 234 } | 296 } |
| 235 | 297 |
| 236 int32_t PPB_FileIO_Impl::WillSetLength(int64_t length, | 298 int32_t PPB_FileIO_Impl::WillSetLength(int64_t length, |
| 237 PP_CompletionCallback callback) { | 299 PP_CompletionCallback callback) { |
| 238 // TODO(dumi): implement me | 300 // TODO(dumi): implement me |
| 301 // Request quota. | |
| 239 return PP_OK; | 302 return PP_OK; |
| 240 } | 303 } |
| 241 | 304 |
| 242 int32_t PPB_FileIO_Impl::CommonCallValidation(bool should_be_open, | 305 int32_t PPB_FileIO_Impl::CommonCallValidation(bool should_be_open, |
| 243 OperationType new_op, | 306 OperationType new_op, |
| 244 PP_CompletionCallback callback) { | 307 PP_CompletionCallback callback) { |
| 245 // Only asynchronous operation is supported. | 308 // Only asynchronous operation is supported. |
| 246 if (!callback.func) { | 309 if (!callback.func) { |
| 247 NOTIMPLEMENTED(); | 310 NOTIMPLEMENTED(); |
| 248 return PP_ERROR_BADARGUMENT; | 311 return PP_ERROR_BADARGUMENT; |
| 249 } | 312 } |
| 250 | 313 |
| 251 if (should_be_open) { | 314 if (should_be_open) { |
| 252 if (file_ == base::kInvalidPlatformFileValue) | 315 if (file_ == base::kInvalidPlatformFileValue) |
| 253 return PP_ERROR_FAILED; | 316 return PP_ERROR_FAILED; |
| 254 } else { | 317 } else { |
| 255 if (file_ != base::kInvalidPlatformFileValue) | 318 if (file_ != base::kInvalidPlatformFileValue) |
| 256 return PP_ERROR_FAILED; | 319 return PP_ERROR_FAILED; |
| 257 } | 320 } |
| 258 | 321 |
| 259 if (pending_op_ != OPERATION_NONE && | 322 if (pending_op_ != OPERATION_NONE && |
| 260 (pending_op_ != new_op || pending_op_ == OPERATION_EXCLUSIVE)) { | 323 (pending_op_ != new_op || pending_op_ == OPERATION_EXCLUSIVE)) { |
| 261 return PP_ERROR_INPROGRESS; | 324 return PP_ERROR_INPROGRESS; |
| 262 } | 325 } |
| 263 | 326 |
| 264 return PP_OK; | 327 return PP_OK; |
| 265 } | 328 } |
| 266 | 329 |
| 267 void PPB_FileIO_Impl::RegisterCallback(OperationType op, | 330 void PPB_FileIO_Impl::RegisterCallback(std::queue<CallbackEntry>* callbacks, |
| 331 OperationType op, | |
| 268 PP_CompletionCallback callback, | 332 PP_CompletionCallback callback, |
| 269 char* read_buffer) { | 333 char* read_buffer) { |
| 270 DCHECK(callback.func); | 334 DCHECK(callback.func); |
| 271 DCHECK(pending_op_ == OPERATION_NONE || | 335 DCHECK(pending_op_ == OPERATION_NONE || |
| 272 (pending_op_ != OPERATION_EXCLUSIVE && pending_op_ == op)); | 336 (pending_op_ != OPERATION_EXCLUSIVE && pending_op_ == op)); |
| 273 | 337 |
| 274 CallbackEntry entry; | 338 CallbackEntry entry; |
| 275 PP_Resource resource_id = GetReferenceNoAddRef(); | 339 PP_Resource resource_id = GetReferenceNoAddRef(); |
| 276 CHECK(resource_id); | 340 CHECK(resource_id); |
| 277 entry.callback = new TrackedCompletionCallback( | 341 entry.callback = new TrackedCompletionCallback( |
| 278 instance()->module()->GetCallbackTracker(), resource_id, callback); | 342 instance()->module()->GetCallbackTracker(), resource_id, callback); |
| 279 entry.read_buffer = read_buffer; | 343 entry.read_buffer = read_buffer; |
| 280 | 344 |
| 281 callbacks_.push(entry); | 345 callbacks->push(entry); |
| 282 pending_op_ = op; | 346 pending_op_ = op; |
| 283 } | 347 } |
| 284 | 348 |
| 285 void PPB_FileIO_Impl::RunAndRemoveFirstPendingCallback(int32_t result) { | 349 void PPB_FileIO_Impl::RunAndRemoveFirstPendingCallback( |
| 286 DCHECK(!callbacks_.empty()); | 350 std::queue<CallbackEntry>* callbacks, int32_t result) { |
| 351 DCHECK(!callbacks->empty()); | |
| 287 | 352 |
| 288 CallbackEntry front = callbacks_.front(); | 353 CallbackEntry front = callbacks->front(); |
| 289 callbacks_.pop(); | 354 callbacks->pop(); |
| 290 if (callbacks_.empty()) | 355 if (callbacks->empty()) |
| 291 pending_op_ = OPERATION_NONE; | 356 pending_op_ = OPERATION_NONE; |
| 292 | 357 |
| 293 front.callback->Run(result); // Will complete abortively if necessary. | 358 front.callback->Run(result); // Will complete abortively if necessary. |
| 294 } | 359 } |
| 295 | 360 |
| 296 void PPB_FileIO_Impl::StatusCallback(base::PlatformFileError error_code) { | 361 void PPB_FileIO_Impl::StatusCallback(base::PlatformFileError error_code) { |
| 297 if (pending_op_ != OPERATION_EXCLUSIVE || callbacks_.empty()) { | 362 if (pending_op_ != OPERATION_EXCLUSIVE || callbacks_.empty()) { |
| 298 NOTREACHED(); | 363 NOTREACHED(); |
| 299 return; | 364 return; |
| 300 } | 365 } |
| 301 | 366 |
| 302 RunAndRemoveFirstPendingCallback(PlatformFileErrorToPepperError(error_code)); | 367 RunAndRemoveFirstPendingCallback( |
| 368 &callbacks_, PlatformFileErrorToPepperError(error_code)); | |
| 303 } | 369 } |
| 304 | 370 |
| 305 void PPB_FileIO_Impl::AsyncOpenFileCallback( | 371 void PPB_FileIO_Impl::AsyncOpenFileCallback( |
| 306 base::PlatformFileError error_code, | 372 base::PlatformFileError error_code, |
| 307 base::PassPlatformFile file) { | 373 base::PassPlatformFile file, |
| 374 int64_t file_size) { | |
| 308 if (pending_op_ != OPERATION_EXCLUSIVE || callbacks_.empty()) { | 375 if (pending_op_ != OPERATION_EXCLUSIVE || callbacks_.empty()) { |
| 309 NOTREACHED(); | 376 NOTREACHED(); |
| 310 return; | 377 return; |
| 311 } | 378 } |
| 312 | 379 |
| 313 DCHECK(file_ == base::kInvalidPlatformFileValue); | 380 DCHECK(file_ == base::kInvalidPlatformFileValue); |
| 314 file_ = file.ReleaseValue(); | 381 file_ = file.ReleaseValue(); |
| 315 RunAndRemoveFirstPendingCallback(PlatformFileErrorToPepperError(error_code)); | 382 file_size_ = file_size; |
| 383 DCHECK(!DoesRequireQuotaCheck() || | |
| 384 error_code != base::PLATFORM_FILE_OK || | |
| 385 file_size_ >= 0); | |
| 386 RunAndRemoveFirstPendingCallback( | |
| 387 &callbacks_, PlatformFileErrorToPepperError(error_code)); | |
| 316 } | 388 } |
| 317 | 389 |
| 318 void PPB_FileIO_Impl::QueryInfoCallback( | 390 void PPB_FileIO_Impl::QueryInfoCallback( |
| 319 base::PlatformFileError error_code, | 391 base::PlatformFileError error_code, |
| 320 const base::PlatformFileInfo& file_info) { | 392 const base::PlatformFileInfo& file_info) { |
| 321 if (pending_op_ != OPERATION_EXCLUSIVE || callbacks_.empty()) { | 393 if (pending_op_ != OPERATION_EXCLUSIVE || callbacks_.empty()) { |
| 322 NOTREACHED(); | 394 NOTREACHED(); |
| 323 return; | 395 return; |
| 324 } | 396 } |
| 325 | 397 |
| 326 DCHECK(info_); | 398 DCHECK(info_); |
| 327 if (error_code == base::PLATFORM_FILE_OK) { | 399 if (error_code == base::PLATFORM_FILE_OK) { |
| 328 info_->size = file_info.size; | 400 info_->size = file_info.size; |
| 329 info_->creation_time = TimeToPPTime(file_info.creation_time); | 401 info_->creation_time = TimeToPPTime(file_info.creation_time); |
| 330 info_->last_access_time = TimeToPPTime(file_info.last_accessed); | 402 info_->last_access_time = TimeToPPTime(file_info.last_accessed); |
| 331 info_->last_modified_time = TimeToPPTime(file_info.last_modified); | 403 info_->last_modified_time = TimeToPPTime(file_info.last_modified); |
| 332 info_->system_type = file_system_type_; | 404 info_->system_type = file_system_type_; |
| 333 if (file_info.is_directory) | 405 if (file_info.is_directory) |
| 334 info_->type = PP_FILETYPE_DIRECTORY; | 406 info_->type = PP_FILETYPE_DIRECTORY; |
| 335 else | 407 else |
| 336 info_->type = PP_FILETYPE_REGULAR; | 408 info_->type = PP_FILETYPE_REGULAR; |
| 337 } | 409 } |
| 338 info_ = NULL; | 410 info_ = NULL; |
| 339 RunAndRemoveFirstPendingCallback(PlatformFileErrorToPepperError(error_code)); | 411 RunAndRemoveFirstPendingCallback( |
| 412 &callbacks_, PlatformFileErrorToPepperError(error_code)); | |
| 340 } | 413 } |
| 341 | 414 |
| 342 void PPB_FileIO_Impl::ReadCallback(base::PlatformFileError error_code, | 415 void PPB_FileIO_Impl::ReadCallback(base::PlatformFileError error_code, |
| 343 const char* data, int bytes_read) { | 416 const char* data, int bytes_read) { |
| 344 if (pending_op_ != OPERATION_READ || callbacks_.empty()) { | 417 if (pending_op_ != OPERATION_READ || callbacks_.empty()) { |
| 345 NOTREACHED(); | 418 NOTREACHED(); |
| 346 return; | 419 return; |
| 347 } | 420 } |
| 348 | 421 |
| 349 char* read_buffer = callbacks_.front().read_buffer; | 422 char* read_buffer = callbacks_.front().read_buffer; |
| 350 DCHECK(data); | 423 DCHECK(data); |
| 351 DCHECK(read_buffer); | 424 DCHECK(read_buffer); |
| 352 | 425 |
| 353 int rv; | 426 int rv; |
| 354 if (error_code == base::PLATFORM_FILE_OK) { | 427 if (error_code == base::PLATFORM_FILE_OK) { |
| 355 rv = bytes_read; | 428 rv = bytes_read; |
| 356 if (file_ != base::kInvalidPlatformFileValue) | 429 if (file_ != base::kInvalidPlatformFileValue) |
| 357 memcpy(read_buffer, data, bytes_read); | 430 memcpy(read_buffer, data, bytes_read); |
| 358 } else { | 431 } else { |
| 359 rv = PlatformFileErrorToPepperError(error_code); | 432 rv = PlatformFileErrorToPepperError(error_code); |
| 360 } | 433 } |
| 361 | 434 |
| 362 RunAndRemoveFirstPendingCallback(rv); | 435 RunAndRemoveFirstPendingCallback(&callbacks_, rv); |
| 363 } | 436 } |
| 364 | 437 |
| 365 void PPB_FileIO_Impl::WriteCallback(base::PlatformFileError error_code, | 438 void PPB_FileIO_Impl::WriteCallback(base::PlatformFileError error_code, |
| 366 int bytes_written) { | 439 int bytes_written) { |
| 367 if (pending_op_ != OPERATION_WRITE || callbacks_.empty()) { | 440 if (pending_op_ != OPERATION_WRITE || callbacks_.empty()) { |
| 368 NOTREACHED(); | 441 NOTREACHED(); |
| 369 return; | 442 return; |
| 370 } | 443 } |
| 371 | 444 |
| 445 DCHECK(!pending_write_offset_.empty()); | |
| 446 int64_t offset = pending_write_offset_.front(); | |
| 447 pending_write_offset_.pop(); | |
| 448 | |
| 372 if (error_code != base::PLATFORM_FILE_OK) { | 449 if (error_code != base::PLATFORM_FILE_OK) { |
| 373 RunAndRemoveFirstPendingCallback( | 450 RunAndRemoveFirstPendingCallback( |
| 374 PlatformFileErrorToPepperError(error_code)); | 451 &callbacks_, PlatformFileErrorToPepperError(error_code)); |
| 375 } else { | 452 } else { |
| 376 RunAndRemoveFirstPendingCallback(bytes_written); | 453 int64_t growth = offset + bytes_written - file_size_; |
| 454 if (growth >= 0) { | |
| 455 if (DoesRequireQuotaCheck()) { | |
| 456 instance()->delegate()->NotifyStorageModified( | |
| 457 quota::QuotaClient::kFileSystem, | |
| 458 origin_url_, | |
| 459 PPFileSystemTypeToQuotaStorageType(file_system_type_), | |
| 460 growth); | |
| 461 } | |
| 462 file_size_ += growth; | |
| 463 } | |
| 464 RunAndRemoveFirstPendingCallback(&callbacks_, bytes_written); | |
| 465 } | |
| 466 | |
| 467 // Reset the available space. | |
| 468 if (HasNoPendingWrites()) | |
| 469 cached_available_space_ = 0; | |
| 470 } | |
| 471 | |
| 472 void PPB_FileIO_Impl::SetLengthCallback( | |
| 473 base::PlatformFileError error_code) { | |
| 474 if (callbacks_.empty()) { | |
| 475 NOTREACHED(); | |
| 476 return; | |
| 477 } | |
| 478 | |
| 479 DCHECK_NE(-1, pending_setlength_length_); | |
| 480 | |
| 481 if (base::PLATFORM_FILE_OK == error_code) { | |
| 482 if (DoesRequireQuotaCheck()) { | |
| 483 int64_t delta = pending_setlength_length_ - file_size_; | |
| 484 instance()->delegate()->NotifyStorageModified( | |
| 485 quota::QuotaClient::kFileSystem, | |
| 486 origin_url_, | |
| 487 PPFileSystemTypeToQuotaStorageType(file_system_type_), | |
| 488 delta); | |
| 489 } | |
| 490 file_size_ = pending_setlength_length_; | |
| 491 } | |
| 492 | |
| 493 RunAndRemoveFirstPendingCallback( | |
| 494 &callbacks_, PlatformFileErrorToPepperError(error_code)); | |
| 495 | |
| 496 pending_setlength_length_ = -1; | |
|
michaeln
2011/07/20 21:28:33
If the caller's callback has invoked FileIO.SetLen
kinuko
2011/07/21 14:34:08
Good catch, fixed.
| |
| 497 cached_available_space_ = 0; | |
| 498 } | |
| 499 | |
| 500 bool PPB_FileIO_Impl::DoesRequireQuotaCheck() const { | |
| 501 return (file_system_type_ == PP_FILESYSTEMTYPE_LOCALTEMPORARY || | |
| 502 file_system_type_ == PP_FILESYSTEMTYPE_LOCALPERSISTENT); | |
| 503 } | |
| 504 | |
| 505 bool PPB_FileIO_Impl::HasNoPendingWrites() const { | |
| 506 return pending_quota_checks_.empty() && | |
| 507 pending_write_offset_.empty() && | |
| 508 pending_setlength_length_ == -1; | |
| 509 } | |
| 510 | |
| 511 void PPB_FileIO_Impl::QueryAvailableSpace(const PendingOperation& op) { | |
| 512 pending_quota_checks_.push(op); | |
| 513 if (pending_quota_checks_.size() == 1) { | |
| 514 // This is the first one. | |
| 515 instance()->delegate()->QueryAvailableSpace( | |
| 516 origin_url_, | |
| 517 PPFileSystemTypeToQuotaStorageType(file_system_type_), | |
| 518 callback_factory_.NewCallback( | |
| 519 &PPB_FileIO_Impl::DidQueryAvailableSpace)); | |
| 377 } | 520 } |
| 378 } | 521 } |
| 379 | 522 |
| 523 void PPB_FileIO_Impl::DidQueryAvailableSpace(int64_t avail_space) { | |
| 524 cached_available_space_ = avail_space; | |
| 525 DCHECK(!pending_quota_checks_.empty()); | |
| 526 | |
| 527 while (!pending_quota_checks_.empty()) { | |
| 528 DCHECK(!pending_quota_check_callbacks_.empty()); | |
| 529 PendingOperation op = pending_quota_checks_.front(); | |
| 530 pending_quota_checks_.pop(); | |
| 531 | |
| 532 switch (op.type) { | |
| 533 case PendingOperation::WRITE: { | |
| 534 int64_t growth = op.offset + op.bytes_to_write - file_size_; | |
| 535 if (growth > cached_available_space_) { | |
| 536 RunAndRemoveFirstPendingCallback( | |
| 537 &pending_quota_check_callbacks_, | |
| 538 PP_ERROR_NOQUOTA); | |
| 539 return; | |
|
michaeln
2011/07/20 21:28:33
What about other pending checks in the queue? Is i
kinuko
2011/07/21 14:34:08
Done.
| |
| 540 } | |
| 541 if (!base::FileUtilProxy::Write( | |
| 542 instance()->delegate()->GetFileThreadMessageLoopProxy(), | |
| 543 file_, op.offset, op.buffer, op.bytes_to_write, | |
| 544 callback_factory_.NewCallback( | |
| 545 &PPB_FileIO_Impl::WriteCallback))) { | |
| 546 RunAndRemoveFirstPendingCallback( | |
| 547 &pending_quota_check_callbacks_, PP_ERROR_FAILED); | |
| 548 } | |
| 549 pending_write_offset_.push(op.offset); | |
| 550 break; | |
| 551 } | |
| 552 | |
| 553 case PendingOperation::SETLENGTH: { | |
| 554 int64_t growth = op.length - file_size_; | |
| 555 if (growth > cached_available_space_) { | |
| 556 RunAndRemoveFirstPendingCallback( | |
| 557 &pending_quota_check_callbacks_, | |
| 558 PP_ERROR_NOQUOTA); | |
| 559 return; | |
| 560 } | |
| 561 if (!base::FileUtilProxy::Truncate( | |
| 562 instance()->delegate()->GetFileThreadMessageLoopProxy(), | |
| 563 file_, op.length, | |
| 564 callback_factory_.NewCallback( | |
| 565 &PPB_FileIO_Impl::SetLengthCallback))) { | |
| 566 RunAndRemoveFirstPendingCallback( | |
| 567 &pending_quota_check_callbacks_, PP_ERROR_FAILED); | |
| 568 } | |
| 569 DCHECK_EQ(-1, pending_setlength_length_); | |
| 570 pending_setlength_length_ = op.length; | |
| 571 break; | |
| 572 } | |
| 573 | |
| 574 default: | |
| 575 NOTREACHED(); | |
| 576 return; | |
| 577 } | |
| 578 | |
| 579 CallbackEntry entry = pending_quota_check_callbacks_.front(); | |
| 580 pending_quota_check_callbacks_.pop(); | |
| 581 callbacks_.push(entry); | |
| 582 } | |
| 583 } | |
| 584 | |
| 380 } // namespace ppapi | 585 } // namespace ppapi |
| 381 } // namespace webkit | 586 } // namespace webkit |
| OLD | NEW |