Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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/fileapi/file_system_operation.h" | 5 #include "webkit/fileapi/file_system_operation.h" |
| 6 | 6 |
| 7 #include "base/time.h" | 7 #include "base/time.h" |
| 8 #include "net/url_request/url_request_context.h" | 8 #include "net/url_request/url_request_context.h" |
| 9 #include "webkit/fileapi/file_system_callback_dispatcher.h" | 9 #include "webkit/fileapi/file_system_callback_dispatcher.h" |
| 10 #include "webkit/fileapi/file_writer_delegate.h" | 10 #include "webkit/fileapi/file_writer_delegate.h" |
| 11 | 11 |
| 12 namespace fileapi { | 12 namespace fileapi { |
| 13 | 13 |
| 14 namespace { | |
| 15 | |
| 16 // A helper callback dispatcher class to make it easy to control | |
| 17 // FileSystemOperation's lifetime. Calling any callback methods of this | |
| 18 // class would delete the corresponding FileSystemOperation. | |
| 19 class DispatchAndDeleteCallbackWrapper | |
| 20 : public FileSystemCallbackDispatcher { | |
| 21 public: | |
| 22 DispatchAndDeleteCallbackWrapper( | |
| 23 FileSystemOperation* operation, | |
| 24 FileSystemCallbackDispatcher* dispatcher) | |
| 25 : operation_(operation), | |
| 26 dispatcher_(dispatcher) { } | |
| 27 | |
| 28 // Returns the wrapped dispatcher. | |
| 29 // This would be useful when the caller does not want to delete the operation. | |
| 30 FileSystemCallbackDispatcher* wrapped() const { return dispatcher_.get(); } | |
| 31 | |
| 32 virtual void DidSucceed() { | |
| 33 dispatcher_->DidSucceed(); | |
| 34 delete operation_; | |
| 35 } | |
| 36 | |
| 37 virtual void DidReadMetadata(const base::PlatformFileInfo& file_info) { | |
| 38 dispatcher_->DidReadMetadata(file_info); | |
| 39 delete operation_; | |
| 40 } | |
| 41 | |
| 42 virtual void DidReadDirectory( | |
| 43 const std::vector<base::FileUtilProxy::Entry>& entries, | |
| 44 bool has_more) { | |
| 45 dispatcher_->DidReadDirectory(entries, has_more); | |
| 46 delete operation_; | |
| 47 } | |
| 48 | |
| 49 virtual void DidOpenFileSystem(const std::string& name, | |
| 50 const FilePath& root_path) { | |
| 51 dispatcher_->DidOpenFileSystem(name, root_path); | |
| 52 delete operation_; | |
| 53 } | |
| 54 | |
| 55 virtual void DidFail(base::PlatformFileError error_code) { | |
| 56 dispatcher_->DidFail(error_code); | |
| 57 delete operation_; | |
| 58 } | |
| 59 | |
| 60 virtual void DidWrite(int64 bytes, bool complete) { | |
| 61 dispatcher_->DidWrite(bytes, complete); | |
| 62 if (complete) | |
| 63 delete operation_; | |
| 64 } | |
| 65 | |
| 66 private: | |
| 67 FileSystemOperation* operation_; | |
| 68 scoped_ptr<FileSystemCallbackDispatcher> dispatcher_; | |
| 69 }; | |
| 70 | |
| 71 } // namespace | |
| 72 | |
| 14 FileSystemOperation::FileSystemOperation( | 73 FileSystemOperation::FileSystemOperation( |
| 15 FileSystemCallbackDispatcher* dispatcher, | 74 FileSystemCallbackDispatcher* dispatcher, |
| 16 scoped_refptr<base::MessageLoopProxy> proxy) | 75 scoped_refptr<base::MessageLoopProxy> proxy) |
| 17 : proxy_(proxy), | 76 : proxy_(proxy), |
| 18 dispatcher_(dispatcher), | 77 destructive_dispatcher_( |
| 78 new DispatchAndDeleteCallbackWrapper( | |
| 79 ALLOW_THIS_IN_INITIALIZER_LIST(this), dispatcher)), | |
|
ericu
2010/11/16 19:26:54
This seems a bit odd to me. We're creating a wrap
| |
| 19 callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), | 80 callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), |
| 20 cancel_operation_(NULL) { | 81 cancel_operation_(NULL) { |
| 21 DCHECK(dispatcher); | 82 DCHECK(dispatcher); |
| 22 #ifndef NDEBUG | 83 #ifndef NDEBUG |
| 23 pending_operation_ = kOperationNone; | 84 pending_operation_ = kOperationNone; |
| 24 #endif | 85 #endif |
| 25 } | 86 } |
| 26 | 87 |
| 27 FileSystemOperation::~FileSystemOperation() { | 88 FileSystemOperation::~FileSystemOperation() { |
| 28 if (file_writer_delegate_.get()) | 89 if (file_writer_delegate_.get()) |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 151 base::PLATFORM_FILE_ASYNC, | 212 base::PLATFORM_FILE_ASYNC, |
| 152 callback_factory_.NewCallback( | 213 callback_factory_.NewCallback( |
| 153 &FileSystemOperation::OnFileOpenedForWrite)); | 214 &FileSystemOperation::OnFileOpenedForWrite)); |
| 154 } | 215 } |
| 155 | 216 |
| 156 void FileSystemOperation::OnFileOpenedForWrite( | 217 void FileSystemOperation::OnFileOpenedForWrite( |
| 157 base::PlatformFileError rv, | 218 base::PlatformFileError rv, |
| 158 base::PassPlatformFile file, | 219 base::PassPlatformFile file, |
| 159 bool created) { | 220 bool created) { |
| 160 if (base::PLATFORM_FILE_OK != rv) { | 221 if (base::PLATFORM_FILE_OK != rv) { |
| 161 dispatcher_->DidFail(rv); | 222 destructive_dispatcher()->DidFail(rv); |
| 162 return; | 223 return; |
| 163 } | 224 } |
| 164 file_writer_delegate_->Start(file.ReleaseValue(), blob_request_.get()); | 225 file_writer_delegate_->Start(file.ReleaseValue(), blob_request_.get()); |
| 165 } | 226 } |
| 166 | 227 |
| 167 void FileSystemOperation::Truncate(const FilePath& path, int64 length) { | 228 void FileSystemOperation::Truncate(const FilePath& path, int64 length) { |
| 168 #ifndef NDEBUG | 229 #ifndef NDEBUG |
| 169 DCHECK(kOperationNone == pending_operation_); | 230 DCHECK(kOperationNone == pending_operation_); |
| 170 pending_operation_ = kOperationTruncate; | 231 pending_operation_ = kOperationTruncate; |
| 171 #endif | 232 #endif |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 197 // Writes are done without proxying through FileUtilProxy after the initial | 258 // Writes are done without proxying through FileUtilProxy after the initial |
| 198 // opening of the PlatformFile. All state changes are done on this thread, | 259 // opening of the PlatformFile. All state changes are done on this thread, |
| 199 // so we're guaranteed to be able to shut down atomically. We do need to | 260 // so we're guaranteed to be able to shut down atomically. We do need to |
| 200 // check that the file has been opened [which means the blob_request_ has | 261 // check that the file has been opened [which means the blob_request_ has |
| 201 // been created], so we know how much we need to do. | 262 // been created], so we know how much we need to do. |
| 202 if (blob_request_.get()) | 263 if (blob_request_.get()) |
| 203 // This halts any calls to file_writer_delegate_ from blob_request_. | 264 // This halts any calls to file_writer_delegate_ from blob_request_. |
| 204 blob_request_->Cancel(); | 265 blob_request_->Cancel(); |
| 205 | 266 |
| 206 // This deletes us, and by proxy deletes file_writer_delegate_ if any. | 267 // This deletes us, and by proxy deletes file_writer_delegate_ if any. |
| 207 dispatcher_->DidFail(base::PLATFORM_FILE_ERROR_ABORT); | 268 destructive_dispatcher()->DidFail(base::PLATFORM_FILE_ERROR_ABORT); |
| 208 cancel_operation->dispatcher_->DidSucceed(); | 269 cancel_operation->destructive_dispatcher()->DidSucceed(); |
| 209 } else { | 270 } else { |
| 210 #ifndef NDEBUG | 271 #ifndef NDEBUG |
| 211 DCHECK(kOperationTruncate == pending_operation_); | 272 DCHECK(kOperationTruncate == pending_operation_); |
| 212 #endif | 273 #endif |
| 213 // We're cancelling a truncate operation, but we can't actually stop it | 274 // We're cancelling a truncate operation, but we can't actually stop it |
| 214 // since it's been proxied to another thread. We need to save the | 275 // since it's been proxied to another thread. We need to save the |
| 215 // cancel_operation so that when the truncate returns, it can see that it's | 276 // cancel_operation so that when the truncate returns, it can see that it's |
| 216 // been cancelled, report it, and report that the cancel has succeeded. | 277 // been cancelled, report it, and report that the cancel has succeeded. |
| 278 DCHECK(!cancel_operation_); | |
| 217 cancel_operation_ = cancel_operation; | 279 cancel_operation_ = cancel_operation; |
| 218 } | 280 } |
| 219 } | 281 } |
| 220 | 282 |
| 283 FileSystemCallbackDispatcher* | |
| 284 FileSystemOperation::non_destructive_dispatcher() const { | |
| 285 return static_cast<DispatchAndDeleteCallbackWrapper*>( | |
| 286 destructive_dispatcher_.get())->wrapped(); | |
| 287 } | |
| 288 | |
| 221 void FileSystemOperation::DidEnsureFileExistsExclusive( | 289 void FileSystemOperation::DidEnsureFileExistsExclusive( |
| 222 base::PlatformFileError rv, bool created) { | 290 base::PlatformFileError rv, bool created) { |
| 223 if (rv == base::PLATFORM_FILE_OK && !created) | 291 if (rv == base::PLATFORM_FILE_OK && !created) { |
| 224 dispatcher_->DidFail(base::PLATFORM_FILE_ERROR_EXISTS); | 292 destructive_dispatcher()->DidFail(base::PLATFORM_FILE_ERROR_EXISTS); |
| 225 else | 293 } else |
| 226 DidFinishFileOperation(rv); | 294 DidFinishFileOperation(rv); |
| 227 } | 295 } |
| 228 | 296 |
| 229 void FileSystemOperation::DidEnsureFileExistsNonExclusive( | 297 void FileSystemOperation::DidEnsureFileExistsNonExclusive( |
| 230 base::PlatformFileError rv, bool /* created */) { | 298 base::PlatformFileError rv, bool /* created */) { |
| 231 DidFinishFileOperation(rv); | 299 DidFinishFileOperation(rv); |
| 232 } | 300 } |
| 233 | 301 |
| 234 void FileSystemOperation::DidFinishFileOperation( | 302 void FileSystemOperation::DidFinishFileOperation( |
| 235 base::PlatformFileError rv) { | 303 base::PlatformFileError rv) { |
| 236 if (cancel_operation_) { | 304 if (cancel_operation_) { |
| 237 #ifndef NDEBUG | 305 #ifndef NDEBUG |
| 238 DCHECK(kOperationTruncate == pending_operation_); | 306 DCHECK(kOperationTruncate == pending_operation_); |
| 239 #endif | 307 #endif |
| 240 FileSystemOperation *cancel_op = cancel_operation_; | 308 |
| 241 // This call deletes us, so we have to extract cancel_op first. | 309 // Call non-destructive dispatcher's method not to delete this instance yet. |
| 242 dispatcher_->DidFail(base::PLATFORM_FILE_ERROR_ABORT); | 310 non_destructive_dispatcher()->DidFail(base::PLATFORM_FILE_ERROR_ABORT); |
| 243 cancel_op->dispatcher_->DidSucceed(); | 311 cancel_operation_->destructive_dispatcher()->DidSucceed(); |
| 312 delete this; | |
| 244 } else if (rv == base::PLATFORM_FILE_OK) { | 313 } else if (rv == base::PLATFORM_FILE_OK) { |
| 245 dispatcher_->DidSucceed(); | 314 destructive_dispatcher()->DidSucceed(); |
| 246 } else { | 315 } else { |
| 247 dispatcher_->DidFail(rv); | 316 destructive_dispatcher()->DidFail(rv); |
| 248 } | 317 } |
| 249 } | 318 } |
| 250 | 319 |
| 251 void FileSystemOperation::DidDirectoryExists( | 320 void FileSystemOperation::DidDirectoryExists( |
| 252 base::PlatformFileError rv, | 321 base::PlatformFileError rv, |
| 253 const base::PlatformFileInfo& file_info) { | 322 const base::PlatformFileInfo& file_info) { |
| 254 if (rv == base::PLATFORM_FILE_OK) { | 323 if (rv == base::PLATFORM_FILE_OK) { |
| 255 if (file_info.is_directory) | 324 if (file_info.is_directory) |
| 256 dispatcher_->DidSucceed(); | 325 destructive_dispatcher()->DidSucceed(); |
| 257 else | 326 else |
| 258 dispatcher_->DidFail(base::PLATFORM_FILE_ERROR_FAILED); | 327 destructive_dispatcher()->DidFail(base::PLATFORM_FILE_ERROR_FAILED); |
| 259 } else { | 328 } else { |
| 260 dispatcher_->DidFail(rv); | 329 destructive_dispatcher()->DidFail(rv); |
| 261 } | 330 } |
| 262 } | 331 } |
| 263 | 332 |
| 264 void FileSystemOperation::DidFileExists( | 333 void FileSystemOperation::DidFileExists( |
| 265 base::PlatformFileError rv, | 334 base::PlatformFileError rv, |
| 266 const base::PlatformFileInfo& file_info) { | 335 const base::PlatformFileInfo& file_info) { |
| 267 if (rv == base::PLATFORM_FILE_OK) { | 336 if (rv == base::PLATFORM_FILE_OK) { |
| 268 if (file_info.is_directory) | 337 if (file_info.is_directory) |
| 269 dispatcher_->DidFail(base::PLATFORM_FILE_ERROR_FAILED); | 338 destructive_dispatcher()->DidFail(base::PLATFORM_FILE_ERROR_FAILED); |
| 270 else | 339 else |
| 271 dispatcher_->DidSucceed(); | 340 destructive_dispatcher()->DidSucceed(); |
| 272 } else { | 341 } else { |
| 273 dispatcher_->DidFail(rv); | 342 destructive_dispatcher()->DidFail(rv); |
| 274 } | 343 } |
| 275 } | 344 } |
| 276 | 345 |
| 277 void FileSystemOperation::DidGetMetadata( | 346 void FileSystemOperation::DidGetMetadata( |
| 278 base::PlatformFileError rv, | 347 base::PlatformFileError rv, |
| 279 const base::PlatformFileInfo& file_info) { | 348 const base::PlatformFileInfo& file_info) { |
| 280 if (rv == base::PLATFORM_FILE_OK) | 349 if (rv == base::PLATFORM_FILE_OK) |
| 281 dispatcher_->DidReadMetadata(file_info); | 350 destructive_dispatcher()->DidReadMetadata(file_info); |
| 282 else | 351 else |
| 283 dispatcher_->DidFail(rv); | 352 destructive_dispatcher()->DidFail(rv); |
| 284 } | 353 } |
| 285 | 354 |
| 286 void FileSystemOperation::DidReadDirectory( | 355 void FileSystemOperation::DidReadDirectory( |
| 287 base::PlatformFileError rv, | 356 base::PlatformFileError rv, |
| 288 const std::vector<base::FileUtilProxy::Entry>& entries) { | 357 const std::vector<base::FileUtilProxy::Entry>& entries) { |
| 289 if (rv == base::PLATFORM_FILE_OK) | 358 if (rv == base::PLATFORM_FILE_OK) |
| 290 dispatcher_->DidReadDirectory(entries, false /* has_more */); | 359 destructive_dispatcher()->DidReadDirectory(entries, false /* has_more */); |
| 291 else | 360 else |
| 292 dispatcher_->DidFail(rv); | 361 destructive_dispatcher()->DidFail(rv); |
| 293 } | 362 } |
| 294 | 363 |
| 295 void FileSystemOperation::DidWrite( | 364 void FileSystemOperation::DidWrite( |
| 296 base::PlatformFileError rv, | 365 base::PlatformFileError rv, |
| 297 int64 bytes, | 366 int64 bytes, |
| 298 bool complete) { | 367 bool complete) { |
| 299 if (rv == base::PLATFORM_FILE_OK) | 368 if (rv == base::PLATFORM_FILE_OK) |
| 300 dispatcher_->DidWrite(bytes, complete); | 369 destructive_dispatcher()->DidWrite(bytes, complete); |
|
ericu
2010/11/16 19:26:54
Given that we explicitly don't want to delete the
| |
| 301 else | 370 else |
| 302 dispatcher_->DidFail(rv); | 371 destructive_dispatcher()->DidFail(rv); |
| 303 } | 372 } |
| 304 | 373 |
| 305 void FileSystemOperation::DidTouchFile(base::PlatformFileError rv) { | 374 void FileSystemOperation::DidTouchFile(base::PlatformFileError rv) { |
| 306 if (rv == base::PLATFORM_FILE_OK) | 375 if (rv == base::PLATFORM_FILE_OK) |
| 307 dispatcher_->DidSucceed(); | 376 destructive_dispatcher()->DidSucceed(); |
| 308 else | 377 else |
| 309 dispatcher_->DidFail(rv); | 378 destructive_dispatcher()->DidFail(rv); |
| 310 } | 379 } |
| 311 | 380 |
| 312 } // namespace fileapi | 381 } // namespace fileapi |
| OLD | NEW |