| 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_ = file_system_->WriteFile( |
| 86 file_handle_, |
| 87 buffer, |
| 88 offset, |
| 89 length, |
| 90 base::Bind( |
| 91 &OperationRunner::OnWriteFileCompletedOnUIThread, this, callback)); |
| 92 } |
| 93 |
| 94 // Aborts the most recent operation (if exists), and calls the callback. |
| 95 void AbortOnUIThread(const fileapi::AsyncFileUtil::StatusCallback& callback) { |
| 96 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 97 |
| 98 if (abort_callback_.is_null()) { |
| 99 // No operation on the file system being performed. At most a callback |
| 100 // call, which will be discarded. |
| 101 BrowserThread::PostTask( |
| 102 BrowserThread::IO, |
| 103 FROM_HERE, |
| 104 base::Bind(callback, base::File::FILE_ERROR_ABORT)); |
| 105 return; |
| 106 } |
| 107 |
| 108 const ProvidedFileSystemInterface::AbortCallback abort_callback = |
| 109 abort_callback_; |
| 110 abort_callback_ = ProvidedFileSystemInterface::AbortCallback(); |
| 111 abort_callback.Run(base::Bind( |
| 112 &OperationRunner::OnAbortCompletedOnUIThread, this, callback)); |
| 113 } |
| 114 |
| 115 private: |
| 116 friend class base::RefCountedThreadSafe<OperationRunner>; |
| 117 |
| 118 virtual ~OperationRunner() {} |
| 119 |
| 120 // Remembers a file handle for further operations and forwards the result to |
| 121 // the IO thread. |
| 122 void OnOpenFileCompletedOnUIThread( |
| 123 const fileapi::AsyncFileUtil::StatusCallback& callback, |
| 124 int file_handle, |
| 125 base::File::Error result) { |
| 126 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 127 |
| 128 file_handle_ = file_handle; |
| 129 BrowserThread::PostTask( |
| 130 BrowserThread::IO, FROM_HERE, base::Bind(callback, result)); |
| 131 } |
| 132 |
| 133 // Forwards a response of writing to a file to the IO thread. |
| 134 void OnWriteFileCompletedOnUIThread( |
| 135 const fileapi::AsyncFileUtil::StatusCallback& callback, |
| 136 base::File::Error result) { |
| 137 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 138 BrowserThread::PostTask( |
| 139 BrowserThread::IO, FROM_HERE, base::Bind(callback, result)); |
| 140 } |
| 141 |
| 142 // Forwards a response of aborting an operation to the IO thread. |
| 143 void OnAbortCompletedOnUIThread( |
| 144 const fileapi::AsyncFileUtil::StatusCallback& callback, |
| 145 base::File::Error result) { |
| 146 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 147 BrowserThread::PostTask( |
| 148 BrowserThread::IO, FROM_HERE, base::Bind(callback, result)); |
| 149 } |
| 150 |
| 151 ProvidedFileSystemInterface::AbortCallback abort_callback_; |
| 152 base::WeakPtr<ProvidedFileSystemInterface> file_system_; |
| 153 int file_handle_; |
| 154 |
| 155 DISALLOW_COPY_AND_ASSIGN(OperationRunner); |
| 156 }; |
| 102 | 157 |
| 103 FileStreamWriter::FileStreamWriter(const fileapi::FileSystemURL& url, | 158 FileStreamWriter::FileStreamWriter(const fileapi::FileSystemURL& url, |
| 104 int64 initial_offset) | 159 int64 initial_offset) |
| 105 : url_(url), | 160 : url_(url), |
| 106 current_offset_(initial_offset), | 161 current_offset_(initial_offset), |
| 162 runner_(new OperationRunner), |
| 107 state_(NOT_INITIALIZED), | 163 state_(NOT_INITIALIZED), |
| 108 file_handle_(0), | |
| 109 weak_ptr_factory_(this) { | 164 weak_ptr_factory_(this) { |
| 110 } | 165 } |
| 111 | 166 |
| 112 FileStreamWriter::~FileStreamWriter() { | 167 FileStreamWriter::~FileStreamWriter() { |
| 113 BrowserThread::PostTask( | 168 BrowserThread::PostTask( |
| 114 BrowserThread::UI, | 169 BrowserThread::UI, |
| 115 FROM_HERE, | 170 FROM_HERE, |
| 116 base::Bind(&CloseFileOnUIThread, file_system_, file_handle_)); | 171 base::Bind(&OperationRunner::CloseFileOnUIThread, runner_)); |
| 117 } | 172 } |
| 118 | 173 |
| 119 void FileStreamWriter::Initialize( | 174 void FileStreamWriter::Initialize( |
| 120 const base::Closure& pending_closure, | 175 const base::Closure& pending_closure, |
| 121 const net::CompletionCallback& error_callback) { | 176 const net::CompletionCallback& error_callback) { |
| 177 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 122 DCHECK_EQ(NOT_INITIALIZED, state_); | 178 DCHECK_EQ(NOT_INITIALIZED, state_); |
| 123 state_ = INITIALIZING; | 179 state_ = INITIALIZING; |
| 124 | 180 |
| 125 BrowserThread::PostTask( | 181 BrowserThread::PostTask( |
| 126 BrowserThread::UI, | 182 BrowserThread::UI, |
| 127 FROM_HERE, | 183 FROM_HERE, |
| 128 base::Bind(&OpenFileOnUIThread, | 184 base::Bind(&OperationRunner::OpenFileOnUIThread, |
| 185 runner_, |
| 129 url_, | 186 url_, |
| 130 base::Bind(&OnOpenFileCompletedOnUIThread, | 187 base::Bind(&FileStreamWriter::OnOpenFileCompleted, |
| 131 base::Bind(&FileStreamWriter::OnOpenFileCompleted, | 188 weak_ptr_factory_.GetWeakPtr(), |
| 132 weak_ptr_factory_.GetWeakPtr(), | 189 pending_closure, |
| 133 pending_closure, | 190 error_callback))); |
| 134 error_callback)))); | |
| 135 } | 191 } |
| 136 | 192 |
| 137 void FileStreamWriter::OnOpenFileCompleted( | 193 void FileStreamWriter::OnOpenFileCompleted( |
| 138 const base::Closure& pending_closure, | 194 const base::Closure& pending_closure, |
| 139 const net::CompletionCallback& error_callback, | 195 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) { | 196 base::File::Error result) { |
| 144 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 197 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 145 DCHECK_EQ(INITIALIZING, state_); | 198 DCHECK_EQ(INITIALIZING, state_); |
| 146 | 199 |
| 147 // In case of an error, return immediately using the |error_callback| of the | 200 // In case of an error, return immediately using the |error_callback| of the |
| 148 // Write() pending request. | 201 // Write() pending request. |
| 149 if (result != base::File::FILE_OK) { | 202 if (result != base::File::FILE_OK) { |
| 150 state_ = FAILED; | 203 state_ = FAILED; |
| 151 error_callback.Run(net::FileErrorToNetError(result)); | 204 error_callback.Run(net::FileErrorToNetError(result)); |
| 152 return; | 205 return; |
| 153 } | 206 } |
| 154 | 207 |
| 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); | 208 DCHECK_EQ(base::File::FILE_OK, result); |
| 160 state_ = INITIALIZED; | 209 state_ = INITIALIZED; |
| 161 | 210 |
| 162 // Run the task waiting for the initialization to be completed. | 211 // Run the task waiting for the initialization to be completed. |
| 163 pending_closure.Run(); | 212 pending_closure.Run(); |
| 164 } | 213 } |
| 165 | 214 |
| 166 int FileStreamWriter::Write(net::IOBuffer* buffer, | 215 int FileStreamWriter::Write(net::IOBuffer* buffer, |
| 167 int buffer_length, | 216 int buffer_length, |
| 168 const net::CompletionCallback& callback) { | 217 const net::CompletionCallback& callback) { |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 202 | 251 |
| 203 case FAILED: | 252 case FAILED: |
| 204 NOTREACHED(); | 253 NOTREACHED(); |
| 205 break; | 254 break; |
| 206 } | 255 } |
| 207 | 256 |
| 208 return net::ERR_IO_PENDING; | 257 return net::ERR_IO_PENDING; |
| 209 } | 258 } |
| 210 | 259 |
| 211 int FileStreamWriter::Cancel(const net::CompletionCallback& callback) { | 260 int FileStreamWriter::Cancel(const net::CompletionCallback& callback) { |
| 212 NOTIMPLEMENTED(); | 261 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 213 return net::ERR_FAILED; | 262 |
| 263 BrowserThread::PostTask( |
| 264 BrowserThread::UI, |
| 265 FROM_HERE, |
| 266 base::Bind(&OperationRunner::AbortOnUIThread, |
| 267 runner_, |
| 268 base::Bind(&FileStreamWriter::OnAbortCompleted, |
| 269 weak_ptr_factory_.GetWeakPtr(), |
| 270 callback))); |
| 271 return net::ERR_IO_PENDING; |
| 214 } | 272 } |
| 215 | 273 |
| 216 int FileStreamWriter::Flush(const net::CompletionCallback& callback) { | 274 int FileStreamWriter::Flush(const net::CompletionCallback& callback) { |
| 217 if (state_ != INITIALIZED) | 275 if (state_ != INITIALIZED) |
| 218 return net::ERR_FAILED; | 276 return net::ERR_FAILED; |
| 219 | 277 |
| 220 return net::OK; | 278 return net::OK; |
| 221 } | 279 } |
| 222 | 280 |
| 223 void FileStreamWriter::OnWriteFileCompleted( | 281 void FileStreamWriter::OnWriteFileCompleted( |
| (...skipping 14 matching lines...) Expand all Loading... |
| 238 } | 296 } |
| 239 | 297 |
| 240 void FileStreamWriter::OnWriteCompleted(net::CompletionCallback callback, | 298 void FileStreamWriter::OnWriteCompleted(net::CompletionCallback callback, |
| 241 int result) { | 299 int result) { |
| 242 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 300 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 243 callback.Run(result); | 301 callback.Run(result); |
| 244 TRACE_EVENT_ASYNC_END0( | 302 TRACE_EVENT_ASYNC_END0( |
| 245 "file_system_provider", "FileStreamWriter::Write", this); | 303 "file_system_provider", "FileStreamWriter::Write", this); |
| 246 } | 304 } |
| 247 | 305 |
| 306 void FileStreamWriter::OnAbortCompleted(const net::CompletionCallback& callback, |
| 307 base::File::Error result) { |
| 308 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 309 |
| 310 if (result != base::File::FILE_OK) |
| 311 state_ = FAILED; |
| 312 |
| 313 callback.Run(net::FileErrorToNetError(result)); |
| 314 } |
| 315 |
| 248 void FileStreamWriter::WriteAfterInitialized( | 316 void FileStreamWriter::WriteAfterInitialized( |
| 249 scoped_refptr<net::IOBuffer> buffer, | 317 scoped_refptr<net::IOBuffer> buffer, |
| 250 int buffer_length, | 318 int buffer_length, |
| 251 const net::CompletionCallback& callback) { | 319 const net::CompletionCallback& callback) { |
| 252 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 320 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 253 DCHECK_EQ(INITIALIZED, state_); | 321 DCHECK_EQ(INITIALIZED, state_); |
| 254 | 322 |
| 255 BrowserThread::PostTask( | 323 BrowserThread::PostTask( |
| 256 BrowserThread::UI, | 324 BrowserThread::UI, |
| 257 FROM_HERE, | 325 FROM_HERE, |
| 258 base::Bind(&WriteFileOnUIThread, | 326 base::Bind(&OperationRunner::WriteFileOnUIThread, |
| 259 file_system_, | 327 runner_, |
| 260 file_handle_, | |
| 261 buffer, | 328 buffer, |
| 262 current_offset_, | 329 current_offset_, |
| 263 buffer_length, | 330 buffer_length, |
| 264 base::Bind(&OnWriteFileCompletedOnUIThread, | 331 base::Bind(&FileStreamWriter::OnWriteFileCompleted, |
| 265 base::Bind(&FileStreamWriter::OnWriteFileCompleted, | 332 weak_ptr_factory_.GetWeakPtr(), |
| 266 weak_ptr_factory_.GetWeakPtr(), | 333 buffer_length, |
| 267 buffer_length, | 334 callback))); |
| 268 callback)))); | |
| 269 } | 335 } |
| 270 | 336 |
| 271 } // namespace file_system_provider | 337 } // namespace file_system_provider |
| 272 } // namespace chromeos | 338 } // namespace chromeos |
| OLD | NEW |