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" |
| 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 | |
| 51 bool DoesRequireQuotaCheck(PP_FileSystemType type) { | |
| 52 return (type == PP_FILESYSTEMTYPE_LOCALTEMPORARY || | |
| 53 type == PP_FILESYSTEMTYPE_LOCALPERSISTENT); | |
| 54 } | |
| 55 } // anonymous namespace | |
| 56 | |
| 37 PPB_FileIO_Impl::CallbackEntry::CallbackEntry() | 57 PPB_FileIO_Impl::CallbackEntry::CallbackEntry() |
| 38 : read_buffer(NULL) { | 58 : read_buffer(NULL) { |
| 39 } | 59 } |
| 40 | 60 |
| 41 PPB_FileIO_Impl::CallbackEntry::CallbackEntry(const CallbackEntry& entry) | 61 PPB_FileIO_Impl::CallbackEntry::CallbackEntry(const CallbackEntry& entry) |
| 42 : callback(entry.callback), | 62 : callback(entry.callback), |
| 43 read_buffer(entry.read_buffer) { | 63 read_buffer(entry.read_buffer) { |
| 44 } | 64 } |
| 45 | 65 |
| 46 PPB_FileIO_Impl::CallbackEntry::~CallbackEntry() { | 66 PPB_FileIO_Impl::CallbackEntry::~CallbackEntry() { |
| 47 } | 67 } |
| 48 | 68 |
| 49 PPB_FileIO_Impl::PPB_FileIO_Impl(PluginInstance* instance) | 69 PPB_FileIO_Impl::PPB_FileIO_Impl(PluginInstance* instance) |
| 50 : Resource(instance), | 70 : Resource(instance), |
| 51 ALLOW_THIS_IN_INITIALIZER_LIST(callback_factory_(this)), | 71 ALLOW_THIS_IN_INITIALIZER_LIST(callback_factory_(this)), |
| 52 file_(base::kInvalidPlatformFileValue), | 72 file_(base::kInvalidPlatformFileValue), |
| 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(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) { |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 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 PendingWrite write; |
| 172 instance()->delegate()->GetFileThreadMessageLoopProxy(), | 196 write.offset = offset; |
| 173 file_, offset, buffer, bytes_to_write, | 197 write.buffer = buffer; |
| 174 callback_factory_.NewCallback(&PPB_FileIO_Impl::WriteCallback))) | 198 write.bytes_to_write = bytes_to_write; |
| 175 return PP_ERROR_FAILED; | 199 |
| 200 int64 expected_growth = offset + bytes_to_write - file_size_; | |
|
yzshen1
2011/07/19 17:41:55
It is possible that this method gets called for mu
michaeln
2011/07/19 22:01:45
I have these concerns too, keeping track of filesi
kinuko
2011/07/20 13:39:35
Putting aside the fact that the current design is
| |
| 201 if (!DoesRequireQuotaCheck(file_system_type_) || | |
| 202 expected_growth <= 0) { | |
| 203 // we're ok to go. | |
| 204 pending_write_callbacks_.push(write); | |
| 205 if (!base::FileUtilProxy::Write( | |
| 206 instance()->delegate()->GetFileThreadMessageLoopProxy(), | |
| 207 file_, offset, buffer, bytes_to_write, | |
| 208 callback_factory_.NewCallback(&PPB_FileIO_Impl::WriteCallback))) { | |
| 209 pending_write_callbacks_.pop(); | |
| 210 return PP_ERROR_FAILED; | |
| 211 } | |
| 212 } else { | |
| 213 pending_writes_.push(write); | |
| 214 instance()->delegate()->CanWrite( | |
| 215 origin_url_, | |
| 216 PPFileSystemTypeToQuotaStorageType(file_system_type_), | |
| 217 expected_growth, | |
| 218 callback_factory_.NewCallback(&PPB_FileIO_Impl::DidCheckQuotaForWrite)); | |
| 219 } | |
| 176 | 220 |
| 177 RegisterCallback(OPERATION_WRITE, callback, NULL); | 221 RegisterCallback(OPERATION_WRITE, callback, NULL); |
| 178 return PP_OK_COMPLETIONPENDING; | 222 return PP_OK_COMPLETIONPENDING; |
| 179 } | 223 } |
| 180 | 224 |
| 181 int32_t PPB_FileIO_Impl::SetLength(int64_t length, | 225 int32_t PPB_FileIO_Impl::SetLength(int64_t length, |
| 182 PP_CompletionCallback callback) { | 226 PP_CompletionCallback callback) { |
| 183 int32_t rv = CommonCallValidation(true, OPERATION_EXCLUSIVE, callback); | 227 int32_t rv = CommonCallValidation(true, OPERATION_EXCLUSIVE, callback); |
| 184 if (rv != PP_OK) | 228 if (rv != PP_OK) |
| 185 return rv; | 229 return rv; |
| 186 | 230 |
| 187 if (!base::FileUtilProxy::Truncate( | 231 DCHECK_EQ(-1, pending_setlength_length_); |
|
michaeln
2011/07/19 22:01:45
What guarantees are there that there's only one Se
kinuko
2011/07/20 13:39:35
Seems like EXCLUSIVE operations cannot run in para
yzshen1
2011/07/20 20:50:36
Yes, that is correct.
On 2011/07/20 13:39:35, kin
| |
| 188 instance()->delegate()->GetFileThreadMessageLoopProxy(), | 232 pending_setlength_length_ = length; |
| 189 file_, length, | 233 |
| 190 callback_factory_.NewCallback(&PPB_FileIO_Impl::StatusCallback))) | 234 int64 expected_growth = length - file_size_; |
| 191 return PP_ERROR_FAILED; | 235 if (!DoesRequireQuotaCheck(file_system_type_) || |
| 236 expected_growth <= 0) { | |
| 237 if (!base::FileUtilProxy::Truncate( | |
| 238 instance()->delegate()->GetFileThreadMessageLoopProxy(), | |
| 239 file_, length, | |
| 240 callback_factory_.NewCallback( | |
| 241 &PPB_FileIO_Impl::SetLengthCallback))) { | |
| 242 pending_setlength_length_ = -1; | |
| 243 return PP_ERROR_FAILED; | |
| 244 } | |
| 245 } else { | |
| 246 instance()->delegate()->CanWrite( | |
| 247 origin_url_, | |
| 248 PPFileSystemTypeToQuotaStorageType(file_system_type_), | |
| 249 expected_growth, | |
| 250 callback_factory_.NewCallback( | |
| 251 &PPB_FileIO_Impl::DidCheckQuotaForSetLength)); | |
| 252 } | |
| 192 | 253 |
| 193 RegisterCallback(OPERATION_EXCLUSIVE, callback, NULL); | 254 RegisterCallback(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 |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 297 if (pending_op_ != OPERATION_EXCLUSIVE || callbacks_.empty()) { | 358 if (pending_op_ != OPERATION_EXCLUSIVE || callbacks_.empty()) { |
| 298 NOTREACHED(); | 359 NOTREACHED(); |
| 299 return; | 360 return; |
| 300 } | 361 } |
| 301 | 362 |
| 302 RunAndRemoveFirstPendingCallback(PlatformFileErrorToPepperError(error_code)); | 363 RunAndRemoveFirstPendingCallback(PlatformFileErrorToPepperError(error_code)); |
| 303 } | 364 } |
| 304 | 365 |
| 305 void PPB_FileIO_Impl::AsyncOpenFileCallback( | 366 void PPB_FileIO_Impl::AsyncOpenFileCallback( |
| 306 base::PlatformFileError error_code, | 367 base::PlatformFileError error_code, |
| 307 base::PassPlatformFile file) { | 368 base::PassPlatformFile file, |
| 369 int64_t file_size) { | |
| 308 if (pending_op_ != OPERATION_EXCLUSIVE || callbacks_.empty()) { | 370 if (pending_op_ != OPERATION_EXCLUSIVE || callbacks_.empty()) { |
| 309 NOTREACHED(); | 371 NOTREACHED(); |
| 310 return; | 372 return; |
| 311 } | 373 } |
| 312 | 374 |
| 313 DCHECK(file_ == base::kInvalidPlatformFileValue); | 375 DCHECK(file_ == base::kInvalidPlatformFileValue); |
| 314 file_ = file.ReleaseValue(); | 376 file_ = file.ReleaseValue(); |
| 377 file_size_ = file_size; | |
| 315 RunAndRemoveFirstPendingCallback(PlatformFileErrorToPepperError(error_code)); | 378 RunAndRemoveFirstPendingCallback(PlatformFileErrorToPepperError(error_code)); |
| 316 } | 379 } |
| 317 | 380 |
| 318 void PPB_FileIO_Impl::QueryInfoCallback( | 381 void PPB_FileIO_Impl::QueryInfoCallback( |
| 319 base::PlatformFileError error_code, | 382 base::PlatformFileError error_code, |
| 320 const base::PlatformFileInfo& file_info) { | 383 const base::PlatformFileInfo& file_info) { |
| 321 if (pending_op_ != OPERATION_EXCLUSIVE || callbacks_.empty()) { | 384 if (pending_op_ != OPERATION_EXCLUSIVE || callbacks_.empty()) { |
| 322 NOTREACHED(); | 385 NOTREACHED(); |
| 323 return; | 386 return; |
| 324 } | 387 } |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 362 RunAndRemoveFirstPendingCallback(rv); | 425 RunAndRemoveFirstPendingCallback(rv); |
| 363 } | 426 } |
| 364 | 427 |
| 365 void PPB_FileIO_Impl::WriteCallback(base::PlatformFileError error_code, | 428 void PPB_FileIO_Impl::WriteCallback(base::PlatformFileError error_code, |
| 366 int bytes_written) { | 429 int bytes_written) { |
| 367 if (pending_op_ != OPERATION_WRITE || callbacks_.empty()) { | 430 if (pending_op_ != OPERATION_WRITE || callbacks_.empty()) { |
| 368 NOTREACHED(); | 431 NOTREACHED(); |
| 369 return; | 432 return; |
| 370 } | 433 } |
| 371 | 434 |
| 435 DCHECK(!pending_write_callbacks_.empty()); | |
| 436 PendingWrite write = pending_write_callbacks_.front(); | |
| 437 pending_write_callbacks_.pop(); | |
| 438 | |
| 372 if (error_code != base::PLATFORM_FILE_OK) { | 439 if (error_code != base::PLATFORM_FILE_OK) { |
| 373 RunAndRemoveFirstPendingCallback( | 440 RunAndRemoveFirstPendingCallback( |
| 374 PlatformFileErrorToPepperError(error_code)); | 441 PlatformFileErrorToPepperError(error_code)); |
| 375 } else { | 442 } else { |
| 443 int64 growth = write.offset + bytes_written - file_size_; | |
| 444 if (growth >= 0) { | |
| 445 if (DoesRequireQuotaCheck(file_system_type_)) { | |
| 446 instance()->delegate()->NotifyStorageModified( | |
| 447 quota::QuotaClient::kFileSystem, | |
| 448 origin_url_, | |
| 449 PPFileSystemTypeToQuotaStorageType(file_system_type_), | |
| 450 growth); | |
| 451 } | |
| 452 file_size_ += growth; | |
| 453 } | |
| 376 RunAndRemoveFirstPendingCallback(bytes_written); | 454 RunAndRemoveFirstPendingCallback(bytes_written); |
| 377 } | 455 } |
| 378 } | 456 } |
| 379 | 457 |
| 458 void PPB_FileIO_Impl::SetLengthCallback( | |
| 459 base::PlatformFileError error_code) { | |
| 460 if (callbacks_.empty()) { | |
| 461 NOTREACHED(); | |
| 462 return; | |
| 463 } | |
| 464 | |
| 465 DCHECK_NE(-1, pending_setlength_length_); | |
| 466 | |
| 467 if (base::PLATFORM_FILE_OK == error_code && | |
| 468 DoesRequireQuotaCheck(file_system_type_)) { | |
| 469 int64 delta = pending_setlength_length_ - file_size_; | |
| 470 instance()->delegate()->NotifyStorageModified( | |
| 471 quota::QuotaClient::kFileSystem, | |
| 472 origin_url_, | |
| 473 PPFileSystemTypeToQuotaStorageType(file_system_type_), | |
| 474 delta); | |
| 475 } | |
| 476 | |
| 477 RunAndRemoveFirstPendingCallback(PlatformFileErrorToPepperError(error_code)); | |
|
michaeln
2011/07/19 22:01:45
Now that some of these operations call out the the
yzshen1
2011/07/19 23:14:14
What is more, the order of multiple write operatio
kinuko
2011/07/20 13:39:35
I splitted the callbacks queue into two, one for r
| |
| 478 file_size_ = pending_setlength_length_; | |
|
yzshen1
2011/07/19 17:41:55
Even if it failed, we still set file_size_ to pend
kinuko
2011/07/20 13:39:35
Good catch... fixed.
| |
| 479 pending_setlength_length_ = -1; | |
| 480 } | |
| 481 | |
| 482 void PPB_FileIO_Impl::DidCheckQuotaForWrite(bool success) { | |
|
yzshen1
2011/07/19 17:41:55
This method and DidCheckQuotaForSetLength ignore |
| |
| 483 DCHECK(!pending_writes_.empty()); | |
| 484 PendingWrite write = pending_writes_.front(); | |
| 485 pending_writes_.pop(); | |
| 486 pending_write_callbacks_.push(write); | |
| 487 | |
| 488 if (!base::FileUtilProxy::Write( | |
| 489 instance()->delegate()->GetFileThreadMessageLoopProxy(), | |
| 490 file_, write.offset, write.buffer, write.bytes_to_write, | |
| 491 callback_factory_.NewCallback(&PPB_FileIO_Impl::WriteCallback))) { | |
| 492 RunAndRemoveFirstPendingCallback(PP_ERROR_FAILED); | |
| 493 } | |
| 494 } | |
| 495 | |
| 496 void PPB_FileIO_Impl::DidCheckQuotaForSetLength(bool success) { | |
| 497 DCHECK(!pending_setlength_length_ != -1); | |
| 498 if (!base::FileUtilProxy::Truncate( | |
| 499 instance()->delegate()->GetFileThreadMessageLoopProxy(), | |
| 500 file_, pending_setlength_length_, | |
| 501 callback_factory_.NewCallback( | |
| 502 &PPB_FileIO_Impl::SetLengthCallback))) { | |
| 503 RunAndRemoveFirstPendingCallback(PP_ERROR_FAILED); | |
| 504 } | |
| 505 } | |
| 506 | |
| 380 } // namespace ppapi | 507 } // namespace ppapi |
| 381 } // namespace webkit | 508 } // namespace webkit |
| OLD | NEW |