Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / storage / browser / fileapi / local_file_stream_writer.cc
1 // Copyright (c) 2012 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 "storage/browser/fileapi/local_file_stream_writer.h"
6
7 #include "base/callback.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/profiler/scoped_tracker.h"
10 #include "net/base/file_stream.h"
11 #include "net/base/io_buffer.h"
12 #include "net/base/net_errors.h"
13
14 namespace storage {
15
16 namespace {
17
18 const int kOpenFlagsForWrite = base::File::FLAG_OPEN |
19                                base::File::FLAG_WRITE |
20                                base::File::FLAG_ASYNC;
21 const int kCreateFlagsForWrite = base::File::FLAG_CREATE |
22                                  base::File::FLAG_WRITE |
23                                  base::File::FLAG_ASYNC;
24
25 }  // namespace
26
27 FileStreamWriter* FileStreamWriter::CreateForLocalFile(
28     base::TaskRunner* task_runner,
29     const base::FilePath& file_path,
30     int64 initial_offset,
31     OpenOrCreate open_or_create) {
32   return new LocalFileStreamWriter(
33       task_runner, file_path, initial_offset, open_or_create);
34 }
35
36 LocalFileStreamWriter::~LocalFileStreamWriter() {
37   // Invalidate weak pointers so that we won't receive any callbacks from
38   // in-flight stream operations, which might be triggered during the file close
39   // in the FileStream destructor.
40   weak_factory_.InvalidateWeakPtrs();
41
42   // FileStream's destructor closes the file safely, since we opened the file
43   // by its Open() method.
44 }
45
46 int LocalFileStreamWriter::Write(net::IOBuffer* buf, int buf_len,
47                                  const net::CompletionCallback& callback) {
48   DCHECK(!has_pending_operation_);
49   DCHECK(cancel_callback_.is_null());
50
51   has_pending_operation_ = true;
52   if (stream_impl_) {
53     int result = InitiateWrite(buf, buf_len, callback);
54     if (result != net::ERR_IO_PENDING)
55       has_pending_operation_ = false;
56     return result;
57   }
58   return InitiateOpen(callback,
59                       base::Bind(&LocalFileStreamWriter::ReadyToWrite,
60                                  weak_factory_.GetWeakPtr(),
61                                  make_scoped_refptr(buf), buf_len, callback));
62 }
63
64 int LocalFileStreamWriter::Cancel(const net::CompletionCallback& callback) {
65   if (!has_pending_operation_)
66     return net::ERR_UNEXPECTED;
67
68   DCHECK(!callback.is_null());
69   cancel_callback_ = callback;
70   return net::ERR_IO_PENDING;
71 }
72
73 int LocalFileStreamWriter::Flush(const net::CompletionCallback& callback) {
74   DCHECK(!has_pending_operation_);
75   DCHECK(cancel_callback_.is_null());
76
77   // Write() is not called yet, so there's nothing to flush.
78   if (!stream_impl_)
79     return net::OK;
80
81   has_pending_operation_ = true;
82   int result = InitiateFlush(callback);
83   if (result != net::ERR_IO_PENDING)
84     has_pending_operation_ = false;
85   return result;
86 }
87
88 LocalFileStreamWriter::LocalFileStreamWriter(base::TaskRunner* task_runner,
89                                              const base::FilePath& file_path,
90                                              int64 initial_offset,
91                                              OpenOrCreate open_or_create)
92     : file_path_(file_path),
93       open_or_create_(open_or_create),
94       initial_offset_(initial_offset),
95       task_runner_(task_runner),
96       has_pending_operation_(false),
97       weak_factory_(this) {}
98
99 int LocalFileStreamWriter::InitiateOpen(
100     const net::CompletionCallback& error_callback,
101     const base::Closure& main_operation) {
102   DCHECK(has_pending_operation_);
103   DCHECK(!stream_impl_.get());
104
105   stream_impl_.reset(new net::FileStream(task_runner_));
106
107   int open_flags = 0;
108   switch (open_or_create_) {
109   case OPEN_EXISTING_FILE:
110     open_flags = kOpenFlagsForWrite;
111     break;
112   case CREATE_NEW_FILE:
113     open_flags = kCreateFlagsForWrite;
114     break;
115   }
116
117   return stream_impl_->Open(file_path_,
118                             open_flags,
119                             base::Bind(&LocalFileStreamWriter::DidOpen,
120                                        weak_factory_.GetWeakPtr(),
121                                        error_callback,
122                                        main_operation));
123 }
124
125 void LocalFileStreamWriter::DidOpen(
126     const net::CompletionCallback& error_callback,
127     const base::Closure& main_operation,
128     int result) {
129   // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
130   tracked_objects::ScopedTracker tracking_profile(
131       FROM_HERE_WITH_EXPLICIT_FUNCTION(
132           "423948 LocalFileStreamWriter::DidOpen"));
133
134   DCHECK(has_pending_operation_);
135   DCHECK(stream_impl_.get());
136
137   if (CancelIfRequested())
138     return;
139
140   if (result != net::OK) {
141     has_pending_operation_ = false;
142     stream_impl_.reset(NULL);
143     error_callback.Run(result);
144     return;
145   }
146
147   InitiateSeek(error_callback, main_operation);
148 }
149
150 void LocalFileStreamWriter::InitiateSeek(
151     const net::CompletionCallback& error_callback,
152     const base::Closure& main_operation) {
153   DCHECK(has_pending_operation_);
154   DCHECK(stream_impl_.get());
155
156   if (initial_offset_ == 0) {
157     // No need to seek.
158     main_operation.Run();
159     return;
160   }
161
162   int result = stream_impl_->Seek(base::File::FROM_BEGIN, initial_offset_,
163                                   base::Bind(&LocalFileStreamWriter::DidSeek,
164                                              weak_factory_.GetWeakPtr(),
165                                              error_callback,
166                                              main_operation));
167   if (result != net::ERR_IO_PENDING) {
168     has_pending_operation_ = false;
169     error_callback.Run(result);
170   }
171 }
172
173 void LocalFileStreamWriter::DidSeek(
174     const net::CompletionCallback& error_callback,
175     const base::Closure& main_operation,
176     int64 result) {
177   DCHECK(has_pending_operation_);
178
179   if (CancelIfRequested())
180     return;
181
182   if (result != initial_offset_) {
183     // TODO(kinaba) add a more specific error code.
184     result = net::ERR_FAILED;
185   }
186
187   if (result < 0) {
188     has_pending_operation_ = false;
189     error_callback.Run(static_cast<int>(result));
190     return;
191   }
192
193   main_operation.Run();
194 }
195
196 void LocalFileStreamWriter::ReadyToWrite(
197     net::IOBuffer* buf, int buf_len,
198     const net::CompletionCallback& callback) {
199   DCHECK(has_pending_operation_);
200
201   int result = InitiateWrite(buf, buf_len, callback);
202   if (result != net::ERR_IO_PENDING) {
203     has_pending_operation_ = false;
204     callback.Run(result);
205   }
206 }
207
208 int LocalFileStreamWriter::InitiateWrite(
209     net::IOBuffer* buf, int buf_len,
210     const net::CompletionCallback& callback) {
211   DCHECK(has_pending_operation_);
212   DCHECK(stream_impl_.get());
213
214   return stream_impl_->Write(buf, buf_len,
215                              base::Bind(&LocalFileStreamWriter::DidWrite,
216                                         weak_factory_.GetWeakPtr(),
217                                         callback));
218 }
219
220 void LocalFileStreamWriter::DidWrite(const net::CompletionCallback& callback,
221                                      int result) {
222   DCHECK(has_pending_operation_);
223
224   if (CancelIfRequested())
225     return;
226   has_pending_operation_ = false;
227   callback.Run(result);
228 }
229
230 int LocalFileStreamWriter::InitiateFlush(
231     const net::CompletionCallback& callback) {
232   DCHECK(has_pending_operation_);
233   DCHECK(stream_impl_.get());
234
235   return stream_impl_->Flush(base::Bind(&LocalFileStreamWriter::DidFlush,
236                                         weak_factory_.GetWeakPtr(),
237                                         callback));
238 }
239
240 void LocalFileStreamWriter::DidFlush(const net::CompletionCallback& callback,
241                                      int result) {
242   DCHECK(has_pending_operation_);
243
244   if (CancelIfRequested())
245     return;
246   has_pending_operation_ = false;
247   callback.Run(result);
248 }
249
250 bool LocalFileStreamWriter::CancelIfRequested() {
251   DCHECK(has_pending_operation_);
252
253   if (cancel_callback_.is_null())
254     return false;
255
256   net::CompletionCallback pending_cancel = cancel_callback_;
257   has_pending_operation_ = false;
258   cancel_callback_.Reset();
259   pending_cancel.Run(net::OK);
260   return true;
261 }
262
263 }  // namespace storage