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