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 "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"
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
;
27 FileStreamWriter
* FileStreamWriter::CreateForLocalFile(
28 base::TaskRunner
* task_runner
,
29 const base::FilePath
& file_path
,
31 OpenOrCreate open_or_create
) {
32 return new LocalFileStreamWriter(
33 task_runner
, file_path
, initial_offset
, open_or_create
);
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();
42 // FileStream's destructor closes the file safely, since we opened the file
43 // by its Open() method.
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());
51 has_pending_operation_
= true;
53 int result
= InitiateWrite(buf
, buf_len
, callback
);
54 if (result
!= net::ERR_IO_PENDING
)
55 has_pending_operation_
= false;
58 return InitiateOpen(callback
,
59 base::Bind(&LocalFileStreamWriter::ReadyToWrite
,
60 weak_factory_
.GetWeakPtr(),
61 make_scoped_refptr(buf
), buf_len
, callback
));
64 int LocalFileStreamWriter::Cancel(const net::CompletionCallback
& callback
) {
65 if (!has_pending_operation_
)
66 return net::ERR_UNEXPECTED
;
68 DCHECK(!callback
.is_null());
69 cancel_callback_
= callback
;
70 return net::ERR_IO_PENDING
;
73 int LocalFileStreamWriter::Flush(const net::CompletionCallback
& callback
) {
74 DCHECK(!has_pending_operation_
);
75 DCHECK(cancel_callback_
.is_null());
77 // Write() is not called yet, so there's nothing to flush.
81 has_pending_operation_
= true;
82 int result
= InitiateFlush(callback
);
83 if (result
!= net::ERR_IO_PENDING
)
84 has_pending_operation_
= false;
88 LocalFileStreamWriter::LocalFileStreamWriter(base::TaskRunner
* task_runner
,
89 const base::FilePath
& file_path
,
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) {}
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());
105 stream_impl_
.reset(new net::FileStream(task_runner_
));
108 switch (open_or_create_
) {
109 case OPEN_EXISTING_FILE
:
110 open_flags
= kOpenFlagsForWrite
;
112 case CREATE_NEW_FILE
:
113 open_flags
= kCreateFlagsForWrite
;
117 return stream_impl_
->Open(file_path_
,
119 base::Bind(&LocalFileStreamWriter::DidOpen
,
120 weak_factory_
.GetWeakPtr(),
125 void LocalFileStreamWriter::DidOpen(
126 const net::CompletionCallback
& error_callback
,
127 const base::Closure
& main_operation
,
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"));
134 DCHECK(has_pending_operation_
);
135 DCHECK(stream_impl_
.get());
137 if (CancelIfRequested())
140 if (result
!= net::OK
) {
141 has_pending_operation_
= false;
142 stream_impl_
.reset(NULL
);
143 error_callback
.Run(result
);
147 InitiateSeek(error_callback
, main_operation
);
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());
156 if (initial_offset_
== 0) {
158 main_operation
.Run();
162 int result
= stream_impl_
->Seek(base::File::FROM_BEGIN
, initial_offset_
,
163 base::Bind(&LocalFileStreamWriter::DidSeek
,
164 weak_factory_
.GetWeakPtr(),
167 if (result
!= net::ERR_IO_PENDING
) {
168 has_pending_operation_
= false;
169 error_callback
.Run(result
);
173 void LocalFileStreamWriter::DidSeek(
174 const net::CompletionCallback
& error_callback
,
175 const base::Closure
& main_operation
,
177 DCHECK(has_pending_operation_
);
179 if (CancelIfRequested())
182 if (result
!= initial_offset_
) {
183 // TODO(kinaba) add a more specific error code.
184 result
= net::ERR_FAILED
;
188 has_pending_operation_
= false;
189 error_callback
.Run(static_cast<int>(result
));
193 main_operation
.Run();
196 void LocalFileStreamWriter::ReadyToWrite(
197 net::IOBuffer
* buf
, int buf_len
,
198 const net::CompletionCallback
& callback
) {
199 DCHECK(has_pending_operation_
);
201 int result
= InitiateWrite(buf
, buf_len
, callback
);
202 if (result
!= net::ERR_IO_PENDING
) {
203 has_pending_operation_
= false;
204 callback
.Run(result
);
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());
214 return stream_impl_
->Write(buf
, buf_len
,
215 base::Bind(&LocalFileStreamWriter::DidWrite
,
216 weak_factory_
.GetWeakPtr(),
220 void LocalFileStreamWriter::DidWrite(const net::CompletionCallback
& callback
,
222 DCHECK(has_pending_operation_
);
224 if (CancelIfRequested())
226 has_pending_operation_
= false;
227 callback
.Run(result
);
230 int LocalFileStreamWriter::InitiateFlush(
231 const net::CompletionCallback
& callback
) {
232 DCHECK(has_pending_operation_
);
233 DCHECK(stream_impl_
.get());
235 return stream_impl_
->Flush(base::Bind(&LocalFileStreamWriter::DidFlush
,
236 weak_factory_
.GetWeakPtr(),
240 void LocalFileStreamWriter::DidFlush(const net::CompletionCallback
& callback
,
242 DCHECK(has_pending_operation_
);
244 if (CancelIfRequested())
246 has_pending_operation_
= false;
247 callback
.Run(result
);
250 bool LocalFileStreamWriter::CancelIfRequested() {
251 DCHECK(has_pending_operation_
);
253 if (cancel_callback_
.is_null())
256 net::CompletionCallback pending_cancel
= cancel_callback_
;
257 has_pending_operation_
= false;
258 cancel_callback_
.Reset();
259 pending_cancel
.Run(net::OK
);
263 } // namespace storage