1 // Copyright 2014 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 "chrome/browser/chromeos/file_system_provider/fileapi/buffering_file_stream_writer.h"
9 #include "net/base/io_buffer.h"
10 #include "net/base/net_errors.h"
13 namespace file_system_provider
{
15 BufferingFileStreamWriter::BufferingFileStreamWriter(
16 scoped_ptr
<storage::FileStreamWriter
> file_stream_writer
,
17 int intermediate_buffer_length
)
18 : file_stream_writer_(file_stream_writer
.Pass()),
19 intermediate_buffer_length_(intermediate_buffer_length
),
20 intermediate_buffer_(new net::IOBuffer(intermediate_buffer_length_
)),
22 weak_ptr_factory_(this) {
25 BufferingFileStreamWriter::~BufferingFileStreamWriter() {
27 LOG(ERROR
) << "File stream writer not flushed. Data will be lost.";
30 int BufferingFileStreamWriter::Write(net::IOBuffer
* buffer
,
32 const net::CompletionCallback
& callback
) {
33 // If |buffer_length| is larger than the intermediate buffer, then call the
34 // inner file stream writer directly. Note, that the intermediate buffer
35 // (used for buffering) must be flushed first.
36 if (buffer_length
> intermediate_buffer_length_
) {
37 if (buffered_bytes_
) {
38 FlushIntermediateBuffer(
39 base::Bind(&BufferingFileStreamWriter::
40 OnFlushIntermediateBufferForDirectWriteCompleted
,
41 weak_ptr_factory_
.GetWeakPtr(),
42 make_scoped_refptr(buffer
),
46 // Nothing to flush, so skip it.
47 OnFlushIntermediateBufferForDirectWriteCompleted(
48 make_scoped_refptr(buffer
), buffer_length
, callback
, net::OK
);
50 return net::ERR_IO_PENDING
;
53 // Buffer consecutive writes to larger chunks.
54 const int buffer_bytes
=
55 std::min(intermediate_buffer_length_
- buffered_bytes_
, buffer_length
);
57 CopyToIntermediateBuffer(
58 make_scoped_refptr(buffer
), 0 /* buffer_offset */, buffer_bytes
);
59 const int bytes_left
= buffer_length
- buffer_bytes
;
61 if (buffered_bytes_
== intermediate_buffer_length_
) {
62 FlushIntermediateBuffer(
63 base::Bind(&BufferingFileStreamWriter::
64 OnFlushIntermediateBufferForBufferedWriteCompleted
,
65 weak_ptr_factory_
.GetWeakPtr(),
66 make_scoped_refptr(buffer
),
70 return net::ERR_IO_PENDING
;
73 // Optimistically return a success.
77 int BufferingFileStreamWriter::Cancel(const net::CompletionCallback
& callback
) {
78 // Since there is no any asynchronous call in this class other than on
79 // |file_stream_writer_|, then there must be an in-flight operation going on.
80 return file_stream_writer_
->Cancel(callback
);
83 int BufferingFileStreamWriter::Flush(const net::CompletionCallback
& callback
) {
84 // Flush all the buffered bytes first, then invoke Flush() on the inner file
86 FlushIntermediateBuffer(base::Bind(
87 &BufferingFileStreamWriter::OnFlushIntermediateBufferForFlushCompleted
,
88 weak_ptr_factory_
.GetWeakPtr(),
90 return net::ERR_IO_PENDING
;
93 void BufferingFileStreamWriter::CopyToIntermediateBuffer(
94 scoped_refptr
<net::IOBuffer
> buffer
,
97 DCHECK_GE(intermediate_buffer_length_
, buffer_length
+ buffered_bytes_
);
98 memcpy(intermediate_buffer_
->data() + buffered_bytes_
,
99 buffer
->data() + buffer_offset
,
101 buffered_bytes_
+= buffer_length
;
104 void BufferingFileStreamWriter::FlushIntermediateBuffer(
105 const net::CompletionCallback
& callback
) {
106 const int result
= file_stream_writer_
->Write(
107 intermediate_buffer_
.get(),
109 base::Bind(&BufferingFileStreamWriter::OnFlushIntermediateBufferCompleted
,
110 weak_ptr_factory_
.GetWeakPtr(),
113 DCHECK_EQ(net::ERR_IO_PENDING
, result
);
116 void BufferingFileStreamWriter::OnFlushIntermediateBufferCompleted(
118 const net::CompletionCallback
& callback
,
121 callback
.Run(result
);
125 DCHECK_EQ(length
, result
) << "Partial writes are not supported.";
128 callback
.Run(net::OK
);
132 BufferingFileStreamWriter::OnFlushIntermediateBufferForDirectWriteCompleted(
133 scoped_refptr
<net::IOBuffer
> buffer
,
135 const net::CompletionCallback
& callback
,
138 callback
.Run(result
);
142 // The following logic is only valid if the intermediate buffer is empty.
143 DCHECK_EQ(0, buffered_bytes_
);
145 const int write_result
=
146 file_stream_writer_
->Write(buffer
.get(), length
, callback
);
147 DCHECK_EQ(net::ERR_IO_PENDING
, write_result
);
151 BufferingFileStreamWriter::OnFlushIntermediateBufferForBufferedWriteCompleted(
152 scoped_refptr
<net::IOBuffer
> buffer
,
155 const net::CompletionCallback
& callback
,
158 callback
.Run(result
);
162 // Copy the rest of bytes to the buffer.
163 DCHECK_EQ(net::OK
, result
);
164 DCHECK_EQ(0, buffered_bytes_
);
165 DCHECK_GE(intermediate_buffer_length_
, bytes_left
);
166 CopyToIntermediateBuffer(buffer
, buffered_bytes
, bytes_left
);
168 callback
.Run(buffered_bytes
+ bytes_left
);
171 void BufferingFileStreamWriter::OnFlushIntermediateBufferForFlushCompleted(
172 const net::CompletionCallback
& callback
,
175 callback
.Run(result
);
179 const int flush_result
= file_stream_writer_
->Flush(callback
);
180 DCHECK_EQ(net::ERR_IO_PENDING
, flush_result
);
183 } // namespace file_system_provider
184 } // namespace chromeos