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.
5 #include "storage/browser/fileapi/local_file_stream_writer.h"
7 #include "base/message_loop/message_loop.h"
8 #include "net/base/file_stream.h"
9 #include "net/base/io_buffer.h"
10 #include "net/base/net_errors.h"
16 const int kOpenFlagsForWrite
= base::File::FLAG_OPEN
|
17 base::File::FLAG_WRITE
|
18 base::File::FLAG_ASYNC
;
19 const int kCreateFlagsForWrite
= base::File::FLAG_CREATE
|
20 base::File::FLAG_WRITE
|
21 base::File::FLAG_ASYNC
;
25 FileStreamWriter
* FileStreamWriter::CreateForLocalFile(
26 base::TaskRunner
* task_runner
,
27 const base::FilePath
& file_path
,
29 OpenOrCreate open_or_create
) {
30 return new LocalFileStreamWriter(
31 task_runner
, file_path
, initial_offset
, open_or_create
);
34 LocalFileStreamWriter::~LocalFileStreamWriter() {
35 // Invalidate weak pointers so that we won't receive any callbacks from
36 // in-flight stream operations, which might be triggered during the file close
37 // in the FileStream destructor.
38 weak_factory_
.InvalidateWeakPtrs();
40 // FileStream's destructor closes the file safely, since we opened the file
41 // by its Open() method.
44 int LocalFileStreamWriter::Write(net::IOBuffer
* buf
, int buf_len
,
45 const net::CompletionCallback
& callback
) {
46 DCHECK(!has_pending_operation_
);
47 DCHECK(cancel_callback_
.is_null());
49 has_pending_operation_
= true;
51 int result
= InitiateWrite(buf
, buf_len
, callback
);
52 if (result
!= net::ERR_IO_PENDING
)
53 has_pending_operation_
= false;
56 return InitiateOpen(callback
,
57 base::Bind(&LocalFileStreamWriter::ReadyToWrite
,
58 weak_factory_
.GetWeakPtr(),
59 make_scoped_refptr(buf
), buf_len
, callback
));
62 int LocalFileStreamWriter::Cancel(const net::CompletionCallback
& callback
) {
63 if (!has_pending_operation_
)
64 return net::ERR_UNEXPECTED
;
66 DCHECK(!callback
.is_null());
67 cancel_callback_
= callback
;
68 return net::ERR_IO_PENDING
;
71 int LocalFileStreamWriter::Flush(const net::CompletionCallback
& callback
) {
72 DCHECK(!has_pending_operation_
);
73 DCHECK(cancel_callback_
.is_null());
75 // Write() is not called yet, so there's nothing to flush.
79 has_pending_operation_
= true;
80 int result
= InitiateFlush(callback
);
81 if (result
!= net::ERR_IO_PENDING
)
82 has_pending_operation_
= false;
86 LocalFileStreamWriter::LocalFileStreamWriter(base::TaskRunner
* task_runner
,
87 const base::FilePath
& file_path
,
89 OpenOrCreate open_or_create
)
90 : file_path_(file_path
),
91 open_or_create_(open_or_create
),
92 initial_offset_(initial_offset
),
93 task_runner_(task_runner
),
94 has_pending_operation_(false),
95 weak_factory_(this) {}
97 int LocalFileStreamWriter::InitiateOpen(
98 const net::CompletionCallback
& error_callback
,
99 const base::Closure
& main_operation
) {
100 DCHECK(has_pending_operation_
);
101 DCHECK(!stream_impl_
.get());
103 stream_impl_
.reset(new net::FileStream(task_runner_
));
106 switch (open_or_create_
) {
107 case OPEN_EXISTING_FILE
:
108 open_flags
= kOpenFlagsForWrite
;
110 case CREATE_NEW_FILE
:
111 open_flags
= kCreateFlagsForWrite
;
115 return stream_impl_
->Open(file_path_
,
117 base::Bind(&LocalFileStreamWriter::DidOpen
,
118 weak_factory_
.GetWeakPtr(),
123 void LocalFileStreamWriter::DidOpen(
124 const net::CompletionCallback
& error_callback
,
125 const base::Closure
& main_operation
,
127 DCHECK(has_pending_operation_
);
128 DCHECK(stream_impl_
.get());
130 if (CancelIfRequested())
133 if (result
!= net::OK
) {
134 has_pending_operation_
= false;
135 stream_impl_
.reset(NULL
);
136 error_callback
.Run(result
);
140 InitiateSeek(error_callback
, main_operation
);
143 void LocalFileStreamWriter::InitiateSeek(
144 const net::CompletionCallback
& error_callback
,
145 const base::Closure
& main_operation
) {
146 DCHECK(has_pending_operation_
);
147 DCHECK(stream_impl_
.get());
149 if (initial_offset_
== 0) {
151 main_operation
.Run();
155 int result
= stream_impl_
->Seek(
157 base::Bind(&LocalFileStreamWriter::DidSeek
, weak_factory_
.GetWeakPtr(),
158 error_callback
, main_operation
));
159 if (result
!= net::ERR_IO_PENDING
) {
160 has_pending_operation_
= false;
161 error_callback
.Run(result
);
165 void LocalFileStreamWriter::DidSeek(
166 const net::CompletionCallback
& error_callback
,
167 const base::Closure
& main_operation
,
169 DCHECK(has_pending_operation_
);
171 if (CancelIfRequested())
174 if (result
!= initial_offset_
) {
175 // TODO(kinaba) add a more specific error code.
176 result
= net::ERR_FAILED
;
180 has_pending_operation_
= false;
181 error_callback
.Run(static_cast<int>(result
));
185 main_operation
.Run();
188 void LocalFileStreamWriter::ReadyToWrite(
189 net::IOBuffer
* buf
, int buf_len
,
190 const net::CompletionCallback
& callback
) {
191 DCHECK(has_pending_operation_
);
193 int result
= InitiateWrite(buf
, buf_len
, callback
);
194 if (result
!= net::ERR_IO_PENDING
) {
195 has_pending_operation_
= false;
196 callback
.Run(result
);
200 int LocalFileStreamWriter::InitiateWrite(
201 net::IOBuffer
* buf
, int buf_len
,
202 const net::CompletionCallback
& callback
) {
203 DCHECK(has_pending_operation_
);
204 DCHECK(stream_impl_
.get());
206 return stream_impl_
->Write(buf
, buf_len
,
207 base::Bind(&LocalFileStreamWriter::DidWrite
,
208 weak_factory_
.GetWeakPtr(),
212 void LocalFileStreamWriter::DidWrite(const net::CompletionCallback
& callback
,
214 DCHECK(has_pending_operation_
);
216 if (CancelIfRequested())
218 has_pending_operation_
= false;
219 callback
.Run(result
);
222 int LocalFileStreamWriter::InitiateFlush(
223 const net::CompletionCallback
& callback
) {
224 DCHECK(has_pending_operation_
);
225 DCHECK(stream_impl_
.get());
227 return stream_impl_
->Flush(base::Bind(&LocalFileStreamWriter::DidFlush
,
228 weak_factory_
.GetWeakPtr(),
232 void LocalFileStreamWriter::DidFlush(const net::CompletionCallback
& callback
,
234 DCHECK(has_pending_operation_
);
236 if (CancelIfRequested())
238 has_pending_operation_
= false;
239 callback
.Run(result
);
242 bool LocalFileStreamWriter::CancelIfRequested() {
243 DCHECK(has_pending_operation_
);
245 if (cancel_callback_
.is_null())
248 net::CompletionCallback pending_cancel
= cancel_callback_
;
249 has_pending_operation_
= false;
250 cancel_callback_
.Reset();
251 pending_cancel
.Run(net::OK
);
255 } // namespace storage