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(base::File::FROM_BEGIN
, initial_offset_
,
156 base::Bind(&LocalFileStreamWriter::DidSeek
,
157 weak_factory_
.GetWeakPtr(),
160 if (result
!= net::ERR_IO_PENDING
) {
161 has_pending_operation_
= false;
162 error_callback
.Run(result
);
166 void LocalFileStreamWriter::DidSeek(
167 const net::CompletionCallback
& error_callback
,
168 const base::Closure
& main_operation
,
170 DCHECK(has_pending_operation_
);
172 if (CancelIfRequested())
175 if (result
!= initial_offset_
) {
176 // TODO(kinaba) add a more specific error code.
177 result
= net::ERR_FAILED
;
181 has_pending_operation_
= false;
182 error_callback
.Run(static_cast<int>(result
));
186 main_operation
.Run();
189 void LocalFileStreamWriter::ReadyToWrite(
190 net::IOBuffer
* buf
, int buf_len
,
191 const net::CompletionCallback
& callback
) {
192 DCHECK(has_pending_operation_
);
194 int result
= InitiateWrite(buf
, buf_len
, callback
);
195 if (result
!= net::ERR_IO_PENDING
) {
196 has_pending_operation_
= false;
197 callback
.Run(result
);
201 int LocalFileStreamWriter::InitiateWrite(
202 net::IOBuffer
* buf
, int buf_len
,
203 const net::CompletionCallback
& callback
) {
204 DCHECK(has_pending_operation_
);
205 DCHECK(stream_impl_
.get());
207 return stream_impl_
->Write(buf
, buf_len
,
208 base::Bind(&LocalFileStreamWriter::DidWrite
,
209 weak_factory_
.GetWeakPtr(),
213 void LocalFileStreamWriter::DidWrite(const net::CompletionCallback
& callback
,
215 DCHECK(has_pending_operation_
);
217 if (CancelIfRequested())
219 has_pending_operation_
= false;
220 callback
.Run(result
);
223 int LocalFileStreamWriter::InitiateFlush(
224 const net::CompletionCallback
& callback
) {
225 DCHECK(has_pending_operation_
);
226 DCHECK(stream_impl_
.get());
228 return stream_impl_
->Flush(base::Bind(&LocalFileStreamWriter::DidFlush
,
229 weak_factory_
.GetWeakPtr(),
233 void LocalFileStreamWriter::DidFlush(const net::CompletionCallback
& callback
,
235 DCHECK(has_pending_operation_
);
237 if (CancelIfRequested())
239 has_pending_operation_
= false;
240 callback
.Run(result
);
243 bool LocalFileStreamWriter::CancelIfRequested() {
244 DCHECK(has_pending_operation_
);
246 if (cancel_callback_
.is_null())
249 net::CompletionCallback pending_cancel
= cancel_callback_
;
250 has_pending_operation_
= false;
251 cancel_callback_
.Reset();
252 pending_cancel
.Run(net::OK
);
256 } // namespace storage