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/callback.h"
8 #include "base/message_loop/message_loop.h"
9 #include "net/base/file_stream.h"
10 #include "net/base/io_buffer.h"
11 #include "net/base/net_errors.h"
17 const int kOpenFlagsForWrite
= base::File::FLAG_OPEN
|
18 base::File::FLAG_WRITE
|
19 base::File::FLAG_ASYNC
;
20 const int kCreateFlagsForWrite
= base::File::FLAG_CREATE
|
21 base::File::FLAG_WRITE
|
22 base::File::FLAG_ASYNC
;
26 FileStreamWriter
* FileStreamWriter::CreateForLocalFile(
27 base::TaskRunner
* task_runner
,
28 const base::FilePath
& file_path
,
30 OpenOrCreate open_or_create
) {
31 return new LocalFileStreamWriter(
32 task_runner
, file_path
, initial_offset
, open_or_create
);
35 LocalFileStreamWriter::~LocalFileStreamWriter() {
36 // Invalidate weak pointers so that we won't receive any callbacks from
37 // in-flight stream operations, which might be triggered during the file close
38 // in the FileStream destructor.
39 weak_factory_
.InvalidateWeakPtrs();
41 // FileStream's destructor closes the file safely, since we opened the file
42 // by its Open() method.
45 int LocalFileStreamWriter::Write(net::IOBuffer
* buf
, int buf_len
,
46 const net::CompletionCallback
& callback
) {
47 DCHECK(!has_pending_operation_
);
48 DCHECK(cancel_callback_
.is_null());
50 has_pending_operation_
= true;
52 int result
= InitiateWrite(buf
, buf_len
, callback
);
53 if (result
!= net::ERR_IO_PENDING
)
54 has_pending_operation_
= false;
57 return InitiateOpen(callback
,
58 base::Bind(&LocalFileStreamWriter::ReadyToWrite
,
59 weak_factory_
.GetWeakPtr(),
60 make_scoped_refptr(buf
), buf_len
, callback
));
63 int LocalFileStreamWriter::Cancel(const net::CompletionCallback
& callback
) {
64 if (!has_pending_operation_
)
65 return net::ERR_UNEXPECTED
;
67 DCHECK(!callback
.is_null());
68 cancel_callback_
= callback
;
69 return net::ERR_IO_PENDING
;
72 int LocalFileStreamWriter::Flush(const net::CompletionCallback
& callback
) {
73 DCHECK(!has_pending_operation_
);
74 DCHECK(cancel_callback_
.is_null());
76 // Write() is not called yet, so there's nothing to flush.
80 has_pending_operation_
= true;
81 int result
= InitiateFlush(callback
);
82 if (result
!= net::ERR_IO_PENDING
)
83 has_pending_operation_
= false;
87 LocalFileStreamWriter::LocalFileStreamWriter(base::TaskRunner
* task_runner
,
88 const base::FilePath
& file_path
,
90 OpenOrCreate open_or_create
)
91 : file_path_(file_path
),
92 open_or_create_(open_or_create
),
93 initial_offset_(initial_offset
),
94 task_runner_(task_runner
),
95 has_pending_operation_(false),
96 weak_factory_(this) {}
98 int LocalFileStreamWriter::InitiateOpen(
99 const net::CompletionCallback
& error_callback
,
100 const base::Closure
& main_operation
) {
101 DCHECK(has_pending_operation_
);
102 DCHECK(!stream_impl_
.get());
104 stream_impl_
.reset(new net::FileStream(task_runner_
));
107 switch (open_or_create_
) {
108 case OPEN_EXISTING_FILE
:
109 open_flags
= kOpenFlagsForWrite
;
111 case CREATE_NEW_FILE
:
112 open_flags
= kCreateFlagsForWrite
;
116 return stream_impl_
->Open(file_path_
,
118 base::Bind(&LocalFileStreamWriter::DidOpen
,
119 weak_factory_
.GetWeakPtr(),
124 void LocalFileStreamWriter::DidOpen(
125 const net::CompletionCallback
& error_callback
,
126 const base::Closure
& main_operation
,
128 DCHECK(has_pending_operation_
);
129 DCHECK(stream_impl_
.get());
131 if (CancelIfRequested())
134 if (result
!= net::OK
) {
135 has_pending_operation_
= false;
136 stream_impl_
.reset(NULL
);
137 error_callback
.Run(result
);
141 InitiateSeek(error_callback
, main_operation
);
144 void LocalFileStreamWriter::InitiateSeek(
145 const net::CompletionCallback
& error_callback
,
146 const base::Closure
& main_operation
) {
147 DCHECK(has_pending_operation_
);
148 DCHECK(stream_impl_
.get());
150 if (initial_offset_
== 0) {
152 main_operation
.Run();
156 int result
= stream_impl_
->Seek(base::File::FROM_BEGIN
, initial_offset_
,
157 base::Bind(&LocalFileStreamWriter::DidSeek
,
158 weak_factory_
.GetWeakPtr(),
161 if (result
!= net::ERR_IO_PENDING
) {
162 has_pending_operation_
= false;
163 error_callback
.Run(result
);
167 void LocalFileStreamWriter::DidSeek(
168 const net::CompletionCallback
& error_callback
,
169 const base::Closure
& main_operation
,
171 DCHECK(has_pending_operation_
);
173 if (CancelIfRequested())
176 if (result
!= initial_offset_
) {
177 // TODO(kinaba) add a more specific error code.
178 result
= net::ERR_FAILED
;
182 has_pending_operation_
= false;
183 error_callback
.Run(static_cast<int>(result
));
187 main_operation
.Run();
190 void LocalFileStreamWriter::ReadyToWrite(
191 net::IOBuffer
* buf
, int buf_len
,
192 const net::CompletionCallback
& callback
) {
193 DCHECK(has_pending_operation_
);
195 int result
= InitiateWrite(buf
, buf_len
, callback
);
196 if (result
!= net::ERR_IO_PENDING
) {
197 has_pending_operation_
= false;
198 callback
.Run(result
);
202 int LocalFileStreamWriter::InitiateWrite(
203 net::IOBuffer
* buf
, int buf_len
,
204 const net::CompletionCallback
& callback
) {
205 DCHECK(has_pending_operation_
);
206 DCHECK(stream_impl_
.get());
208 return stream_impl_
->Write(buf
, buf_len
,
209 base::Bind(&LocalFileStreamWriter::DidWrite
,
210 weak_factory_
.GetWeakPtr(),
214 void LocalFileStreamWriter::DidWrite(const net::CompletionCallback
& callback
,
216 DCHECK(has_pending_operation_
);
218 if (CancelIfRequested())
220 has_pending_operation_
= false;
221 callback
.Run(result
);
224 int LocalFileStreamWriter::InitiateFlush(
225 const net::CompletionCallback
& callback
) {
226 DCHECK(has_pending_operation_
);
227 DCHECK(stream_impl_
.get());
229 return stream_impl_
->Flush(base::Bind(&LocalFileStreamWriter::DidFlush
,
230 weak_factory_
.GetWeakPtr(),
234 void LocalFileStreamWriter::DidFlush(const net::CompletionCallback
& callback
,
236 DCHECK(has_pending_operation_
);
238 if (CancelIfRequested())
240 has_pending_operation_
= false;
241 callback
.Run(result
);
244 bool LocalFileStreamWriter::CancelIfRequested() {
245 DCHECK(has_pending_operation_
);
247 if (cancel_callback_
.is_null())
250 net::CompletionCallback pending_cancel
= cancel_callback_
;
251 has_pending_operation_
= false;
252 cancel_callback_
.Reset();
253 pending_cancel
.Run(net::OK
);
257 } // namespace storage