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 */) {
26 // Opens a file for writing and calls the completion callback. Must be called
28 void OpenFileOnUIThread(
29 const fileapi::FileSystemURL& url,
30 const FileStreamWriter::OpenFileCompletedCallback& callback) {
31 DCHECK_CURRENTLY_ON(BrowserThread::UI);
33 util::FileSystemURLParser parser(url);
34 if (!parser.Parse()) {
35 callback.Run(base::WeakPtr<ProvidedFileSystemInterface>(),
38 base::File::FILE_ERROR_SECURITY);
42 parser.file_system()->OpenFile(
44 ProvidedFileSystemInterface::OPEN_FILE_MODE_WRITE,
46 callback, parser.file_system()->GetWeakPtr(), parser.file_path()));
49 // Forwards results of calling OpenFileOnUIThread back to the IO thread.
50 void OnOpenFileCompletedOnUIThread(
51 const FileStreamWriter::OpenFileCompletedCallback& callback,
52 base::WeakPtr<ProvidedFileSystemInterface> file_system,
53 const base::FilePath& file_path,
55 base::File::Error result) {
56 DCHECK_CURRENTLY_ON(BrowserThread::UI);
57 BrowserThread::PostTask(
60 base::Bind(callback, file_system, file_path, file_handle, result));
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,
67 DCHECK_CURRENTLY_ON(BrowserThread::UI);
68 if (file_system.get())
69 file_system->CloseFile(file_handle, base::Bind(&EmptyStatusCallback));
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,
77 scoped_refptr<net::IOBuffer> buffer,
80 const fileapi::AsyncFileUtil::StatusCallback& callback) {
81 DCHECK_CURRENTLY_ON(BrowserThread::UI);
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);
89 file_system->WriteFile(file_handle, buffer, offset, length, callback);
92 // Forward the completion callback to IO thread.
93 void OnWriteFileCompletedOnUIThread(
94 const fileapi::AsyncFileUtil::StatusCallback& callback,
95 base::File::Error result) {
96 DCHECK_CURRENTLY_ON(BrowserThread::UI);
97 BrowserThread::PostTask(
98 BrowserThread::IO, FROM_HERE, base::Bind(callback, result));
103 FileStreamWriter::FileStreamWriter(const fileapi::FileSystemURL& url,
104 int64 initial_offset)
106 current_offset_(initial_offset),
107 state_(NOT_INITIALIZED),
109 weak_ptr_factory_(this) {
112 FileStreamWriter::~FileStreamWriter() {
113 BrowserThread::PostTask(
116 base::Bind(&CloseFileOnUIThread, file_system_, file_handle_));
119 void FileStreamWriter::Initialize(
120 const base::Closure& pending_closure,
121 const net::CompletionCallback& error_callback) {
122 DCHECK_EQ(NOT_INITIALIZED, state_);
123 state_ = INITIALIZING;
125 BrowserThread::PostTask(
128 base::Bind(&OpenFileOnUIThread,
130 base::Bind(&OnOpenFileCompletedOnUIThread,
131 base::Bind(&FileStreamWriter::OnOpenFileCompleted,
132 weak_ptr_factory_.GetWeakPtr(),
137 void FileStreamWriter::OnOpenFileCompleted(
138 const base::Closure& pending_closure,
139 const net::CompletionCallback& error_callback,
140 base::WeakPtr<ProvidedFileSystemInterface> file_system,
141 const base::FilePath& file_path,
143 base::File::Error result) {
144 DCHECK_CURRENTLY_ON(BrowserThread::IO);
145 DCHECK_EQ(INITIALIZING, state_);
147 // In case of an error, return immediately using the |error_callback| of the
148 // Write() pending request.
149 if (result != base::File::FILE_OK) {
151 error_callback.Run(net::FileErrorToNetError(result));
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);
160 state_ = INITIALIZED;
162 // Run the task waiting for the initialization to be completed.
163 pending_closure.Run();
166 int FileStreamWriter::Write(net::IOBuffer* buffer,
168 const net::CompletionCallback& callback) {
169 DCHECK_CURRENTLY_ON(BrowserThread::IO);
170 TRACE_EVENT_ASYNC_BEGIN1("file_system_provider",
171 "FileStreamWriter::Write",
177 case NOT_INITIALIZED:
178 // Lazily initialize with the first call to Write().
179 Initialize(base::Bind(&FileStreamWriter::WriteAfterInitialized,
180 weak_ptr_factory_.GetWeakPtr(),
181 make_scoped_refptr(buffer),
183 base::Bind(&FileStreamWriter::OnWriteCompleted,
184 weak_ptr_factory_.GetWeakPtr(),
186 base::Bind(&FileStreamWriter::OnWriteCompleted,
187 weak_ptr_factory_.GetWeakPtr(),
196 WriteAfterInitialized(buffer,
198 base::Bind(&FileStreamWriter::OnWriteCompleted,
199 weak_ptr_factory_.GetWeakPtr(),
208 return net::ERR_IO_PENDING;
211 int FileStreamWriter::Cancel(const net::CompletionCallback& callback) {
213 return net::ERR_FAILED;
216 int FileStreamWriter::Flush(const net::CompletionCallback& callback) {
217 if (state_ != INITIALIZED)
218 return net::ERR_FAILED;
223 void FileStreamWriter::OnWriteFileCompleted(
225 const net::CompletionCallback& callback,
226 base::File::Error result) {
227 DCHECK_CURRENTLY_ON(BrowserThread::IO);
228 DCHECK_EQ(INITIALIZED, state_);
230 if (result != base::File::FILE_OK) {
232 callback.Run(net::FileErrorToNetError(result));
236 current_offset_ += buffer_length;
237 callback.Run(buffer_length);
240 void FileStreamWriter::OnWriteCompleted(net::CompletionCallback callback,
242 DCHECK_CURRENTLY_ON(BrowserThread::IO);
243 callback.Run(result);
244 TRACE_EVENT_ASYNC_END0(
245 "file_system_provider", "FileStreamWriter::Write", this);
248 void FileStreamWriter::WriteAfterInitialized(
249 scoped_refptr<net::IOBuffer> buffer,
251 const net::CompletionCallback& callback) {
252 DCHECK_CURRENTLY_ON(BrowserThread::IO);
253 DCHECK_EQ(INITIALIZED, state_);
255 BrowserThread::PostTask(
258 base::Bind(&WriteFileOnUIThread,
264 base::Bind(&OnWriteFileCompletedOnUIThread,
265 base::Bind(&FileStreamWriter::OnWriteFileCompleted,
266 weak_ptr_factory_.GetWeakPtr(),
271 } // namespace file_system_provider
272 } // namespace chromeos