Upstream version 9.38.198.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 // Opens a file for writing and calls the completion callback. Must be called
27 // on UI thread.
28 void OpenFileOnUIThread(
29     const fileapi::FileSystemURL& url,
30     const FileStreamWriter::OpenFileCompletedCallback& callback) {
31   DCHECK_CURRENTLY_ON(BrowserThread::UI);
32
33   util::FileSystemURLParser parser(url);
34   if (!parser.Parse()) {
35     callback.Run(base::WeakPtr<ProvidedFileSystemInterface>(),
36                  base::FilePath(),
37                  0 /* file_handle */,
38                  base::File::FILE_ERROR_SECURITY);
39     return;
40   }
41
42   parser.file_system()->OpenFile(
43       parser.file_path(),
44       ProvidedFileSystemInterface::OPEN_FILE_MODE_WRITE,
45       base::Bind(
46           callback, parser.file_system()->GetWeakPtr(), parser.file_path()));
47 }
48
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,
54     int file_handle,
55     base::File::Error result) {
56   DCHECK_CURRENTLY_ON(BrowserThread::UI);
57   BrowserThread::PostTask(
58       BrowserThread::IO,
59       FROM_HERE,
60       base::Bind(callback, file_system, file_path, file_handle, result));
61 }
62
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,
66                          int file_handle) {
67   DCHECK_CURRENTLY_ON(BrowserThread::UI);
68   if (file_system.get())
69     file_system->CloseFile(file_handle, base::Bind(&EmptyStatusCallback));
70 }
71
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,
76     int file_handle,
77     scoped_refptr<net::IOBuffer> buffer,
78     int64 offset,
79     int length,
80     const fileapi::AsyncFileUtil::StatusCallback& callback) {
81   DCHECK_CURRENTLY_ON(BrowserThread::UI);
82
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);
86     return;
87   }
88
89   file_system->WriteFile(file_handle, buffer, offset, length, callback);
90 }
91
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));
99 }
100
101 }  // namespace
102
103 FileStreamWriter::FileStreamWriter(const fileapi::FileSystemURL& url,
104                                    int64 initial_offset)
105     : url_(url),
106       current_offset_(initial_offset),
107       state_(NOT_INITIALIZED),
108       file_handle_(0),
109       weak_ptr_factory_(this) {
110 }
111
112 FileStreamWriter::~FileStreamWriter() {
113   BrowserThread::PostTask(
114       BrowserThread::UI,
115       FROM_HERE,
116       base::Bind(&CloseFileOnUIThread, file_system_, file_handle_));
117 }
118
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;
124
125   BrowserThread::PostTask(
126       BrowserThread::UI,
127       FROM_HERE,
128       base::Bind(&OpenFileOnUIThread,
129                  url_,
130                  base::Bind(&OnOpenFileCompletedOnUIThread,
131                             base::Bind(&FileStreamWriter::OnOpenFileCompleted,
132                                        weak_ptr_factory_.GetWeakPtr(),
133                                        pending_closure,
134                                        error_callback))));
135 }
136
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,
142     int file_handle,
143     base::File::Error result) {
144   DCHECK_CURRENTLY_ON(BrowserThread::IO);
145   DCHECK_EQ(INITIALIZING, state_);
146
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) {
150     state_ = FAILED;
151     error_callback.Run(net::FileErrorToNetError(result));
152     return;
153   }
154
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;
161
162   // Run the task waiting for the initialization to be completed.
163   pending_closure.Run();
164 }
165
166 int FileStreamWriter::Write(net::IOBuffer* buffer,
167                             int buffer_length,
168                             const net::CompletionCallback& callback) {
169   DCHECK_CURRENTLY_ON(BrowserThread::IO);
170   TRACE_EVENT_ASYNC_BEGIN1("file_system_provider",
171                            "FileStreamWriter::Write",
172                            this,
173                            "buffer_length",
174                            buffer_length);
175
176   switch (state_) {
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),
182                             buffer_length,
183                             base::Bind(&FileStreamWriter::OnWriteCompleted,
184                                        weak_ptr_factory_.GetWeakPtr(),
185                                        callback)),
186                  base::Bind(&FileStreamWriter::OnWriteCompleted,
187                             weak_ptr_factory_.GetWeakPtr(),
188                             callback));
189       break;
190
191     case INITIALIZING:
192       NOTREACHED();
193       break;
194
195     case INITIALIZED:
196       WriteAfterInitialized(buffer,
197                             buffer_length,
198                             base::Bind(&FileStreamWriter::OnWriteCompleted,
199                                        weak_ptr_factory_.GetWeakPtr(),
200                                        callback));
201       break;
202
203     case FAILED:
204       NOTREACHED();
205       break;
206   }
207
208   return net::ERR_IO_PENDING;
209 }
210
211 int FileStreamWriter::Cancel(const net::CompletionCallback& callback) {
212   NOTIMPLEMENTED();
213   return net::ERR_FAILED;
214 }
215
216 int FileStreamWriter::Flush(const net::CompletionCallback& callback) {
217   if (state_ != INITIALIZED)
218     return net::ERR_FAILED;
219
220   return net::OK;
221 }
222
223 void FileStreamWriter::OnWriteFileCompleted(
224     int buffer_length,
225     const net::CompletionCallback& callback,
226     base::File::Error result) {
227   DCHECK_CURRENTLY_ON(BrowserThread::IO);
228   DCHECK_EQ(INITIALIZED, state_);
229
230   if (result != base::File::FILE_OK) {
231     state_ = FAILED;
232     callback.Run(net::FileErrorToNetError(result));
233     return;
234   }
235
236   current_offset_ += buffer_length;
237   callback.Run(buffer_length);
238 }
239
240 void FileStreamWriter::OnWriteCompleted(net::CompletionCallback callback,
241                                         int result) {
242   DCHECK_CURRENTLY_ON(BrowserThread::IO);
243   callback.Run(result);
244   TRACE_EVENT_ASYNC_END0(
245       "file_system_provider", "FileStreamWriter::Write", this);
246 }
247
248 void FileStreamWriter::WriteAfterInitialized(
249     scoped_refptr<net::IOBuffer> buffer,
250     int buffer_length,
251     const net::CompletionCallback& callback) {
252   DCHECK_CURRENTLY_ON(BrowserThread::IO);
253   DCHECK_EQ(INITIALIZED, state_);
254
255   BrowserThread::PostTask(
256       BrowserThread::UI,
257       FROM_HERE,
258       base::Bind(&WriteFileOnUIThread,
259                  file_system_,
260                  file_handle_,
261                  buffer,
262                  current_offset_,
263                  buffer_length,
264                  base::Bind(&OnWriteFileCompletedOnUIThread,
265                             base::Bind(&FileStreamWriter::OnWriteFileCompleted,
266                                        weak_ptr_factory_.GetWeakPtr(),
267                                        buffer_length,
268                                        callback))));
269 }
270
271 }  // namespace file_system_provider
272 }  // namespace chromeos