Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "chrome/browser/chromeos/file_system_provider/fileapi/file_stream_write r.h" | 5 #include "chrome/browser/chromeos/file_system_provider/fileapi/file_stream_write r.h" |
| 6 | 6 |
| 7 #include "base/debug/trace_event.h" | 7 #include "base/debug/trace_event.h" |
| 8 #include "base/memory/ref_counted.h" | 8 #include "base/memory/ref_counted.h" |
| 9 #include "chrome/browser/chromeos/file_system_provider/fileapi/provider_async_fi le_util.h" | 9 #include "chrome/browser/chromeos/file_system_provider/fileapi/provider_async_fi le_util.h" |
| 10 #include "chrome/browser/chromeos/file_system_provider/mount_path_util.h" | 10 #include "chrome/browser/chromeos/file_system_provider/mount_path_util.h" |
| 11 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_inte rface.h" | 11 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_inte rface.h" |
| 12 #include "content/public/browser/browser_thread.h" | 12 #include "content/public/browser/browser_thread.h" |
| 13 #include "net/base/io_buffer.h" | 13 #include "net/base/io_buffer.h" |
| 14 #include "net/base/net_errors.h" | 14 #include "net/base/net_errors.h" |
| 15 | 15 |
| 16 using content::BrowserThread; | 16 using content::BrowserThread; |
| 17 | 17 |
| 18 namespace chromeos { | 18 namespace chromeos { |
| 19 namespace file_system_provider { | 19 namespace file_system_provider { |
| 20 namespace { | 20 namespace { |
| 21 | 21 |
| 22 // Dicards the callback from CloseFile(). | 22 // Dicards the callback from CloseFile(). |
| 23 void EmptyStatusCallback(base::File::Error /* result */) { | 23 void EmptyStatusCallback(base::File::Error /* result */) { |
| 24 } | 24 } |
| 25 | 25 |
| 26 // Opens a file for writing and calls the completion callback. Must be called | 26 } // namespace |
| 27 // on UI thread. | |
| 28 void OpenFileOnUIThread( | |
| 29 const fileapi::FileSystemURL& url, | |
| 30 const FileStreamWriter::OpenFileCompletedCallback& callback) { | |
| 31 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 32 | 27 |
| 33 util::FileSystemURLParser parser(url); | 28 class FileStreamWriter::OperationRunner |
| 34 if (!parser.Parse()) { | 29 : public base::RefCountedThreadSafe<FileStreamWriter::OperationRunner> { |
| 35 callback.Run(base::WeakPtr<ProvidedFileSystemInterface>(), | 30 public: |
| 36 base::FilePath(), | 31 OperationRunner() : file_handle_(-1) {} |
| 37 0 /* file_handle */, | 32 |
| 38 base::File::FILE_ERROR_SECURITY); | 33 // Opens a file for writing and calls the completion callback. Must be called |
| 39 return; | 34 // on UI thread. |
| 35 void OpenFileOnUIThread( | |
| 36 const fileapi::FileSystemURL& url, | |
| 37 const fileapi::AsyncFileUtil::StatusCallback& callback) { | |
| 38 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 39 | |
| 40 util::FileSystemURLParser parser(url); | |
| 41 if (!parser.Parse()) { | |
| 42 BrowserThread::PostTask( | |
| 43 BrowserThread::IO, | |
| 44 FROM_HERE, | |
| 45 base::Bind(callback, base::File::FILE_ERROR_SECURITY)); | |
| 46 return; | |
| 47 } | |
| 48 | |
| 49 file_system_ = parser.file_system()->GetWeakPtr(); | |
| 50 abort_callback_ = parser.file_system()->OpenFile( | |
| 51 parser.file_path(), | |
| 52 ProvidedFileSystemInterface::OPEN_FILE_MODE_WRITE, | |
| 53 base::Bind( | |
| 54 &OperationRunner::OnOpenFileCompletedOnUIThread, this, callback)); | |
| 40 } | 55 } |
| 41 | 56 |
| 42 parser.file_system()->OpenFile( | 57 // Closes a file. Ignores result, since outlives the caller. Must be called on |
| 43 parser.file_path(), | 58 // UI thread. |
| 44 ProvidedFileSystemInterface::OPEN_FILE_MODE_WRITE, | 59 void CloseFileOnUIThread() { |
| 45 base::Bind( | 60 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 46 callback, parser.file_system()->GetWeakPtr(), parser.file_path())); | 61 if (file_system_.get() && file_handle_ != -1) { |
| 47 } | 62 abort_callback_ = file_system_->CloseFile( |
| 48 | 63 file_handle_, base::Bind(&EmptyStatusCallback)); |
| 49 // Forwards results of calling OpenFileOnUIThread back to the IO thread. | 64 } |
| 50 void OnOpenFileCompletedOnUIThread( | |
| 51 const FileStreamWriter::OpenFileCompletedCallback& callback, | |
| 52 base::WeakPtr<ProvidedFileSystemInterface> file_system, | |
| 53 const base::FilePath& file_path, | |
| 54 int file_handle, | |
| 55 base::File::Error result) { | |
| 56 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 57 BrowserThread::PostTask( | |
| 58 BrowserThread::IO, | |
| 59 FROM_HERE, | |
| 60 base::Bind(callback, file_system, file_path, file_handle, result)); | |
| 61 } | |
| 62 | |
| 63 // Closes a file. Ignores result, since it is called from a constructor. | |
| 64 // Must be called on UI thread. | |
| 65 void CloseFileOnUIThread(base::WeakPtr<ProvidedFileSystemInterface> file_system, | |
| 66 int file_handle) { | |
| 67 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 68 if (file_system.get()) | |
| 69 file_system->CloseFile(file_handle, base::Bind(&EmptyStatusCallback)); | |
| 70 } | |
| 71 | |
| 72 // Requests writing bytes to the file. In case of either success or a failure | |
| 73 // |callback| is executed. Must be called on UI thread. | |
| 74 void WriteFileOnUIThread( | |
| 75 base::WeakPtr<ProvidedFileSystemInterface> file_system, | |
| 76 int file_handle, | |
| 77 scoped_refptr<net::IOBuffer> buffer, | |
| 78 int64 offset, | |
| 79 int length, | |
| 80 const fileapi::AsyncFileUtil::StatusCallback& callback) { | |
| 81 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 82 | |
| 83 // If the file system got unmounted, then abort the writing operation. | |
| 84 if (!file_system.get()) { | |
| 85 callback.Run(base::File::FILE_ERROR_ABORT); | |
| 86 return; | |
| 87 } | 65 } |
| 88 | 66 |
| 89 file_system->WriteFile(file_handle, buffer, offset, length, callback); | 67 // Requests writing bytes to the file. In case of either success or a failure |
| 90 } | 68 // |callback| is executed. Must be called on UI thread. |
| 69 void WriteFileOnUIThread( | |
| 70 scoped_refptr<net::IOBuffer> buffer, | |
| 71 int64 offset, | |
| 72 int length, | |
| 73 const fileapi::AsyncFileUtil::StatusCallback& callback) { | |
| 74 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 91 | 75 |
| 92 // Forward the completion callback to IO thread. | 76 // If the file system got unmounted, then abort the writing operation. |
| 93 void OnWriteFileCompletedOnUIThread( | 77 if (!file_system_.get()) { |
| 94 const fileapi::AsyncFileUtil::StatusCallback& callback, | 78 BrowserThread::PostTask( |
| 95 base::File::Error result) { | 79 BrowserThread::IO, |
| 96 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 80 FROM_HERE, |
| 97 BrowserThread::PostTask( | 81 base::Bind(callback, base::File::FILE_ERROR_ABORT)); |
| 98 BrowserThread::IO, FROM_HERE, base::Bind(callback, result)); | 82 return; |
| 99 } | 83 } |
| 100 | 84 |
| 101 } // namespace | 85 abort_callback_ = |
| 86 file_system_->WriteFile(file_handle_, buffer, offset, length, callback); | |
|
hirono
2014/08/06 08:33:50
Should we check file_handle_ != -1?
| |
| 87 } | |
| 88 | |
| 89 // Aborts the most recent operation (if exists), and calls the callback. | |
| 90 void AbortOnUIThread(const fileapi::AsyncFileUtil::StatusCallback& callback) { | |
| 91 if (abort_callback_.is_null()) { | |
| 92 // No operation on the file system being performed. At most a callback | |
| 93 // call, which will be discarded. | |
| 94 callback.Run(base::File::FILE_OK); | |
| 95 return; | |
| 96 } | |
| 97 | |
| 98 const ProvidedFileSystemInterface::AbortCallback abort_callback = | |
| 99 abort_callback_; | |
| 100 abort_callback_ = ProvidedFileSystemInterface::AbortCallback(); | |
| 101 abort_callback.Run(callback); | |
| 102 } | |
| 103 | |
| 104 private: | |
| 105 friend class base::RefCountedThreadSafe<OperationRunner>; | |
| 106 | |
| 107 virtual ~OperationRunner() {} | |
| 108 | |
| 109 // Remembers a file handle for further operations and forwards the result to | |
| 110 // the IO thread. | |
| 111 void OnOpenFileCompletedOnUIThread( | |
| 112 const fileapi::AsyncFileUtil::StatusCallback& callback, | |
| 113 int file_handle, | |
| 114 base::File::Error result) { | |
| 115 file_handle_ = file_handle; | |
| 116 BrowserThread::PostTask( | |
| 117 BrowserThread::IO, FROM_HERE, base::Bind(callback, result)); | |
| 118 } | |
| 119 | |
| 120 ProvidedFileSystemInterface::AbortCallback abort_callback_; | |
| 121 base::WeakPtr<ProvidedFileSystemInterface> file_system_; | |
| 122 int file_handle_; | |
| 123 | |
| 124 DISALLOW_COPY_AND_ASSIGN(OperationRunner); | |
| 125 }; | |
| 102 | 126 |
| 103 FileStreamWriter::FileStreamWriter(const fileapi::FileSystemURL& url, | 127 FileStreamWriter::FileStreamWriter(const fileapi::FileSystemURL& url, |
| 104 int64 initial_offset) | 128 int64 initial_offset) |
| 105 : url_(url), | 129 : url_(url), |
| 106 current_offset_(initial_offset), | 130 current_offset_(initial_offset), |
| 131 runner_(new OperationRunner), | |
| 107 state_(NOT_INITIALIZED), | 132 state_(NOT_INITIALIZED), |
| 108 file_handle_(0), | |
| 109 weak_ptr_factory_(this) { | 133 weak_ptr_factory_(this) { |
| 110 } | 134 } |
| 111 | 135 |
| 112 FileStreamWriter::~FileStreamWriter() { | 136 FileStreamWriter::~FileStreamWriter() { |
| 113 BrowserThread::PostTask( | 137 BrowserThread::PostTask( |
| 114 BrowserThread::UI, | 138 BrowserThread::UI, |
| 115 FROM_HERE, | 139 FROM_HERE, |
| 116 base::Bind(&CloseFileOnUIThread, file_system_, file_handle_)); | 140 base::Bind(&OperationRunner::CloseFileOnUIThread, runner_)); |
| 117 } | 141 } |
| 118 | 142 |
| 119 void FileStreamWriter::Initialize( | 143 void FileStreamWriter::Initialize( |
| 120 const base::Closure& pending_closure, | 144 const base::Closure& pending_closure, |
| 121 const net::CompletionCallback& error_callback) { | 145 const net::CompletionCallback& error_callback) { |
| 122 DCHECK_EQ(NOT_INITIALIZED, state_); | 146 DCHECK_EQ(NOT_INITIALIZED, state_); |
| 123 state_ = INITIALIZING; | 147 state_ = INITIALIZING; |
| 124 | 148 |
| 125 BrowserThread::PostTask( | 149 BrowserThread::PostTask( |
| 126 BrowserThread::UI, | 150 BrowserThread::UI, |
| 127 FROM_HERE, | 151 FROM_HERE, |
| 128 base::Bind(&OpenFileOnUIThread, | 152 base::Bind(&OperationRunner::OpenFileOnUIThread, |
| 153 runner_, | |
| 129 url_, | 154 url_, |
| 130 base::Bind(&OnOpenFileCompletedOnUIThread, | 155 base::Bind(&FileStreamWriter::OnOpenFileCompleted, |
| 131 base::Bind(&FileStreamWriter::OnOpenFileCompleted, | 156 weak_ptr_factory_.GetWeakPtr(), |
| 132 weak_ptr_factory_.GetWeakPtr(), | 157 pending_closure, |
| 133 pending_closure, | 158 error_callback))); |
| 134 error_callback)))); | |
| 135 } | 159 } |
| 136 | 160 |
| 137 void FileStreamWriter::OnOpenFileCompleted( | 161 void FileStreamWriter::OnOpenFileCompleted( |
| 138 const base::Closure& pending_closure, | 162 const base::Closure& pending_closure, |
| 139 const net::CompletionCallback& error_callback, | 163 const net::CompletionCallback& error_callback, |
| 140 base::WeakPtr<ProvidedFileSystemInterface> file_system, | |
| 141 const base::FilePath& file_path, | |
| 142 int file_handle, | |
| 143 base::File::Error result) { | 164 base::File::Error result) { |
| 144 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 165 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 145 DCHECK_EQ(INITIALIZING, state_); | 166 DCHECK_EQ(INITIALIZING, state_); |
| 146 | 167 |
| 147 // In case of an error, return immediately using the |error_callback| of the | 168 // In case of an error, return immediately using the |error_callback| of the |
| 148 // Write() pending request. | 169 // Write() pending request. |
| 149 if (result != base::File::FILE_OK) { | 170 if (result != base::File::FILE_OK) { |
| 150 state_ = FAILED; | 171 state_ = FAILED; |
| 151 error_callback.Run(net::FileErrorToNetError(result)); | 172 error_callback.Run(net::FileErrorToNetError(result)); |
| 152 return; | 173 return; |
| 153 } | 174 } |
| 154 | 175 |
| 155 file_system_ = file_system; | |
| 156 file_path_ = file_path; | |
| 157 file_handle_ = file_handle; | |
| 158 DCHECK_LT(0, file_handle); | |
| 159 DCHECK_EQ(base::File::FILE_OK, result); | 176 DCHECK_EQ(base::File::FILE_OK, result); |
| 160 state_ = INITIALIZED; | 177 state_ = INITIALIZED; |
| 161 | 178 |
| 162 // Run the task waiting for the initialization to be completed. | 179 // Run the task waiting for the initialization to be completed. |
| 163 pending_closure.Run(); | 180 pending_closure.Run(); |
| 164 } | 181 } |
| 165 | 182 |
| 166 int FileStreamWriter::Write(net::IOBuffer* buffer, | 183 int FileStreamWriter::Write(net::IOBuffer* buffer, |
| 167 int buffer_length, | 184 int buffer_length, |
| 168 const net::CompletionCallback& callback) { | 185 const net::CompletionCallback& callback) { |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 202 | 219 |
| 203 case FAILED: | 220 case FAILED: |
| 204 NOTREACHED(); | 221 NOTREACHED(); |
| 205 break; | 222 break; |
| 206 } | 223 } |
| 207 | 224 |
| 208 return net::ERR_IO_PENDING; | 225 return net::ERR_IO_PENDING; |
| 209 } | 226 } |
| 210 | 227 |
| 211 int FileStreamWriter::Cancel(const net::CompletionCallback& callback) { | 228 int FileStreamWriter::Cancel(const net::CompletionCallback& callback) { |
| 212 NOTIMPLEMENTED(); | 229 BrowserThread::PostTask( |
| 213 return net::ERR_FAILED; | 230 BrowserThread::UI, |
| 231 FROM_HERE, | |
| 232 base::Bind(&OperationRunner::AbortOnUIThread, | |
| 233 runner_, | |
| 234 base::Bind(&FileStreamWriter::OnAbortCompleted, | |
| 235 weak_ptr_factory_.GetWeakPtr(), | |
| 236 callback))); | |
| 237 return net::ERR_IO_PENDING; | |
| 214 } | 238 } |
| 215 | 239 |
| 216 int FileStreamWriter::Flush(const net::CompletionCallback& callback) { | 240 int FileStreamWriter::Flush(const net::CompletionCallback& callback) { |
| 217 if (state_ != INITIALIZED) | 241 if (state_ != INITIALIZED) |
| 218 return net::ERR_FAILED; | 242 return net::ERR_FAILED; |
| 219 | 243 |
| 220 return net::OK; | 244 return net::OK; |
| 221 } | 245 } |
| 222 | 246 |
| 223 void FileStreamWriter::OnWriteFileCompleted( | 247 void FileStreamWriter::OnWriteFileCompleted( |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 238 } | 262 } |
| 239 | 263 |
| 240 void FileStreamWriter::OnWriteCompleted(net::CompletionCallback callback, | 264 void FileStreamWriter::OnWriteCompleted(net::CompletionCallback callback, |
| 241 int result) { | 265 int result) { |
| 242 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 266 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 243 callback.Run(result); | 267 callback.Run(result); |
| 244 TRACE_EVENT_ASYNC_END0( | 268 TRACE_EVENT_ASYNC_END0( |
| 245 "file_system_provider", "FileStreamWriter::Write", this); | 269 "file_system_provider", "FileStreamWriter::Write", this); |
| 246 } | 270 } |
| 247 | 271 |
| 272 void FileStreamWriter::OnAbortCompleted(const net::CompletionCallback& callback, | |
| 273 base::File::Error result) { | |
| 274 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 275 | |
| 276 if (result != base::File::FILE_OK) | |
| 277 state_ = FAILED; | |
| 278 | |
| 279 callback.Run(net::FileErrorToNetError(result)); | |
| 280 } | |
| 281 | |
| 248 void FileStreamWriter::WriteAfterInitialized( | 282 void FileStreamWriter::WriteAfterInitialized( |
| 249 scoped_refptr<net::IOBuffer> buffer, | 283 scoped_refptr<net::IOBuffer> buffer, |
| 250 int buffer_length, | 284 int buffer_length, |
| 251 const net::CompletionCallback& callback) { | 285 const net::CompletionCallback& callback) { |
| 252 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 286 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 253 DCHECK_EQ(INITIALIZED, state_); | 287 DCHECK_EQ(INITIALIZED, state_); |
| 254 | 288 |
| 255 BrowserThread::PostTask( | 289 BrowserThread::PostTask( |
| 256 BrowserThread::UI, | 290 BrowserThread::UI, |
| 257 FROM_HERE, | 291 FROM_HERE, |
| 258 base::Bind(&WriteFileOnUIThread, | 292 base::Bind(&OperationRunner::WriteFileOnUIThread, |
| 259 file_system_, | 293 runner_, |
| 260 file_handle_, | |
| 261 buffer, | 294 buffer, |
| 262 current_offset_, | 295 current_offset_, |
| 263 buffer_length, | 296 buffer_length, |
| 264 base::Bind(&OnWriteFileCompletedOnUIThread, | 297 base::Bind(&FileStreamWriter::OnWriteFileCompleted, |
| 265 base::Bind(&FileStreamWriter::OnWriteFileCompleted, | 298 weak_ptr_factory_.GetWeakPtr(), |
| 266 weak_ptr_factory_.GetWeakPtr(), | 299 buffer_length, |
| 267 buffer_length, | 300 callback))); |
| 268 callback)))); | |
| 269 } | 301 } |
| 270 | 302 |
| 271 } // namespace file_system_provider | 303 } // namespace file_system_provider |
| 272 } // namespace chromeos | 304 } // namespace chromeos |
| OLD | NEW |