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
3 // found in the LICENSE file.
5 #include "chrome/browser/chromeos/file_system_provider/fileapi/file_stream_writer.h"
7 #include "base/debug/trace_event.h"
8 #include "base/memory/ref_counted.h"
9 #include "base/thread_task_runner_handle.h"
10 #include "chrome/browser/chromeos/file_system_provider/fileapi/provider_async_file_util.h"
11 #include "chrome/browser/chromeos/file_system_provider/mount_path_util.h"
12 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "net/base/io_buffer.h"
15 #include "net/base/net_errors.h"
17 using content::BrowserThread;
20 namespace file_system_provider {
23 // Dicards the callback from CloseFile().
24 void EmptyStatusCallback(base::File::Error /* result */) {
29 class FileStreamWriter::OperationRunner
30 : public base::RefCountedThreadSafe<FileStreamWriter::OperationRunner> {
32 OperationRunner() : file_handle_(-1) {}
34 // Opens a file for writing and calls the completion callback. Must be called
36 void OpenFileOnUIThread(
37 const storage::FileSystemURL& url,
38 const storage::AsyncFileUtil::StatusCallback& callback) {
39 DCHECK_CURRENTLY_ON(BrowserThread::UI);
41 util::FileSystemURLParser parser(url);
42 if (!parser.Parse()) {
43 BrowserThread::PostTask(
46 base::Bind(callback, base::File::FILE_ERROR_SECURITY));
50 file_system_ = parser.file_system()->GetWeakPtr();
51 abort_callback_ = parser.file_system()->OpenFile(
53 ProvidedFileSystemInterface::OPEN_FILE_MODE_WRITE,
55 &OperationRunner::OnOpenFileCompletedOnUIThread, this, callback));
58 // Closes a file. Ignores result, since outlives the caller. Must be called on
60 void CloseFileOnUIThread() {
61 DCHECK_CURRENTLY_ON(BrowserThread::UI);
62 if (file_system_.get() && file_handle_ != -1) {
63 // Closing a file must not be aborted, since we could end up on files
64 // which are never closed.
65 file_system_->CloseFile(file_handle_, base::Bind(&EmptyStatusCallback));
69 // Requests writing bytes to the file. In case of either success or a failure
70 // |callback| is executed. Must be called on UI thread.
71 void WriteFileOnUIThread(
72 scoped_refptr<net::IOBuffer> buffer,
75 const storage::AsyncFileUtil::StatusCallback& callback) {
76 DCHECK_CURRENTLY_ON(BrowserThread::UI);
78 // If the file system got unmounted, then abort the writing operation.
79 if (!file_system_.get()) {
80 BrowserThread::PostTask(
83 base::Bind(callback, base::File::FILE_ERROR_ABORT));
87 abort_callback_ = file_system_->WriteFile(
93 &OperationRunner::OnWriteFileCompletedOnUIThread, this, callback));
96 // Aborts the most recent operation (if exists), and calls the callback.
97 void AbortOnUIThread(const storage::AsyncFileUtil::StatusCallback& callback) {
98 DCHECK_CURRENTLY_ON(BrowserThread::UI);
100 if (abort_callback_.is_null()) {
101 // No operation to be cancelled. At most a callback call, which will be
103 BrowserThread::PostTask(BrowserThread::IO,
105 base::Bind(callback, base::File::FILE_OK));
109 const ProvidedFileSystemInterface::AbortCallback abort_callback =
111 abort_callback_ = ProvidedFileSystemInterface::AbortCallback();
112 abort_callback.Run(base::Bind(
113 &OperationRunner::OnAbortCompletedOnUIThread, this, callback));
117 friend class base::RefCountedThreadSafe<OperationRunner>;
119 virtual ~OperationRunner() {}
121 // Remembers a file handle for further operations and forwards the result to
123 void OnOpenFileCompletedOnUIThread(
124 const storage::AsyncFileUtil::StatusCallback& callback,
126 base::File::Error result) {
127 DCHECK_CURRENTLY_ON(BrowserThread::UI);
129 file_handle_ = file_handle;
130 BrowserThread::PostTask(
131 BrowserThread::IO, FROM_HERE, base::Bind(callback, result));
134 // Forwards a response of writing to a file to the IO thread.
135 void OnWriteFileCompletedOnUIThread(
136 const storage::AsyncFileUtil::StatusCallback& callback,
137 base::File::Error result) {
138 DCHECK_CURRENTLY_ON(BrowserThread::UI);
139 BrowserThread::PostTask(
140 BrowserThread::IO, FROM_HERE, base::Bind(callback, result));
143 // Forwards a response of aborting an operation to the IO thread.
144 void OnAbortCompletedOnUIThread(
145 const storage::AsyncFileUtil::StatusCallback& callback,
146 base::File::Error result) {
147 DCHECK_CURRENTLY_ON(BrowserThread::UI);
148 BrowserThread::PostTask(
149 BrowserThread::IO, FROM_HERE, base::Bind(callback, result));
152 ProvidedFileSystemInterface::AbortCallback abort_callback_;
153 base::WeakPtr<ProvidedFileSystemInterface> file_system_;
156 DISALLOW_COPY_AND_ASSIGN(OperationRunner);
159 FileStreamWriter::FileStreamWriter(const storage::FileSystemURL& url,
160 int64 initial_offset)
162 current_offset_(initial_offset),
163 runner_(new OperationRunner),
164 state_(NOT_INITIALIZED),
165 weak_ptr_factory_(this) {
168 FileStreamWriter::~FileStreamWriter() {
169 BrowserThread::PostTask(
172 base::Bind(&OperationRunner::CloseFileOnUIThread, runner_));
175 void FileStreamWriter::Initialize(
176 const base::Closure& pending_closure,
177 const net::CompletionCallback& error_callback) {
178 DCHECK_CURRENTLY_ON(BrowserThread::IO);
179 DCHECK_EQ(NOT_INITIALIZED, state_);
180 state_ = INITIALIZING;
182 BrowserThread::PostTask(
185 base::Bind(&OperationRunner::OpenFileOnUIThread,
188 base::Bind(&FileStreamWriter::OnOpenFileCompleted,
189 weak_ptr_factory_.GetWeakPtr(),
194 void FileStreamWriter::OnOpenFileCompleted(
195 const base::Closure& pending_closure,
196 const net::CompletionCallback& error_callback,
197 base::File::Error result) {
198 DCHECK_CURRENTLY_ON(BrowserThread::IO);
199 DCHECK_EQ(INITIALIZING, state_);
201 // In case of an error, return immediately using the |error_callback| of the
202 // Write() pending request.
203 if (result != base::File::FILE_OK) {
205 error_callback.Run(net::FileErrorToNetError(result));
209 DCHECK_EQ(base::File::FILE_OK, result);
210 state_ = INITIALIZED;
212 // Run the task waiting for the initialization to be completed.
213 pending_closure.Run();
216 int FileStreamWriter::Write(net::IOBuffer* buffer,
218 const net::CompletionCallback& callback) {
219 DCHECK_CURRENTLY_ON(BrowserThread::IO);
220 TRACE_EVENT_ASYNC_BEGIN1("file_system_provider",
221 "FileStreamWriter::Write",
227 case NOT_INITIALIZED:
228 // Lazily initialize with the first call to Write().
229 Initialize(base::Bind(&FileStreamWriter::WriteAfterInitialized,
230 weak_ptr_factory_.GetWeakPtr(),
231 make_scoped_refptr(buffer),
233 base::Bind(&FileStreamWriter::OnWriteCompleted,
234 weak_ptr_factory_.GetWeakPtr(),
236 base::Bind(&FileStreamWriter::OnWriteCompleted,
237 weak_ptr_factory_.GetWeakPtr(),
246 WriteAfterInitialized(buffer,
248 base::Bind(&FileStreamWriter::OnWriteCompleted,
249 weak_ptr_factory_.GetWeakPtr(),
258 return net::ERR_IO_PENDING;
261 int FileStreamWriter::Cancel(const net::CompletionCallback& callback) {
262 DCHECK_CURRENTLY_ON(BrowserThread::IO);
264 BrowserThread::PostTask(
267 base::Bind(&OperationRunner::AbortOnUIThread,
269 base::Bind(&FileStreamWriter::OnAbortCompleted,
270 weak_ptr_factory_.GetWeakPtr(),
272 return net::ERR_IO_PENDING;
275 int FileStreamWriter::Flush(const net::CompletionCallback& callback) {
276 base::ThreadTaskRunnerHandle::Get()->PostTask(
278 base::Bind(callback, state_ == INITIALIZED ? net::OK : net::ERR_FAILED));
280 return net::ERR_IO_PENDING;
283 void FileStreamWriter::OnWriteFileCompleted(
285 const net::CompletionCallback& callback,
286 base::File::Error result) {
287 DCHECK_CURRENTLY_ON(BrowserThread::IO);
288 DCHECK_EQ(INITIALIZED, state_);
290 if (result != base::File::FILE_OK) {
292 callback.Run(net::FileErrorToNetError(result));
296 current_offset_ += buffer_length;
297 callback.Run(buffer_length);
300 void FileStreamWriter::OnWriteCompleted(net::CompletionCallback callback,
302 DCHECK_CURRENTLY_ON(BrowserThread::IO);
303 callback.Run(result);
304 TRACE_EVENT_ASYNC_END0(
305 "file_system_provider", "FileStreamWriter::Write", this);
308 void FileStreamWriter::OnAbortCompleted(const net::CompletionCallback& callback,
309 base::File::Error result) {
310 DCHECK_CURRENTLY_ON(BrowserThread::IO);
312 if (result != base::File::FILE_OK)
315 callback.Run(net::FileErrorToNetError(result));
318 void FileStreamWriter::WriteAfterInitialized(
319 scoped_refptr<net::IOBuffer> buffer,
321 const net::CompletionCallback& callback) {
322 DCHECK_CURRENTLY_ON(BrowserThread::IO);
323 DCHECK_EQ(INITIALIZED, state_);
325 BrowserThread::PostTask(
328 base::Bind(&OperationRunner::WriteFileOnUIThread,
333 base::Bind(&FileStreamWriter::OnWriteFileCompleted,
334 weak_ptr_factory_.GetWeakPtr(),
339 } // namespace file_system_provider
340 } // namespace chromeos