Don't preload rarely seen large images
[chromium-blink-merge.git] / storage / browser / fileapi / sandbox_file_stream_writer.cc
blob74748949ad2e537d75ba8b601137aac249d7b9ca
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/sandbox_file_stream_writer.h"
7 #include "base/files/file_util_proxy.h"
8 #include "base/sequenced_task_runner.h"
9 #include "net/base/io_buffer.h"
10 #include "net/base/net_errors.h"
11 #include "storage/browser/fileapi/file_observers.h"
12 #include "storage/browser/fileapi/file_stream_reader.h"
13 #include "storage/browser/fileapi/file_system_context.h"
14 #include "storage/browser/fileapi/file_system_operation_runner.h"
15 #include "storage/browser/quota/quota_manager_proxy.h"
16 #include "storage/common/fileapi/file_system_util.h"
18 namespace storage {
20 namespace {
22 // Adjust the |quota| value in overwriting case (i.e. |file_size| > 0 and
23 // |file_offset| < |file_size|) to make the remaining quota calculation easier.
24 // Specifically this widens the quota for overlapping range (so that we can
25 // simply compare written bytes against the adjusted quota).
26 int64 AdjustQuotaForOverlap(int64 quota,
27 int64 file_offset,
28 int64 file_size) {
29 DCHECK_LE(file_offset, file_size);
30 if (quota < 0)
31 quota = 0;
32 int64 overlap = file_size - file_offset;
33 if (kint64max - overlap > quota)
34 quota += overlap;
35 return quota;
38 } // namespace
40 SandboxFileStreamWriter::SandboxFileStreamWriter(
41 FileSystemContext* file_system_context,
42 const FileSystemURL& url,
43 int64 initial_offset,
44 const UpdateObserverList& observers)
45 : file_system_context_(file_system_context),
46 url_(url),
47 initial_offset_(initial_offset),
48 observers_(observers),
49 file_size_(0),
50 total_bytes_written_(0),
51 allowed_bytes_to_write_(0),
52 has_pending_operation_(false),
53 default_quota_(kint64max),
54 weak_factory_(this) {
55 DCHECK(url_.is_valid());
58 SandboxFileStreamWriter::~SandboxFileStreamWriter() {}
60 int SandboxFileStreamWriter::Write(
61 net::IOBuffer* buf, int buf_len,
62 const net::CompletionCallback& callback) {
63 has_pending_operation_ = true;
64 if (local_file_writer_)
65 return WriteInternal(buf, buf_len, callback);
67 net::CompletionCallback write_task =
68 base::Bind(&SandboxFileStreamWriter::DidInitializeForWrite,
69 weak_factory_.GetWeakPtr(),
70 make_scoped_refptr(buf), buf_len, callback);
71 file_system_context_->operation_runner()->CreateSnapshotFile(
72 url_, base::Bind(&SandboxFileStreamWriter::DidCreateSnapshotFile,
73 weak_factory_.GetWeakPtr(), write_task));
74 return net::ERR_IO_PENDING;
77 int SandboxFileStreamWriter::Cancel(const net::CompletionCallback& callback) {
78 if (!has_pending_operation_)
79 return net::ERR_UNEXPECTED;
81 DCHECK(!callback.is_null());
82 cancel_callback_ = callback;
83 return net::ERR_IO_PENDING;
86 int SandboxFileStreamWriter::WriteInternal(
87 net::IOBuffer* buf, int buf_len,
88 const net::CompletionCallback& callback) {
89 // allowed_bytes_to_write could be negative if the file size is
90 // greater than the current (possibly new) quota.
91 DCHECK(total_bytes_written_ <= allowed_bytes_to_write_ ||
92 allowed_bytes_to_write_ < 0);
93 if (total_bytes_written_ >= allowed_bytes_to_write_) {
94 has_pending_operation_ = false;
95 return net::ERR_FILE_NO_SPACE;
98 if (buf_len > allowed_bytes_to_write_ - total_bytes_written_)
99 buf_len = allowed_bytes_to_write_ - total_bytes_written_;
101 DCHECK(local_file_writer_.get());
102 const int result = local_file_writer_->Write(
103 buf, buf_len,
104 base::Bind(&SandboxFileStreamWriter::DidWrite, weak_factory_.GetWeakPtr(),
105 callback));
106 if (result != net::ERR_IO_PENDING)
107 has_pending_operation_ = false;
108 return result;
111 void SandboxFileStreamWriter::DidCreateSnapshotFile(
112 const net::CompletionCallback& callback,
113 base::File::Error file_error,
114 const base::File::Info& file_info,
115 const base::FilePath& platform_path,
116 const scoped_refptr<storage::ShareableFileReference>& file_ref) {
117 DCHECK(!file_ref.get());
119 if (CancelIfRequested())
120 return;
121 if (file_error != base::File::FILE_OK) {
122 callback.Run(net::FileErrorToNetError(file_error));
123 return;
125 if (file_info.is_directory) {
126 // We should not be writing to a directory.
127 callback.Run(net::ERR_ACCESS_DENIED);
128 return;
130 file_size_ = file_info.size;
131 if (initial_offset_ > file_size_) {
132 LOG(ERROR) << initial_offset_ << ", " << file_size_;
133 // This shouldn't happen as long as we check offset in the renderer.
134 NOTREACHED();
135 initial_offset_ = file_size_;
137 DCHECK(!local_file_writer_.get());
138 local_file_writer_.reset(FileStreamWriter::CreateForLocalFile(
139 file_system_context_->default_file_task_runner(),
140 platform_path,
141 initial_offset_,
142 FileStreamWriter::OPEN_EXISTING_FILE));
144 storage::QuotaManagerProxy* quota_manager_proxy =
145 file_system_context_->quota_manager_proxy();
146 if (!quota_manager_proxy) {
147 // If we don't have the quota manager or the requested filesystem type
148 // does not support quota, we should be able to let it go.
149 allowed_bytes_to_write_ = default_quota_;
150 callback.Run(net::OK);
151 return;
154 DCHECK(quota_manager_proxy->quota_manager());
155 quota_manager_proxy->quota_manager()->GetUsageAndQuota(
156 url_.origin(),
157 FileSystemTypeToQuotaStorageType(url_.type()),
158 base::Bind(&SandboxFileStreamWriter::DidGetUsageAndQuota,
159 weak_factory_.GetWeakPtr(), callback));
162 void SandboxFileStreamWriter::DidGetUsageAndQuota(
163 const net::CompletionCallback& callback,
164 storage::QuotaStatusCode status,
165 int64 usage,
166 int64 quota) {
167 if (CancelIfRequested())
168 return;
169 if (status != storage::kQuotaStatusOk) {
170 LOG(WARNING) << "Got unexpected quota error : " << status;
171 callback.Run(net::ERR_FAILED);
172 return;
175 allowed_bytes_to_write_ = quota - usage;
176 callback.Run(net::OK);
179 void SandboxFileStreamWriter::DidInitializeForWrite(
180 net::IOBuffer* buf, int buf_len,
181 const net::CompletionCallback& callback,
182 int init_status) {
183 if (CancelIfRequested())
184 return;
185 if (init_status != net::OK) {
186 has_pending_operation_ = false;
187 callback.Run(init_status);
188 return;
190 allowed_bytes_to_write_ = AdjustQuotaForOverlap(
191 allowed_bytes_to_write_, initial_offset_, file_size_);
192 const int result = WriteInternal(buf, buf_len, callback);
193 if (result != net::ERR_IO_PENDING)
194 callback.Run(result);
197 void SandboxFileStreamWriter::DidWrite(
198 const net::CompletionCallback& callback,
199 int write_response) {
200 DCHECK(has_pending_operation_);
201 has_pending_operation_ = false;
203 if (write_response <= 0) {
204 if (CancelIfRequested())
205 return;
206 callback.Run(write_response);
207 return;
210 if (total_bytes_written_ + write_response + initial_offset_ > file_size_) {
211 int overlapped = file_size_ - total_bytes_written_ - initial_offset_;
212 if (overlapped < 0)
213 overlapped = 0;
214 observers_.Notify(&FileUpdateObserver::OnUpdate,
215 base::MakeTuple(url_, write_response - overlapped));
217 total_bytes_written_ += write_response;
219 if (CancelIfRequested())
220 return;
221 callback.Run(write_response);
224 bool SandboxFileStreamWriter::CancelIfRequested() {
225 if (cancel_callback_.is_null())
226 return false;
228 net::CompletionCallback pending_cancel = cancel_callback_;
229 has_pending_operation_ = false;
230 cancel_callback_.Reset();
231 pending_cancel.Run(net::OK);
232 return true;
235 int SandboxFileStreamWriter::Flush(const net::CompletionCallback& callback) {
236 DCHECK(!has_pending_operation_);
237 DCHECK(cancel_callback_.is_null());
239 // Write() is not called yet, so there's nothing to flush.
240 if (!local_file_writer_)
241 return net::OK;
243 return local_file_writer_->Flush(callback);
246 } // namespace storage