- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / drive / webkit_file_stream_writer_impl.cc
1 // Copyright 2013 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/drive/webkit_file_stream_writer_impl.h"
6
7 #include "base/bind.h"
8 #include "base/callback_helpers.h"
9 #include "chrome/browser/chromeos/drive/file_system_util.h"
10 #include "chrome/browser/chromeos/drive/fileapi_worker.h"
11 #include "chrome/browser/google_apis/task_util.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "net/base/io_buffer.h"
14 #include "net/base/net_errors.h"
15 #include "webkit/browser/fileapi/file_stream_writer.h"
16
17 using content::BrowserThread;
18
19 namespace drive {
20 namespace internal {
21 namespace {
22
23 // Creates a writable snapshot file of the |drive_path|.
24 void CreateWritableSnapshotFile(
25     const WebkitFileStreamWriterImpl::FileSystemGetter& file_system_getter,
26     const base::FilePath& drive_path,
27     const fileapi_internal::CreateWritableSnapshotFileCallback& callback) {
28   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
29
30   BrowserThread::PostTask(
31       BrowserThread::UI,
32       FROM_HERE,
33       base::Bind(
34           &fileapi_internal::RunFileSystemCallback,
35           file_system_getter,
36           base::Bind(&fileapi_internal::CreateWritableSnapshotFile,
37                      drive_path, google_apis::CreateRelayCallback(callback)),
38           google_apis::CreateRelayCallback(base::Bind(
39               callback, base::PLATFORM_FILE_ERROR_FAILED, base::FilePath(),
40               base::Closure()))));
41 }
42
43 }  // namespace
44
45 WebkitFileStreamWriterImpl::WebkitFileStreamWriterImpl(
46     const FileSystemGetter& file_system_getter,
47     base::TaskRunner* file_task_runner,
48     const base::FilePath& file_path,
49     int64 offset)
50     : file_system_getter_(file_system_getter),
51       file_task_runner_(file_task_runner),
52       file_path_(file_path),
53       offset_(offset),
54       weak_ptr_factory_(this) {
55 }
56
57 WebkitFileStreamWriterImpl::~WebkitFileStreamWriterImpl() {
58   if (local_file_writer_) {
59     // If the file is opened, close it at destructor.
60     // It is necessary to close the local file in advance.
61     local_file_writer_.reset();
62     DCHECK(!close_callback_on_ui_thread_.is_null());
63     BrowserThread::PostTask(BrowserThread::UI,
64                             FROM_HERE,
65                             close_callback_on_ui_thread_);
66   }
67 }
68
69 int WebkitFileStreamWriterImpl::Write(net::IOBuffer* buf,
70                                       int buf_len,
71                                       const net::CompletionCallback& callback) {
72   DCHECK(pending_write_callback_.is_null());
73   DCHECK(pending_cancel_callback_.is_null());
74   DCHECK(!callback.is_null());
75
76   // If the local file is already available, just delegate to it.
77   if (local_file_writer_)
78     return local_file_writer_->Write(buf, buf_len, callback);
79
80   // The local file is not yet ready. Create the writable snapshot.
81   if (file_path_.empty())
82     return net::ERR_FILE_NOT_FOUND;
83
84   pending_write_callback_ = callback;
85   CreateWritableSnapshotFile(
86       file_system_getter_, file_path_,
87       base::Bind(
88           &WebkitFileStreamWriterImpl::WriteAfterCreateWritableSnapshotFile,
89           weak_ptr_factory_.GetWeakPtr(), make_scoped_refptr(buf), buf_len));
90   return net::ERR_IO_PENDING;
91 }
92
93 int WebkitFileStreamWriterImpl::Cancel(
94     const net::CompletionCallback& callback) {
95   DCHECK(pending_cancel_callback_.is_null());
96   DCHECK(!callback.is_null());
97
98   // If LocalFileWriter is already created, just delegate the cancel to it.
99   if (local_file_writer_)
100     return local_file_writer_->Cancel(callback);
101
102   // If file open operation is in-flight, wait for its completion and cancel
103   // further write operation in WriteAfterCreateWritableSnapshotFile.
104   if (!pending_write_callback_.is_null()) {
105     // Dismiss pending write callback immediately.
106     pending_write_callback_.Reset();
107     pending_cancel_callback_ = callback;
108     return net::ERR_IO_PENDING;
109   }
110
111   // Write() is not called yet.
112   return net::ERR_UNEXPECTED;
113 }
114
115 int WebkitFileStreamWriterImpl::Flush(const net::CompletionCallback& callback) {
116   DCHECK(pending_cancel_callback_.is_null());
117   DCHECK(!callback.is_null());
118
119   // If LocalFileWriter is already created, just delegate to it.
120   if (local_file_writer_)
121     return local_file_writer_->Flush(callback);
122
123   // There shouldn't be in-flight Write operation.
124   DCHECK(pending_write_callback_.is_null());
125
126   // Here is the case Flush() is called before any Write() invocation.
127   // Do nothing.
128   // Synchronization to the remote server is not done until the file is closed.
129   return net::OK;
130 }
131
132 void WebkitFileStreamWriterImpl::WriteAfterCreateWritableSnapshotFile(
133     net::IOBuffer* buf,
134     int buf_len,
135     base::PlatformFileError open_result,
136     const base::FilePath& local_path,
137     const base::Closure& close_callback_on_ui_thread) {
138   DCHECK(!local_file_writer_);
139
140   if (!pending_cancel_callback_.is_null()) {
141     DCHECK(pending_write_callback_.is_null());
142     // Cancel() is called during the creation of the snapshot file.
143     // Don't write to the file.
144     if (open_result == base::PLATFORM_FILE_OK) {
145       // Here the file is internally created. To revert the operation, close
146       // the file.
147       DCHECK(!close_callback_on_ui_thread.is_null());
148       BrowserThread::PostTask(BrowserThread::UI,
149                               FROM_HERE,
150                               close_callback_on_ui_thread);
151     }
152
153     base::ResetAndReturn(&pending_cancel_callback_).Run(net::OK);
154     return;
155   }
156
157   DCHECK(!pending_write_callback_.is_null());
158
159   const net::CompletionCallback callback =
160       base::ResetAndReturn(&pending_write_callback_);
161   if (open_result != base::PLATFORM_FILE_OK) {
162     DCHECK(close_callback_on_ui_thread.is_null());
163     callback.Run(net::PlatformFileErrorToNetError(open_result));
164     return;
165   }
166
167   // Keep |close_callback| to close the file when the stream is destructed.
168   DCHECK(!close_callback_on_ui_thread.is_null());
169   close_callback_on_ui_thread_ = close_callback_on_ui_thread;
170   local_file_writer_.reset(fileapi::FileStreamWriter::CreateForLocalFile(
171       file_task_runner_.get(), local_path, offset_));
172   int result = local_file_writer_->Write(buf, buf_len, callback);
173   if (result != net::ERR_IO_PENDING)
174     callback.Run(result);
175 }
176
177 }  // namespace internal
178 }  // namespace drive