Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / file_system_provider / fileapi / file_stream_writer.cc
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.
4
5 #include "chrome/browser/chromeos/file_system_provider/fileapi/file_stream_writer.h"
6
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"
16
17 using content::BrowserThread;
18
19 namespace chromeos {
20 namespace file_system_provider {
21 namespace {
22
23 // Dicards the callback from CloseFile().
24 void EmptyStatusCallback(base::File::Error /* result */) {
25 }
26
27 }  // namespace
28
29 class FileStreamWriter::OperationRunner
30     : public base::RefCountedThreadSafe<FileStreamWriter::OperationRunner> {
31  public:
32   OperationRunner() : file_handle_(-1) {}
33
34   // Opens a file for writing and calls the completion callback. Must be called
35   // on UI thread.
36   void OpenFileOnUIThread(
37       const storage::FileSystemURL& url,
38       const storage::AsyncFileUtil::StatusCallback& callback) {
39     DCHECK_CURRENTLY_ON(BrowserThread::UI);
40
41     util::FileSystemURLParser parser(url);
42     if (!parser.Parse()) {
43       BrowserThread::PostTask(
44           BrowserThread::IO,
45           FROM_HERE,
46           base::Bind(callback, base::File::FILE_ERROR_SECURITY));
47       return;
48     }
49
50     file_system_ = parser.file_system()->GetWeakPtr();
51     abort_callback_ = parser.file_system()->OpenFile(
52         parser.file_path(),
53         ProvidedFileSystemInterface::OPEN_FILE_MODE_WRITE,
54         base::Bind(
55             &OperationRunner::OnOpenFileCompletedOnUIThread, this, callback));
56   }
57
58   // Closes a file. Ignores result, since outlives the caller. Must be called on
59   // UI thread.
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));
66     }
67   }
68
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,
73       int64 offset,
74       int length,
75       const storage::AsyncFileUtil::StatusCallback& callback) {
76     DCHECK_CURRENTLY_ON(BrowserThread::UI);
77
78     // If the file system got unmounted, then abort the writing operation.
79     if (!file_system_.get()) {
80       BrowserThread::PostTask(
81           BrowserThread::IO,
82           FROM_HERE,
83           base::Bind(callback, base::File::FILE_ERROR_ABORT));
84       return;
85     }
86
87     abort_callback_ = file_system_->WriteFile(
88         file_handle_,
89         buffer.get(),
90         offset,
91         length,
92         base::Bind(
93             &OperationRunner::OnWriteFileCompletedOnUIThread, this, callback));
94   }
95
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);
99
100     if (abort_callback_.is_null()) {
101       // No operation to be cancelled. At most a callback call, which will be
102       // discarded.
103       BrowserThread::PostTask(BrowserThread::IO,
104                               FROM_HERE,
105                               base::Bind(callback, base::File::FILE_OK));
106       return;
107     }
108
109     const ProvidedFileSystemInterface::AbortCallback abort_callback =
110         abort_callback_;
111     abort_callback_ = ProvidedFileSystemInterface::AbortCallback();
112     abort_callback.Run(base::Bind(
113         &OperationRunner::OnAbortCompletedOnUIThread, this, callback));
114   }
115
116  private:
117   friend class base::RefCountedThreadSafe<OperationRunner>;
118
119   virtual ~OperationRunner() {}
120
121   // Remembers a file handle for further operations and forwards the result to
122   // the IO thread.
123   void OnOpenFileCompletedOnUIThread(
124       const storage::AsyncFileUtil::StatusCallback& callback,
125       int file_handle,
126       base::File::Error result) {
127     DCHECK_CURRENTLY_ON(BrowserThread::UI);
128
129     file_handle_ = file_handle;
130     BrowserThread::PostTask(
131         BrowserThread::IO, FROM_HERE, base::Bind(callback, result));
132   }
133
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));
141   }
142
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));
150   }
151
152   ProvidedFileSystemInterface::AbortCallback abort_callback_;
153   base::WeakPtr<ProvidedFileSystemInterface> file_system_;
154   int file_handle_;
155
156   DISALLOW_COPY_AND_ASSIGN(OperationRunner);
157 };
158
159 FileStreamWriter::FileStreamWriter(const storage::FileSystemURL& url,
160                                    int64 initial_offset)
161     : url_(url),
162       current_offset_(initial_offset),
163       runner_(new OperationRunner),
164       state_(NOT_INITIALIZED),
165       weak_ptr_factory_(this) {
166 }
167
168 FileStreamWriter::~FileStreamWriter() {
169   BrowserThread::PostTask(
170       BrowserThread::UI,
171       FROM_HERE,
172       base::Bind(&OperationRunner::CloseFileOnUIThread, runner_));
173 }
174
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;
181
182   BrowserThread::PostTask(
183       BrowserThread::UI,
184       FROM_HERE,
185       base::Bind(&OperationRunner::OpenFileOnUIThread,
186                  runner_,
187                  url_,
188                  base::Bind(&FileStreamWriter::OnOpenFileCompleted,
189                             weak_ptr_factory_.GetWeakPtr(),
190                             pending_closure,
191                             error_callback)));
192 }
193
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_);
200
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) {
204     state_ = FAILED;
205     error_callback.Run(net::FileErrorToNetError(result));
206     return;
207   }
208
209   DCHECK_EQ(base::File::FILE_OK, result);
210   state_ = INITIALIZED;
211
212   // Run the task waiting for the initialization to be completed.
213   pending_closure.Run();
214 }
215
216 int FileStreamWriter::Write(net::IOBuffer* buffer,
217                             int buffer_length,
218                             const net::CompletionCallback& callback) {
219   DCHECK_CURRENTLY_ON(BrowserThread::IO);
220   TRACE_EVENT_ASYNC_BEGIN1("file_system_provider",
221                            "FileStreamWriter::Write",
222                            this,
223                            "buffer_length",
224                            buffer_length);
225
226   switch (state_) {
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),
232                             buffer_length,
233                             base::Bind(&FileStreamWriter::OnWriteCompleted,
234                                        weak_ptr_factory_.GetWeakPtr(),
235                                        callback)),
236                  base::Bind(&FileStreamWriter::OnWriteCompleted,
237                             weak_ptr_factory_.GetWeakPtr(),
238                             callback));
239       break;
240
241     case INITIALIZING:
242       NOTREACHED();
243       break;
244
245     case INITIALIZED:
246       WriteAfterInitialized(buffer,
247                             buffer_length,
248                             base::Bind(&FileStreamWriter::OnWriteCompleted,
249                                        weak_ptr_factory_.GetWeakPtr(),
250                                        callback));
251       break;
252
253     case FAILED:
254       NOTREACHED();
255       break;
256   }
257
258   return net::ERR_IO_PENDING;
259 }
260
261 int FileStreamWriter::Cancel(const net::CompletionCallback& callback) {
262   DCHECK_CURRENTLY_ON(BrowserThread::IO);
263
264   BrowserThread::PostTask(
265       BrowserThread::UI,
266       FROM_HERE,
267       base::Bind(&OperationRunner::AbortOnUIThread,
268                  runner_,
269                  base::Bind(&FileStreamWriter::OnAbortCompleted,
270                             weak_ptr_factory_.GetWeakPtr(),
271                             callback)));
272   return net::ERR_IO_PENDING;
273 }
274
275 int FileStreamWriter::Flush(const net::CompletionCallback& callback) {
276   base::ThreadTaskRunnerHandle::Get()->PostTask(
277       FROM_HERE,
278       base::Bind(callback, state_ == INITIALIZED ? net::OK : net::ERR_FAILED));
279
280   return net::ERR_IO_PENDING;
281 }
282
283 void FileStreamWriter::OnWriteFileCompleted(
284     int buffer_length,
285     const net::CompletionCallback& callback,
286     base::File::Error result) {
287   DCHECK_CURRENTLY_ON(BrowserThread::IO);
288   DCHECK_EQ(INITIALIZED, state_);
289
290   if (result != base::File::FILE_OK) {
291     state_ = FAILED;
292     callback.Run(net::FileErrorToNetError(result));
293     return;
294   }
295
296   current_offset_ += buffer_length;
297   callback.Run(buffer_length);
298 }
299
300 void FileStreamWriter::OnWriteCompleted(net::CompletionCallback callback,
301                                         int result) {
302   DCHECK_CURRENTLY_ON(BrowserThread::IO);
303   callback.Run(result);
304   TRACE_EVENT_ASYNC_END0(
305       "file_system_provider", "FileStreamWriter::Write", this);
306 }
307
308 void FileStreamWriter::OnAbortCompleted(const net::CompletionCallback& callback,
309                                         base::File::Error result) {
310   DCHECK_CURRENTLY_ON(BrowserThread::IO);
311
312   if (result != base::File::FILE_OK)
313     state_ = FAILED;
314
315   callback.Run(net::FileErrorToNetError(result));
316 }
317
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_EQ(INITIALIZED, state_);
324
325   BrowserThread::PostTask(
326       BrowserThread::UI,
327       FROM_HERE,
328       base::Bind(&OperationRunner::WriteFileOnUIThread,
329                  runner_,
330                  buffer,
331                  current_offset_,
332                  buffer_length,
333                  base::Bind(&FileStreamWriter::OnWriteFileCompleted,
334                             weak_ptr_factory_.GetWeakPtr(),
335                             buffer_length,
336                             callback)));
337 }
338
339 }  // namespace file_system_provider
340 }  // namespace chromeos