Include all dupe types (event when value is zero) in scan stats.
[chromium-blink-merge.git] / storage / browser / fileapi / local_file_stream_writer.cc
blob71c6bfbbb04c8f41ce9f587f2588747cdd2d0723
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"
12 namespace storage {
14 namespace {
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;
23 } // namespace
25 FileStreamWriter* FileStreamWriter::CreateForLocalFile(
26 base::TaskRunner* task_runner,
27 const base::FilePath& file_path,
28 int64 initial_offset,
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;
50 if (stream_impl_) {
51 int result = InitiateWrite(buf, buf_len, callback);
52 if (result != net::ERR_IO_PENDING)
53 has_pending_operation_ = false;
54 return result;
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.
76 if (!stream_impl_)
77 return net::OK;
79 has_pending_operation_ = true;
80 int result = InitiateFlush(callback);
81 if (result != net::ERR_IO_PENDING)
82 has_pending_operation_ = false;
83 return result;
86 LocalFileStreamWriter::LocalFileStreamWriter(base::TaskRunner* task_runner,
87 const base::FilePath& file_path,
88 int64 initial_offset,
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_));
105 int open_flags = 0;
106 switch (open_or_create_) {
107 case OPEN_EXISTING_FILE:
108 open_flags = kOpenFlagsForWrite;
109 break;
110 case CREATE_NEW_FILE:
111 open_flags = kCreateFlagsForWrite;
112 break;
115 return stream_impl_->Open(file_path_,
116 open_flags,
117 base::Bind(&LocalFileStreamWriter::DidOpen,
118 weak_factory_.GetWeakPtr(),
119 error_callback,
120 main_operation));
123 void LocalFileStreamWriter::DidOpen(
124 const net::CompletionCallback& error_callback,
125 const base::Closure& main_operation,
126 int result) {
127 DCHECK(has_pending_operation_);
128 DCHECK(stream_impl_.get());
130 if (CancelIfRequested())
131 return;
133 if (result != net::OK) {
134 has_pending_operation_ = false;
135 stream_impl_.reset(NULL);
136 error_callback.Run(result);
137 return;
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) {
150 // No need to seek.
151 main_operation.Run();
152 return;
155 int result = stream_impl_->Seek(base::File::FROM_BEGIN, initial_offset_,
156 base::Bind(&LocalFileStreamWriter::DidSeek,
157 weak_factory_.GetWeakPtr(),
158 error_callback,
159 main_operation));
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,
169 int64 result) {
170 DCHECK(has_pending_operation_);
172 if (CancelIfRequested())
173 return;
175 if (result != initial_offset_) {
176 // TODO(kinaba) add a more specific error code.
177 result = net::ERR_FAILED;
180 if (result < 0) {
181 has_pending_operation_ = false;
182 error_callback.Run(static_cast<int>(result));
183 return;
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(),
210 callback));
213 void LocalFileStreamWriter::DidWrite(const net::CompletionCallback& callback,
214 int result) {
215 DCHECK(has_pending_operation_);
217 if (CancelIfRequested())
218 return;
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(),
230 callback));
233 void LocalFileStreamWriter::DidFlush(const net::CompletionCallback& callback,
234 int result) {
235 DCHECK(has_pending_operation_);
237 if (CancelIfRequested())
238 return;
239 has_pending_operation_ = false;
240 callback.Run(result);
243 bool LocalFileStreamWriter::CancelIfRequested() {
244 DCHECK(has_pending_operation_);
246 if (cancel_callback_.is_null())
247 return false;
249 net::CompletionCallback pending_cancel = cancel_callback_;
250 has_pending_operation_ = false;
251 cancel_callback_.Reset();
252 pending_cancel.Run(net::OK);
253 return true;
256 } // namespace storage