Elim cr-checkbox
[chromium-blink-merge.git] / chrome / browser / chromeos / file_system_provider / fileapi / file_stream_writer.cc
blob501ed7ad0d6c4da5d25ccd1c50e642662b043b86
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/memory/ref_counted.h"
8 #include "base/thread_task_runner_handle.h"
9 #include "base/trace_event/trace_event.h"
10 #include "chrome/browser/chromeos/file_system_provider/abort_callback.h"
11 #include "chrome/browser/chromeos/file_system_provider/fileapi/provider_async_file_util.h"
12 #include "chrome/browser/chromeos/file_system_provider/mount_path_util.h"
13 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h"
14 #include "chrome/browser/chromeos/file_system_provider/scoped_file_opener.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "net/base/io_buffer.h"
17 #include "net/base/net_errors.h"
19 using content::BrowserThread;
21 namespace chromeos {
22 namespace file_system_provider {
24 class FileStreamWriter::OperationRunner
25 : public base::RefCountedThreadSafe<
26 FileStreamWriter::OperationRunner,
27 content::BrowserThread::DeleteOnUIThread> {
28 public:
29 OperationRunner() : file_handle_(-1) {}
31 // Opens a file for writing and calls the completion callback. Must be called
32 // on UI thread.
33 void OpenFileOnUIThread(
34 const storage::FileSystemURL& url,
35 const storage::AsyncFileUtil::StatusCallback& callback) {
36 DCHECK_CURRENTLY_ON(BrowserThread::UI);
37 DCHECK(abort_callback_.is_null());
39 util::FileSystemURLParser parser(url);
40 if (!parser.Parse()) {
41 BrowserThread::PostTask(
42 BrowserThread::IO,
43 FROM_HERE,
44 base::Bind(callback, base::File::FILE_ERROR_SECURITY));
45 return;
48 file_system_ = parser.file_system()->GetWeakPtr();
49 file_opener_.reset(new ScopedFileOpener(
50 parser.file_system(), parser.file_path(), OPEN_FILE_MODE_WRITE,
51 base::Bind(&OperationRunner::OnOpenFileCompletedOnUIThread, this,
52 callback)));
55 // Requests writing bytes to the file. In case of either success or a failure
56 // |callback| is executed. Must be called on UI thread.
57 void WriteFileOnUIThread(
58 scoped_refptr<net::IOBuffer> buffer,
59 int64 offset,
60 int length,
61 const storage::AsyncFileUtil::StatusCallback& callback) {
62 DCHECK_CURRENTLY_ON(BrowserThread::UI);
63 DCHECK(abort_callback_.is_null());
65 // If the file system got unmounted, then abort the writing operation.
66 if (!file_system_.get()) {
67 BrowserThread::PostTask(
68 BrowserThread::IO,
69 FROM_HERE,
70 base::Bind(callback, base::File::FILE_ERROR_ABORT));
71 return;
74 abort_callback_ = file_system_->WriteFile(
75 file_handle_,
76 buffer.get(),
77 offset,
78 length,
79 base::Bind(
80 &OperationRunner::OnWriteFileCompletedOnUIThread, this, callback));
83 // Aborts the most recent operation (if exists) and closes a file if opened.
84 // The runner must not be used anymore after calling this method.
85 void CloseRunnerOnUIThread() {
86 DCHECK_CURRENTLY_ON(BrowserThread::UI);
88 if (!abort_callback_.is_null()) {
89 const AbortCallback last_abort_callback = abort_callback_;
90 abort_callback_ = AbortCallback();
91 last_abort_callback.Run();
94 // Close the file (if opened).
95 file_opener_.reset();
98 private:
99 friend struct content::BrowserThread::DeleteOnThread<
100 content::BrowserThread::UI>;
101 friend class base::DeleteHelper<OperationRunner>;
103 virtual ~OperationRunner() {}
105 // Remembers a file handle for further operations and forwards the result to
106 // the IO thread.
107 void OnOpenFileCompletedOnUIThread(
108 const storage::AsyncFileUtil::StatusCallback& callback,
109 int file_handle,
110 base::File::Error result) {
111 DCHECK_CURRENTLY_ON(BrowserThread::UI);
113 abort_callback_ = AbortCallback();
114 if (result == base::File::FILE_OK)
115 file_handle_ = file_handle;
117 BrowserThread::PostTask(
118 BrowserThread::IO, FROM_HERE, base::Bind(callback, result));
121 // Forwards a response of writing to a file to the IO thread.
122 void OnWriteFileCompletedOnUIThread(
123 const storage::AsyncFileUtil::StatusCallback& callback,
124 base::File::Error result) {
125 DCHECK_CURRENTLY_ON(BrowserThread::UI);
127 abort_callback_ = AbortCallback();
128 BrowserThread::PostTask(
129 BrowserThread::IO, FROM_HERE, base::Bind(callback, result));
132 AbortCallback abort_callback_;
133 base::WeakPtr<ProvidedFileSystemInterface> file_system_;
134 scoped_ptr<ScopedFileOpener> file_opener_;
135 int file_handle_;
137 DISALLOW_COPY_AND_ASSIGN(OperationRunner);
140 FileStreamWriter::FileStreamWriter(const storage::FileSystemURL& url,
141 int64 initial_offset)
142 : url_(url),
143 current_offset_(initial_offset),
144 runner_(new OperationRunner),
145 state_(NOT_INITIALIZED),
146 weak_ptr_factory_(this) {
149 FileStreamWriter::~FileStreamWriter() {
150 // Close the runner explicitly if the file streamer is
151 if (state_ != CANCELLING) {
152 BrowserThread::PostTask(
153 BrowserThread::UI, FROM_HERE,
154 base::Bind(&OperationRunner::CloseRunnerOnUIThread, runner_));
157 // If a write is in progress, mark it as completed.
158 TRACE_EVENT_ASYNC_END0("file_system_provider", "FileStreamWriter::Write",
159 this);
162 void FileStreamWriter::Initialize(
163 const base::Closure& pending_closure,
164 const net::CompletionCallback& error_callback) {
165 DCHECK_CURRENTLY_ON(BrowserThread::IO);
166 DCHECK_EQ(NOT_INITIALIZED, state_);
167 state_ = INITIALIZING;
169 BrowserThread::PostTask(
170 BrowserThread::UI,
171 FROM_HERE,
172 base::Bind(&OperationRunner::OpenFileOnUIThread,
173 runner_,
174 url_,
175 base::Bind(&FileStreamWriter::OnOpenFileCompleted,
176 weak_ptr_factory_.GetWeakPtr(),
177 pending_closure,
178 error_callback)));
181 void FileStreamWriter::OnOpenFileCompleted(
182 const base::Closure& pending_closure,
183 const net::CompletionCallback& error_callback,
184 base::File::Error result) {
185 DCHECK_CURRENTLY_ON(BrowserThread::IO);
186 DCHECK(state_ == INITIALIZING || state_ == CANCELLING);
187 if (state_ == CANCELLING)
188 return;
190 // In case of an error, return immediately using the |error_callback| of the
191 // Write() pending request.
192 if (result != base::File::FILE_OK) {
193 state_ = FAILED;
194 error_callback.Run(net::FileErrorToNetError(result));
195 return;
198 DCHECK_EQ(base::File::FILE_OK, result);
199 state_ = INITIALIZED;
201 // Run the task waiting for the initialization to be completed.
202 pending_closure.Run();
205 int FileStreamWriter::Write(net::IOBuffer* buffer,
206 int buffer_length,
207 const net::CompletionCallback& callback) {
208 DCHECK_CURRENTLY_ON(BrowserThread::IO);
209 TRACE_EVENT_ASYNC_BEGIN1("file_system_provider",
210 "FileStreamWriter::Write",
211 this,
212 "buffer_length",
213 buffer_length);
215 switch (state_) {
216 case NOT_INITIALIZED:
217 // Lazily initialize with the first call to Write().
218 Initialize(base::Bind(&FileStreamWriter::WriteAfterInitialized,
219 weak_ptr_factory_.GetWeakPtr(),
220 make_scoped_refptr(buffer),
221 buffer_length,
222 base::Bind(&FileStreamWriter::OnWriteCompleted,
223 weak_ptr_factory_.GetWeakPtr(),
224 callback)),
225 base::Bind(&FileStreamWriter::OnWriteCompleted,
226 weak_ptr_factory_.GetWeakPtr(),
227 callback));
228 break;
230 case INITIALIZING:
231 NOTREACHED();
232 break;
234 case INITIALIZED:
235 WriteAfterInitialized(buffer,
236 buffer_length,
237 base::Bind(&FileStreamWriter::OnWriteCompleted,
238 weak_ptr_factory_.GetWeakPtr(),
239 callback));
240 break;
242 case EXECUTING:
243 case FAILED:
244 case CANCELLING:
245 NOTREACHED();
246 break;
249 return net::ERR_IO_PENDING;
252 int FileStreamWriter::Cancel(const net::CompletionCallback& callback) {
253 DCHECK_CURRENTLY_ON(BrowserThread::IO);
255 if (state_ != INITIALIZING && state_ != EXECUTING)
256 return net::ERR_UNEXPECTED;
258 state_ = CANCELLING;
260 // Abort and optimistically return an OK result code, as the aborting
261 // operation is always forced and can't be cancelled. Similarly, for closing
262 // files.
263 BrowserThread::PostTask(
264 BrowserThread::UI, FROM_HERE,
265 base::Bind(&OperationRunner::CloseRunnerOnUIThread, runner_));
266 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
267 base::Bind(callback, net::OK));
269 // If a write is in progress, mark it as completed.
270 TRACE_EVENT_ASYNC_END0("file_system_provider", "FileStreamWriter::Write",
271 this);
273 return net::ERR_IO_PENDING;
276 int FileStreamWriter::Flush(const net::CompletionCallback& callback) {
277 DCHECK_CURRENTLY_ON(BrowserThread::IO);
278 DCHECK_NE(CANCELLING, state_);
280 base::ThreadTaskRunnerHandle::Get()->PostTask(
281 FROM_HERE,
282 base::Bind(callback, state_ == INITIALIZED ? net::OK : net::ERR_FAILED));
284 return net::ERR_IO_PENDING;
287 void FileStreamWriter::OnWriteFileCompleted(
288 int buffer_length,
289 const net::CompletionCallback& callback,
290 base::File::Error result) {
291 DCHECK_CURRENTLY_ON(BrowserThread::IO);
292 DCHECK(state_ == EXECUTING || state_ == CANCELLING);
293 if (state_ == CANCELLING)
294 return;
296 state_ = INITIALIZED;
298 if (result != base::File::FILE_OK) {
299 state_ = FAILED;
300 callback.Run(net::FileErrorToNetError(result));
301 return;
304 current_offset_ += buffer_length;
305 callback.Run(buffer_length);
308 void FileStreamWriter::OnWriteCompleted(net::CompletionCallback callback,
309 int result) {
310 DCHECK_CURRENTLY_ON(BrowserThread::IO);
311 if (state_ != CANCELLING)
312 callback.Run(result);
314 TRACE_EVENT_ASYNC_END0(
315 "file_system_provider", "FileStreamWriter::Write", this);
318 void FileStreamWriter::WriteAfterInitialized(
319 scoped_refptr<net::IOBuffer> buffer,
320 int buffer_length,
321 const net::CompletionCallback& callback) {
322 DCHECK_CURRENTLY_ON(BrowserThread::IO);
323 DCHECK(state_ == INITIALIZED || state_ == CANCELLING);
324 if (state_ == CANCELLING)
325 return;
327 state_ = EXECUTING;
329 BrowserThread::PostTask(
330 BrowserThread::UI,
331 FROM_HERE,
332 base::Bind(&OperationRunner::WriteFileOnUIThread,
333 runner_,
334 buffer,
335 current_offset_,
336 buffer_length,
337 base::Bind(&FileStreamWriter::OnWriteFileCompleted,
338 weak_ptr_factory_.GetWeakPtr(),
339 buffer_length,
340 callback)));
343 } // namespace file_system_provider
344 } // namespace chromeos