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 "chrome/browser/chromeos/file_system_provider/fileapi/provider_async_file_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_interface.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "net/base/io_buffer.h"
14 #include "net/base/net_errors.h"
16 using content::BrowserThread;
19 namespace file_system_provider {
22 // Dicards the callback from CloseFile().
23 void EmptyStatusCallback(base::File::Error /* result */) {
28 class FileStreamWriter::OperationRunner
29 : public base::RefCountedThreadSafe<FileStreamWriter::OperationRunner> {
31 OperationRunner() : file_handle_(-1) {}
33 // Opens a file for writing and calls the completion callback. Must be called
35 void OpenFileOnUIThread(
36 const storage::FileSystemURL& url,
37 const storage::AsyncFileUtil::StatusCallback& callback) {
38 DCHECK_CURRENTLY_ON(BrowserThread::UI);
40 util::FileSystemURLParser parser(url);
41 if (!parser.Parse()) {
42 BrowserThread::PostTask(
45 base::Bind(callback, base::File::FILE_ERROR_SECURITY));
49 file_system_ = parser.file_system()->GetWeakPtr();
50 abort_callback_ = parser.file_system()->OpenFile(
52 ProvidedFileSystemInterface::OPEN_FILE_MODE_WRITE,
54 &OperationRunner::OnOpenFileCompletedOnUIThread, this, callback));
57 // Closes a file. Ignores result, since outlives the caller. Must be called on
59 void CloseFileOnUIThread() {
60 DCHECK_CURRENTLY_ON(BrowserThread::UI);
61 if (file_system_.get() && file_handle_ != -1) {
62 // Closing a file must not be aborted, since we could end up on files
63 // which are never closed.
64 file_system_->CloseFile(file_handle_, base::Bind(&EmptyStatusCallback));
68 // Requests writing bytes to the file. In case of either success or a failure
69 // |callback| is executed. Must be called on UI thread.
70 void WriteFileOnUIThread(
71 scoped_refptr<net::IOBuffer> buffer,
74 const storage::AsyncFileUtil::StatusCallback& callback) {
75 DCHECK_CURRENTLY_ON(BrowserThread::UI);
77 // If the file system got unmounted, then abort the writing operation.
78 if (!file_system_.get()) {
79 BrowserThread::PostTask(
82 base::Bind(callback, base::File::FILE_ERROR_ABORT));
86 abort_callback_ = file_system_->WriteFile(
92 &OperationRunner::OnWriteFileCompletedOnUIThread, this, callback));
95 // Aborts the most recent operation (if exists), and calls the callback.
96 void AbortOnUIThread(const storage::AsyncFileUtil::StatusCallback& callback) {
97 DCHECK_CURRENTLY_ON(BrowserThread::UI);
99 if (abort_callback_.is_null()) {
100 // No operation to be cancelled. At most a callback call, which will be
102 BrowserThread::PostTask(BrowserThread::IO,
104 base::Bind(callback, base::File::FILE_OK));
108 const ProvidedFileSystemInterface::AbortCallback abort_callback =
110 abort_callback_ = ProvidedFileSystemInterface::AbortCallback();
111 abort_callback.Run(base::Bind(
112 &OperationRunner::OnAbortCompletedOnUIThread, this, callback));
116 friend class base::RefCountedThreadSafe<OperationRunner>;
118 virtual ~OperationRunner() {}
120 // Remembers a file handle for further operations and forwards the result to
122 void OnOpenFileCompletedOnUIThread(
123 const storage::AsyncFileUtil::StatusCallback& callback,
125 base::File::Error result) {
126 DCHECK_CURRENTLY_ON(BrowserThread::UI);
128 file_handle_ = file_handle;
129 BrowserThread::PostTask(
130 BrowserThread::IO, FROM_HERE, base::Bind(callback, result));
133 // Forwards a response of writing to a file to the IO thread.
134 void OnWriteFileCompletedOnUIThread(
135 const storage::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));
142 // Forwards a response of aborting an operation to the IO thread.
143 void OnAbortCompletedOnUIThread(
144 const storage::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));
151 ProvidedFileSystemInterface::AbortCallback abort_callback_;
152 base::WeakPtr<ProvidedFileSystemInterface> file_system_;
155 DISALLOW_COPY_AND_ASSIGN(OperationRunner);
158 FileStreamWriter::FileStreamWriter(const storage::FileSystemURL& url,
159 int64 initial_offset)
161 current_offset_(initial_offset),
162 runner_(new OperationRunner),
163 state_(NOT_INITIALIZED),
164 weak_ptr_factory_(this) {
167 FileStreamWriter::~FileStreamWriter() {
168 BrowserThread::PostTask(
171 base::Bind(&OperationRunner::CloseFileOnUIThread, runner_));
174 void FileStreamWriter::Initialize(
175 const base::Closure& pending_closure,
176 const net::CompletionCallback& error_callback) {
177 DCHECK_CURRENTLY_ON(BrowserThread::IO);
178 DCHECK_EQ(NOT_INITIALIZED, state_);
179 state_ = INITIALIZING;
181 BrowserThread::PostTask(
184 base::Bind(&OperationRunner::OpenFileOnUIThread,
187 base::Bind(&FileStreamWriter::OnOpenFileCompleted,
188 weak_ptr_factory_.GetWeakPtr(),
193 void FileStreamWriter::OnOpenFileCompleted(
194 const base::Closure& pending_closure,
195 const net::CompletionCallback& error_callback,
196 base::File::Error result) {
197 DCHECK_CURRENTLY_ON(BrowserThread::IO);
198 DCHECK_EQ(INITIALIZING, state_);
200 // In case of an error, return immediately using the |error_callback| of the
201 // Write() pending request.
202 if (result != base::File::FILE_OK) {
204 error_callback.Run(net::FileErrorToNetError(result));
208 DCHECK_EQ(base::File::FILE_OK, result);
209 state_ = INITIALIZED;
211 // Run the task waiting for the initialization to be completed.
212 pending_closure.Run();
215 int FileStreamWriter::Write(net::IOBuffer* buffer,
217 const net::CompletionCallback& callback) {
218 DCHECK_CURRENTLY_ON(BrowserThread::IO);
219 TRACE_EVENT_ASYNC_BEGIN1("file_system_provider",
220 "FileStreamWriter::Write",
226 case NOT_INITIALIZED:
227 // Lazily initialize with the first call to Write().
228 Initialize(base::Bind(&FileStreamWriter::WriteAfterInitialized,
229 weak_ptr_factory_.GetWeakPtr(),
230 make_scoped_refptr(buffer),
232 base::Bind(&FileStreamWriter::OnWriteCompleted,
233 weak_ptr_factory_.GetWeakPtr(),
235 base::Bind(&FileStreamWriter::OnWriteCompleted,
236 weak_ptr_factory_.GetWeakPtr(),
245 WriteAfterInitialized(buffer,
247 base::Bind(&FileStreamWriter::OnWriteCompleted,
248 weak_ptr_factory_.GetWeakPtr(),
257 return net::ERR_IO_PENDING;
260 int FileStreamWriter::Cancel(const net::CompletionCallback& callback) {
261 DCHECK_CURRENTLY_ON(BrowserThread::IO);
263 BrowserThread::PostTask(
266 base::Bind(&OperationRunner::AbortOnUIThread,
268 base::Bind(&FileStreamWriter::OnAbortCompleted,
269 weak_ptr_factory_.GetWeakPtr(),
271 return net::ERR_IO_PENDING;
274 int FileStreamWriter::Flush(const net::CompletionCallback& callback) {
275 if (state_ != INITIALIZED)
276 return net::ERR_FAILED;
281 void FileStreamWriter::OnWriteFileCompleted(
283 const net::CompletionCallback& callback,
284 base::File::Error result) {
285 DCHECK_CURRENTLY_ON(BrowserThread::IO);
286 DCHECK_EQ(INITIALIZED, state_);
288 if (result != base::File::FILE_OK) {
290 callback.Run(net::FileErrorToNetError(result));
294 current_offset_ += buffer_length;
295 callback.Run(buffer_length);
298 void FileStreamWriter::OnWriteCompleted(net::CompletionCallback callback,
300 DCHECK_CURRENTLY_ON(BrowserThread::IO);
301 callback.Run(result);
302 TRACE_EVENT_ASYNC_END0(
303 "file_system_provider", "FileStreamWriter::Write", this);
306 void FileStreamWriter::OnAbortCompleted(const net::CompletionCallback& callback,
307 base::File::Error result) {
308 DCHECK_CURRENTLY_ON(BrowserThread::IO);
310 if (result != base::File::FILE_OK)
313 callback.Run(net::FileErrorToNetError(result));
316 void FileStreamWriter::WriteAfterInitialized(
317 scoped_refptr<net::IOBuffer> buffer,
319 const net::CompletionCallback& callback) {
320 DCHECK_CURRENTLY_ON(BrowserThread::IO);
321 DCHECK_EQ(INITIALIZED, state_);
323 BrowserThread::PostTask(
326 base::Bind(&OperationRunner::WriteFileOnUIThread,
331 base::Bind(&FileStreamWriter::OnWriteFileCompleted,
332 weak_ptr_factory_.GetWeakPtr(),
337 } // namespace file_system_provider
338 } // namespace chromeos