Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(45)

Side by Side Diff: webkit/fileapi/sandbox_file_writer.cc

Issue 10387054: Implement SandboxFileWriter and rewrite FileWriterDelegate to use it (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: addressed comment Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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.
4
5 #include "webkit/fileapi/sandbox_file_writer.h"
6
7 #include "base/file_util_proxy.h"
8 #include "base/platform_file.h"
9 #include "base/sequenced_task_runner.h"
10 #include "net/base/io_buffer.h"
11 #include "net/base/net_errors.h"
12 #include "webkit/blob/local_file_reader.h"
13 #include "webkit/fileapi/file_system_context.h"
14 #include "webkit/fileapi/file_system_operation_interface.h"
15 #include "webkit/fileapi/file_system_quota_util.h"
16 #include "webkit/fileapi/file_system_util.h"
17 #include "webkit/fileapi/local_file_writer.h"
18 #include "webkit/quota/quota_manager.h"
19
20 namespace fileapi {
21
22 namespace {
23
24 int PlatformFileErrorToNetError(base::PlatformFileError error) {
25 // TODO(kinuko): Move this static method to more convenient place.
26 return webkit_blob::LocalFileReader::PlatformFileErrorToNetError(error);
27 }
28
29 // Adjust the |quota| value with given |file_offset| and |file_size| and
30 // return the new quota value.
ericu 2012/05/16 00:23:17 The comments and name here aren't clear. They sho
kinuko 2012/05/16 04:10:12 Updated the comment.
ericu 2012/05/17 00:04:13 Very nice--thanks.
31 int64 AdjustQuotaWithFileRange(int64 quota,
32 int64 file_offset,
33 int64 file_size) {
34 DCHECK_LE(file_offset, file_size);
35 if (quota < 0)
36 quota = 0;
37 int64 overlap = file_size - file_offset;
38 if (kint64max - overlap > quota)
39 quota += overlap;
40 return quota;
41 }
42
43 } // namespace
44
45 SandboxFileWriter::SandboxFileWriter(
46 FileSystemContext* file_system_context,
47 const GURL& url,
48 int64 initial_offset)
49 : file_system_context_(file_system_context),
50 url_(url),
51 initial_offset_(initial_offset),
52 file_size_(0),
53 total_bytes_written_(0),
54 allowed_bytes_to_write_(0),
55 has_pending_operation_(false),
56 default_quota_(kint64max),
57 weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
58 const bool result = CrackFileSystemURL(
59 url_, &origin_, &file_system_type_, &virtual_path_);
60 DCHECK(result);
61 }
62
63 SandboxFileWriter::~SandboxFileWriter() {
64 if (quota_util())
65 quota_util()->proxy()->EndUpdateOrigin(origin_, file_system_type_);
66 }
67
68 int SandboxFileWriter::Write(
69 net::IOBuffer* buf, int buf_len,
70 const net::CompletionCallback& callback) {
71 has_pending_operation_ = true;
72 if (local_file_writer_.get())
73 return WriteInternal(buf, buf_len, callback);
74
75 FileSystemOperationInterface* operation =
76 file_system_context_->CreateFileSystemOperation(url_);
77 DCHECK(operation);
78 net::CompletionCallback write_task =
79 base::Bind(&SandboxFileWriter::DidInitializeForWrite,
80 weak_factory_.GetWeakPtr(),
81 make_scoped_refptr(buf), buf_len, callback);
82 operation->GetMetadata(
83 url_, base::Bind(&SandboxFileWriter::DidGetFileInfo,
84 weak_factory_.GetWeakPtr(), write_task));
85 return net::ERR_IO_PENDING;
86 }
87
88 int SandboxFileWriter::Cancel(const net::CompletionCallback& callback) {
89 if (!has_pending_operation_)
90 return net::ERR_UNEXPECTED;
91
92 DCHECK(local_file_writer_.get());
ericu 2012/05/16 00:23:17 If you call Write, then quickly call Cancel before
kinuko 2012/05/16 04:10:12 You're right, I just found this problem while runn
93 DCHECK(!callback.is_null());
94 cancel_callback_ = callback;
95 return net::ERR_IO_PENDING;
96 }
97
98 int SandboxFileWriter::WriteInternal(
99 net::IOBuffer* buf, int buf_len,
100 const net::CompletionCallback& callback) {
101 // allowed_bytes_to_write could be negative if the file size is
102 // greater than the current (possibly new) quota.
103 DCHECK(total_bytes_written_ <= allowed_bytes_to_write_ ||
104 allowed_bytes_to_write_ < 0);
105 if (total_bytes_written_ >= allowed_bytes_to_write_) {
106 has_pending_operation_ = false;
107 return net::ERR_FILE_NO_SPACE;
108 }
109
110 if (buf_len > allowed_bytes_to_write_ - total_bytes_written_)
111 buf_len = allowed_bytes_to_write_ - total_bytes_written_;
112
113 DCHECK(local_file_writer_.get());
114 const int result = local_file_writer_->Write(
115 buf, buf_len,
116 base::Bind(&SandboxFileWriter::DidWrite, weak_factory_.GetWeakPtr(),
117 callback));
118 if (result != net::ERR_IO_PENDING)
119 has_pending_operation_ = false;
120 return result;
121 }
122
123 void SandboxFileWriter::DidGetFileInfo(
124 const net::CompletionCallback& callback,
125 base::PlatformFileError file_error,
126 const base::PlatformFileInfo& file_info,
127 const FilePath& platform_path) {
128 if (CancelIfRequested())
129 return;
130 if (file_error != base::PLATFORM_FILE_OK) {
131 callback.Run(PlatformFileErrorToNetError(file_error));
132 return;
133 }
134 if (file_info.is_directory) {
135 // We should not be writing to a directory.
136 callback.Run(net::ERR_ACCESS_DENIED);
137 return;
138 }
139 file_size_ = file_info.size;
140 if (initial_offset_ > file_size_) {
141 LOG(ERROR) << initial_offset_ << ", " << file_size_;
142 // This shouldn't happen as long as we check offset in the renderer.
143 NOTREACHED();
144 initial_offset_ = file_size_;
145 }
146 DCHECK(!local_file_writer_.get());
147 local_file_writer_.reset(new LocalFileWriter(platform_path, initial_offset_));
148
149 quota::QuotaManagerProxy* quota_manager_proxy =
150 file_system_context_->quota_manager_proxy();
151 if (!quota_manager_proxy || !quota_util()) {
152 // If we don't have the quota manager or the requested filesystem type
153 // does not support quota, we should be able to let it go.
154 allowed_bytes_to_write_ = default_quota_;
155 callback.Run(net::OK);
156 return;
157 }
158
159 quota_util()->proxy()->StartUpdateOrigin(origin_, file_system_type_);
160 DCHECK(quota_manager_proxy->quota_manager());
161 quota_manager_proxy->quota_manager()->GetUsageAndQuota(
162 origin_,
163 FileSystemTypeToQuotaStorageType(file_system_type_),
164 base::Bind(&SandboxFileWriter::DidGetUsageAndQuota,
165 weak_factory_.GetWeakPtr(), callback));
166 }
167
168 void SandboxFileWriter::DidGetUsageAndQuota(
169 const net::CompletionCallback& callback,
170 quota::QuotaStatusCode status,
171 int64 usage, int64 quota) {
172 if (status != quota::kQuotaStatusOk) {
173 LOG(WARNING) << "Got unexpected quota error : " << status;
174 callback.Run(net::ERR_FAILED);
175 return;
176 }
177
178 allowed_bytes_to_write_ = quota - usage;
179 callback.Run(net::OK);
180 }
181
182 void SandboxFileWriter::DidInitializeForWrite(
183 net::IOBuffer* buf, int buf_len,
184 const net::CompletionCallback& callback,
185 int init_status) {
186 if (init_status != net::OK) {
187 has_pending_operation_ = false;
188 callback.Run(init_status);
189 return;
190 }
191 allowed_bytes_to_write_ = AdjustQuotaWithFileRange(
192 allowed_bytes_to_write_, initial_offset_, file_size_);
193 const int result = WriteInternal(buf, buf_len, callback);
194 if (result != net::ERR_IO_PENDING)
195 callback.Run(result);
196 }
197
198 void SandboxFileWriter::DidWrite(
199 const net::CompletionCallback& callback,
200 int write_response) {
201 DCHECK(has_pending_operation_);
202 has_pending_operation_ = false;
203
204 if (write_response <= 0) {
205 if (CancelIfRequested())
206 return;
207 callback.Run(write_response);
208 return;
209 }
210
211 if (quota_util() &&
212 total_bytes_written_ + write_response + initial_offset_ > file_size_) {
213 int overlapped = file_size_ - total_bytes_written_ - initial_offset_;
214 if (overlapped < 0)
215 overlapped = 0;
216 quota_util()->proxy()->UpdateOriginUsage(
217 file_system_context_->quota_manager_proxy(),
218 origin_, file_system_type_, write_response - overlapped);
219 }
220 total_bytes_written_ += write_response;
221
222 if (CancelIfRequested())
223 return;
224 callback.Run(write_response);
225 }
226
227 bool SandboxFileWriter::CancelIfRequested() {
228 if (cancel_callback_.is_null())
229 return false;
230
231 net::CompletionCallback pending_cancel = cancel_callback_;
232 has_pending_operation_ = false;
233 cancel_callback_.Reset();
234 pending_cancel.Run(net::OK);
235 return true;
236 }
237
238 FileSystemQuotaUtil* SandboxFileWriter::quota_util() const {
239 DCHECK(file_system_context_.get());
240 return file_system_context_->GetQuotaUtil(file_system_type_);
241 }
242
243 } // namespace fileapi
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698