Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / chromeos / file_system_provider / fileapi / file_stream_writer.cc
blob9b43fcf253ff716584230b98621682228b80ebe7
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 "content/public/browser/browser_thread.h"
15 #include "net/base/io_buffer.h"
16 #include "net/base/net_errors.h"
18 using content::BrowserThread;
20 namespace chromeos {
21 namespace file_system_provider {
22 namespace {
24 // Dicards the callback from CloseFile().
25 void EmptyStatusCallback(base::File::Error /* result */) {
28 } // namespace
30 class FileStreamWriter::OperationRunner
31 : public base::RefCountedThreadSafe<FileStreamWriter::OperationRunner> {
32 public:
33 OperationRunner() : file_handle_(-1) {}
35 // Opens a file for writing and calls the completion callback. Must be called
36 // on UI thread.
37 void OpenFileOnUIThread(
38 const storage::FileSystemURL& url,
39 const storage::AsyncFileUtil::StatusCallback& callback) {
40 DCHECK_CURRENTLY_ON(BrowserThread::UI);
41 DCHECK(abort_callback_.is_null());
43 util::FileSystemURLParser parser(url);
44 if (!parser.Parse()) {
45 BrowserThread::PostTask(
46 BrowserThread::IO,
47 FROM_HERE,
48 base::Bind(callback, base::File::FILE_ERROR_SECURITY));
49 return;
52 file_system_ = parser.file_system()->GetWeakPtr();
53 abort_callback_ = parser.file_system()->OpenFile(
54 parser.file_path(), OPEN_FILE_MODE_WRITE,
55 base::Bind(&OperationRunner::OnOpenFileCompletedOnUIThread, this,
56 callback));
59 // Closes a file. Ignores result, since outlives the caller. Must be called on
60 // UI thread.
61 void CloseFileOnUIThread() {
62 DCHECK_CURRENTLY_ON(BrowserThread::UI);
63 DCHECK(abort_callback_.is_null());
65 if (file_system_.get() && file_handle_ != -1) {
66 // Closing a file must not be aborted, since we could end up on files
67 // which are never closed.
68 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 scoped_refptr<net::IOBuffer> buffer,
76 int64 offset,
77 int length,
78 const storage::AsyncFileUtil::StatusCallback& callback) {
79 DCHECK_CURRENTLY_ON(BrowserThread::UI);
80 DCHECK(abort_callback_.is_null());
82 // If the file system got unmounted, then abort the writing operation.
83 if (!file_system_.get()) {
84 BrowserThread::PostTask(
85 BrowserThread::IO,
86 FROM_HERE,
87 base::Bind(callback, base::File::FILE_ERROR_ABORT));
88 return;
91 abort_callback_ = file_system_->WriteFile(
92 file_handle_,
93 buffer.get(),
94 offset,
95 length,
96 base::Bind(
97 &OperationRunner::OnWriteFileCompletedOnUIThread, this, callback));
100 // Aborts the most recent operation (if exists).
101 void AbortOnUIThread() {
102 DCHECK_CURRENTLY_ON(BrowserThread::UI);
103 if (abort_callback_.is_null())
104 return;
106 const AbortCallback last_abort_callback = abort_callback_;
107 abort_callback_ = AbortCallback();
108 last_abort_callback.Run();
111 private:
112 friend class base::RefCountedThreadSafe<OperationRunner>;
114 virtual ~OperationRunner() {}
116 // Remembers a file handle for further operations and forwards the result to
117 // the IO thread.
118 void OnOpenFileCompletedOnUIThread(
119 const storage::AsyncFileUtil::StatusCallback& callback,
120 int file_handle,
121 base::File::Error result) {
122 DCHECK_CURRENTLY_ON(BrowserThread::UI);
124 abort_callback_ = AbortCallback();
125 if (result == base::File::FILE_OK)
126 file_handle_ = file_handle;
128 BrowserThread::PostTask(
129 BrowserThread::IO, FROM_HERE, base::Bind(callback, result));
132 // Forwards a response of writing to a file to the IO thread.
133 void OnWriteFileCompletedOnUIThread(
134 const storage::AsyncFileUtil::StatusCallback& callback,
135 base::File::Error result) {
136 DCHECK_CURRENTLY_ON(BrowserThread::UI);
138 abort_callback_ = AbortCallback();
139 BrowserThread::PostTask(
140 BrowserThread::IO, FROM_HERE, base::Bind(callback, result));
143 AbortCallback abort_callback_;
144 base::WeakPtr<ProvidedFileSystemInterface> file_system_;
145 int file_handle_;
147 DISALLOW_COPY_AND_ASSIGN(OperationRunner);
150 FileStreamWriter::FileStreamWriter(const storage::FileSystemURL& url,
151 int64 initial_offset)
152 : url_(url),
153 current_offset_(initial_offset),
154 runner_(new OperationRunner),
155 state_(NOT_INITIALIZED),
156 weak_ptr_factory_(this) {
159 FileStreamWriter::~FileStreamWriter() {
160 BrowserThread::PostTask(
161 BrowserThread::UI,
162 FROM_HERE,
163 base::Bind(&OperationRunner::CloseFileOnUIThread, runner_));
166 void FileStreamWriter::Initialize(
167 const base::Closure& pending_closure,
168 const net::CompletionCallback& error_callback) {
169 DCHECK_CURRENTLY_ON(BrowserThread::IO);
170 DCHECK_EQ(NOT_INITIALIZED, state_);
171 state_ = INITIALIZING;
173 BrowserThread::PostTask(
174 BrowserThread::UI,
175 FROM_HERE,
176 base::Bind(&OperationRunner::OpenFileOnUIThread,
177 runner_,
178 url_,
179 base::Bind(&FileStreamWriter::OnOpenFileCompleted,
180 weak_ptr_factory_.GetWeakPtr(),
181 pending_closure,
182 error_callback)));
185 void FileStreamWriter::OnOpenFileCompleted(
186 const base::Closure& pending_closure,
187 const net::CompletionCallback& error_callback,
188 base::File::Error result) {
189 DCHECK_CURRENTLY_ON(BrowserThread::IO);
190 DCHECK_EQ(INITIALIZING, state_);
192 // In case of an error, return immediately using the |error_callback| of the
193 // Write() pending request.
194 if (result != base::File::FILE_OK) {
195 state_ = FAILED;
196 error_callback.Run(net::FileErrorToNetError(result));
197 return;
200 DCHECK_EQ(base::File::FILE_OK, result);
201 state_ = INITIALIZED;
203 // Run the task waiting for the initialization to be completed.
204 pending_closure.Run();
207 int FileStreamWriter::Write(net::IOBuffer* buffer,
208 int buffer_length,
209 const net::CompletionCallback& callback) {
210 DCHECK_CURRENTLY_ON(BrowserThread::IO);
211 TRACE_EVENT_ASYNC_BEGIN1("file_system_provider",
212 "FileStreamWriter::Write",
213 this,
214 "buffer_length",
215 buffer_length);
217 switch (state_) {
218 case NOT_INITIALIZED:
219 // Lazily initialize with the first call to Write().
220 Initialize(base::Bind(&FileStreamWriter::WriteAfterInitialized,
221 weak_ptr_factory_.GetWeakPtr(),
222 make_scoped_refptr(buffer),
223 buffer_length,
224 base::Bind(&FileStreamWriter::OnWriteCompleted,
225 weak_ptr_factory_.GetWeakPtr(),
226 callback)),
227 base::Bind(&FileStreamWriter::OnWriteCompleted,
228 weak_ptr_factory_.GetWeakPtr(),
229 callback));
230 break;
232 case INITIALIZING:
233 NOTREACHED();
234 break;
236 case INITIALIZED:
237 WriteAfterInitialized(buffer,
238 buffer_length,
239 base::Bind(&FileStreamWriter::OnWriteCompleted,
240 weak_ptr_factory_.GetWeakPtr(),
241 callback));
242 break;
244 case EXECUTING:
245 case FAILED:
246 NOTREACHED();
247 break;
250 return net::ERR_IO_PENDING;
253 int FileStreamWriter::Cancel(const net::CompletionCallback& callback) {
254 DCHECK_CURRENTLY_ON(BrowserThread::IO);
256 if (state_ != INITIALIZING && state_ != EXECUTING)
257 return net::ERR_UNEXPECTED;
259 // Abort and Optimistically return an OK result code, as the aborting
260 // operation is always forced and can't be cancelled.
261 BrowserThread::PostTask(
262 BrowserThread::UI, FROM_HERE,
263 base::Bind(&OperationRunner::AbortOnUIThread, runner_));
264 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
265 base::Bind(callback, net::OK));
267 return net::ERR_IO_PENDING;
270 int FileStreamWriter::Flush(const net::CompletionCallback& callback) {
271 DCHECK_CURRENTLY_ON(BrowserThread::IO);
272 base::ThreadTaskRunnerHandle::Get()->PostTask(
273 FROM_HERE,
274 base::Bind(callback, state_ == INITIALIZED ? net::OK : net::ERR_FAILED));
276 return net::ERR_IO_PENDING;
279 void FileStreamWriter::OnWriteFileCompleted(
280 int buffer_length,
281 const net::CompletionCallback& callback,
282 base::File::Error result) {
283 DCHECK_CURRENTLY_ON(BrowserThread::IO);
284 DCHECK_EQ(EXECUTING, state_);
285 state_ = INITIALIZED;
287 if (result != base::File::FILE_OK) {
288 state_ = FAILED;
289 callback.Run(net::FileErrorToNetError(result));
290 return;
293 current_offset_ += buffer_length;
294 callback.Run(buffer_length);
297 void FileStreamWriter::OnWriteCompleted(net::CompletionCallback callback,
298 int result) {
299 DCHECK_CURRENTLY_ON(BrowserThread::IO);
300 callback.Run(result);
301 TRACE_EVENT_ASYNC_END0(
302 "file_system_provider", "FileStreamWriter::Write", this);
305 void FileStreamWriter::WriteAfterInitialized(
306 scoped_refptr<net::IOBuffer> buffer,
307 int buffer_length,
308 const net::CompletionCallback& callback) {
309 DCHECK_CURRENTLY_ON(BrowserThread::IO);
310 DCHECK_EQ(INITIALIZED, state_);
311 state_ = EXECUTING;
313 BrowserThread::PostTask(
314 BrowserThread::UI,
315 FROM_HERE,
316 base::Bind(&OperationRunner::WriteFileOnUIThread,
317 runner_,
318 buffer,
319 current_offset_,
320 buffer_length,
321 base::Bind(&FileStreamWriter::OnWriteFileCompleted,
322 weak_ptr_factory_.GetWeakPtr(),
323 buffer_length,
324 callback)));
327 } // namespace file_system_provider
328 } // namespace chromeos