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

Side by Side Diff: webkit/plugins/ppapi/quota_file_io.cc

Issue 20165002: Move webkit/plugins/ppapi to content/renderer/pepper. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: more more clang fun Created 7 years, 5 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
« no previous file with comments | « webkit/plugins/ppapi/quota_file_io.h ('k') | webkit/plugins/ppapi/quota_file_io_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/plugins/ppapi/quota_file_io.h"
6
7 #include <algorithm>
8
9 #include "base/bind.h"
10 #include "base/location.h"
11 #include "base/memory/weak_ptr.h"
12 #include "base/message_loop/message_loop_proxy.h"
13 #include "base/stl_util.h"
14 #include "base/task_runner_util.h"
15 #include "webkit/plugins/ppapi/host_globals.h"
16 #include "webkit/plugins/ppapi/ppapi_plugin_instance_impl.h"
17 #include "webkit/plugins/ppapi/resource_helper.h"
18
19 using base::PlatformFile;
20 using base::PlatformFileError;
21 using quota::StorageType;
22
23 namespace webkit {
24 namespace ppapi {
25
26 namespace {
27 StorageType PPFileSystemTypeToQuotaStorageType(PP_FileSystemType type) {
28 switch (type) {
29 case PP_FILESYSTEMTYPE_LOCALPERSISTENT:
30 return quota::kStorageTypePersistent;
31 case PP_FILESYSTEMTYPE_LOCALTEMPORARY:
32 return quota::kStorageTypeTemporary;
33 default:
34 return quota::kStorageTypeUnknown;
35 }
36 NOTREACHED();
37 return quota::kStorageTypeUnknown;
38 }
39
40 int WriteAdapter(PlatformFile file, int64 offset,
41 scoped_ptr<char[]> data, int size) {
42 return base::WritePlatformFile(file, offset, data.get(), size);
43 }
44
45 } // namespace
46
47 class QuotaFileIO::PendingOperationBase {
48 public:
49 virtual ~PendingOperationBase() {}
50
51 // Either one of Run() or DidFail() is called (the latter is called when
52 // there was more than one error during quota queries).
53 virtual void Run() = 0;
54 virtual void DidFail(PlatformFileError error) = 0;
55
56 protected:
57 PendingOperationBase(QuotaFileIO* quota_io, bool is_will_operation)
58 : quota_io_(quota_io), is_will_operation_(is_will_operation) {
59 DCHECK(quota_io_);
60 quota_io_->WillUpdate();
61 }
62
63 QuotaFileIO* quota_io_;
64 const bool is_will_operation_;
65 };
66
67 class QuotaFileIO::WriteOperation : public PendingOperationBase {
68 public:
69 WriteOperation(QuotaFileIO* quota_io,
70 bool is_will_operation,
71 int64_t offset,
72 const char* buffer,
73 int32_t bytes_to_write,
74 const WriteCallback& callback)
75 : PendingOperationBase(quota_io, is_will_operation),
76 offset_(offset),
77 bytes_to_write_(bytes_to_write),
78 callback_(callback),
79 finished_(false),
80 status_(base::PLATFORM_FILE_OK),
81 bytes_written_(0),
82 weak_factory_(this) {
83 if (!is_will_operation) {
84 // TODO(kinuko): Check the API convention if we really need to keep a copy
85 // of the buffer during the async write operations.
86 buffer_.reset(new char[bytes_to_write]);
87 memcpy(buffer_.get(), buffer, bytes_to_write);
88 }
89 }
90 virtual ~WriteOperation() {}
91 virtual void Run() OVERRIDE {
92 DCHECK(quota_io_);
93 if (quota_io_->CheckIfExceedsQuota(offset_ + bytes_to_write_)) {
94 DidFail(base::PLATFORM_FILE_ERROR_NO_SPACE);
95 return;
96 }
97 if (is_will_operation_) {
98 // Assuming the write will succeed.
99 DidFinish(base::PLATFORM_FILE_OK, bytes_to_write_);
100 return;
101 }
102 DCHECK(buffer_.get());
103
104 PluginDelegate* plugin_delegate = quota_io_->GetPluginDelegate();
105 if (!plugin_delegate) {
106 DidFail(base::PLATFORM_FILE_ERROR_FAILED);
107 return;
108 }
109
110 if (!base::PostTaskAndReplyWithResult(
111 plugin_delegate->GetFileThreadMessageLoopProxy().get(),
112 FROM_HERE,
113 base::Bind(&WriteAdapter,
114 quota_io_->file_,
115 offset_,
116 base::Passed(&buffer_),
117 bytes_to_write_),
118 base::Bind(&WriteOperation::DidWrite,
119 weak_factory_.GetWeakPtr()))) {
120 DidFail(base::PLATFORM_FILE_ERROR_FAILED);
121 return;
122 }
123 }
124
125 virtual void DidFail(PlatformFileError error) OVERRIDE {
126 DidFinish(error, 0);
127 }
128
129 bool finished() const { return finished_; }
130
131 virtual void WillRunCallback() {
132 base::MessageLoopProxy::current()->PostTask(
133 FROM_HERE,
134 base::Bind(&WriteOperation::RunCallback, weak_factory_.GetWeakPtr()));
135 }
136
137 private:
138 void DidWrite(int bytes_written) {
139 base::PlatformFileError error = bytes_written > 0 ?
140 base::PLATFORM_FILE_OK : base::PLATFORM_FILE_ERROR_FAILED;
141 DidFinish(error, bytes_written);
142 }
143
144 void DidFinish(PlatformFileError status, int bytes_written) {
145 finished_ = true;
146 status_ = status;
147 bytes_written_ = bytes_written;
148 int64_t max_offset =
149 (status != base::PLATFORM_FILE_OK) ? 0 : offset_ + bytes_written;
150 // This may delete itself by calling RunCallback.
151 quota_io_->DidWrite(this, max_offset);
152 }
153
154 virtual void RunCallback() {
155 DCHECK_EQ(false, callback_.is_null());
156 callback_.Run(status_, bytes_written_);
157 delete this;
158 }
159
160 const int64_t offset_;
161 scoped_ptr<char[]> buffer_;
162 const int32_t bytes_to_write_;
163 WriteCallback callback_;
164 bool finished_;
165 PlatformFileError status_;
166 int64_t bytes_written_;
167 base::WeakPtrFactory<WriteOperation> weak_factory_;
168 };
169
170 class QuotaFileIO::SetLengthOperation : public PendingOperationBase {
171 public:
172 SetLengthOperation(QuotaFileIO* quota_io,
173 bool is_will_operation,
174 int64_t length,
175 const StatusCallback& callback)
176 : PendingOperationBase(quota_io, is_will_operation),
177 length_(length),
178 callback_(callback),
179 weak_factory_(this) {}
180
181 virtual ~SetLengthOperation() {}
182
183 virtual void Run() OVERRIDE {
184 DCHECK(quota_io_);
185 if (quota_io_->CheckIfExceedsQuota(length_)) {
186 DidFail(base::PLATFORM_FILE_ERROR_NO_SPACE);
187 return;
188 }
189 if (is_will_operation_) {
190 DidFinish(base::PLATFORM_FILE_OK);
191 return;
192 }
193
194 PluginDelegate* plugin_delegate = quota_io_->GetPluginDelegate();
195 if (!plugin_delegate) {
196 DidFail(base::PLATFORM_FILE_ERROR_FAILED);
197 return;
198 }
199
200 if (!base::FileUtilProxy::Truncate(
201 plugin_delegate->GetFileThreadMessageLoopProxy().get(),
202 quota_io_->file_,
203 length_,
204 base::Bind(&SetLengthOperation::DidFinish,
205 weak_factory_.GetWeakPtr()))) {
206 DidFail(base::PLATFORM_FILE_ERROR_FAILED);
207 return;
208 }
209 }
210
211 virtual void DidFail(PlatformFileError error) OVERRIDE {
212 DidFinish(error);
213 }
214
215 private:
216 void DidFinish(PlatformFileError status) {
217 quota_io_->DidSetLength(status, length_);
218 DCHECK_EQ(false, callback_.is_null());
219 callback_.Run(status);
220 delete this;
221 }
222
223 int64_t length_;
224 StatusCallback callback_;
225 base::WeakPtrFactory<SetLengthOperation> weak_factory_;
226 };
227
228 // QuotaFileIO --------------------------------------------------------------
229
230 QuotaFileIO::QuotaFileIO(
231 PP_Instance instance,
232 PlatformFile file,
233 const GURL& file_url,
234 PP_FileSystemType type)
235 : pp_instance_(instance),
236 file_(file),
237 file_url_(file_url),
238 storage_type_(PPFileSystemTypeToQuotaStorageType(type)),
239 cached_file_size_(0),
240 cached_available_space_(0),
241 outstanding_quota_queries_(0),
242 outstanding_errors_(0),
243 max_written_offset_(0),
244 inflight_operations_(0),
245 weak_factory_(this) {
246 DCHECK_NE(base::kInvalidPlatformFileValue, file_);
247 DCHECK_NE(quota::kStorageTypeUnknown, storage_type_);
248 }
249
250 QuotaFileIO::~QuotaFileIO() {
251 // Note that this doesn't dispatch pending callbacks.
252 STLDeleteContainerPointers(pending_operations_.begin(),
253 pending_operations_.end());
254 STLDeleteContainerPointers(pending_callbacks_.begin(),
255 pending_callbacks_.end());
256 }
257
258 bool QuotaFileIO::Write(
259 int64_t offset, const char* buffer, int32_t bytes_to_write,
260 const WriteCallback& callback) {
261 if (bytes_to_write <= 0)
262 return false;
263
264 WriteOperation* op = new WriteOperation(
265 this, false, offset, buffer, bytes_to_write, callback);
266 return RegisterOperationForQuotaChecks(op);
267 }
268
269 bool QuotaFileIO::SetLength(int64_t length, const StatusCallback& callback) {
270 DCHECK(pending_operations_.empty());
271 SetLengthOperation* op = new SetLengthOperation(
272 this, false, length, callback);
273 return RegisterOperationForQuotaChecks(op);
274 }
275
276 bool QuotaFileIO::WillWrite(
277 int64_t offset, int32_t bytes_to_write, const WriteCallback& callback) {
278 WriteOperation* op = new WriteOperation(
279 this, true, offset, NULL, bytes_to_write, callback);
280 return RegisterOperationForQuotaChecks(op);
281 }
282
283 bool QuotaFileIO::WillSetLength(int64_t length,
284 const StatusCallback& callback) {
285 DCHECK(pending_operations_.empty());
286 SetLengthOperation* op = new SetLengthOperation(this, true, length, callback);
287 return RegisterOperationForQuotaChecks(op);
288 }
289
290 PluginDelegate* QuotaFileIO::GetPluginDelegate() const {
291 PluginInstanceImpl* instance = HostGlobals::Get()->GetInstance(pp_instance_);
292 if (instance)
293 return instance->delegate();
294 return NULL;
295 }
296
297 bool QuotaFileIO::RegisterOperationForQuotaChecks(
298 PendingOperationBase* op_ptr) {
299 scoped_ptr<PendingOperationBase> op(op_ptr);
300 if (pending_operations_.empty()) {
301 // This is the first pending quota check. Run querying the file size
302 // and available space.
303 outstanding_quota_queries_ = 0;
304 outstanding_errors_ = 0;
305
306 PluginDelegate* plugin_delegate = GetPluginDelegate();
307 if (!plugin_delegate)
308 return false;
309
310 // Query the file size.
311 ++outstanding_quota_queries_;
312 if (!base::FileUtilProxy::GetFileInfoFromPlatformFile(
313 plugin_delegate->GetFileThreadMessageLoopProxy().get(),
314 file_,
315 base::Bind(&QuotaFileIO::DidQueryInfoForQuota,
316 weak_factory_.GetWeakPtr()))) {
317 // This makes the call fail synchronously; we do not fire the callback
318 // here but just delete the operation and return false.
319 return false;
320 }
321
322 // Query the current available space.
323 ++outstanding_quota_queries_;
324 plugin_delegate->QueryAvailableSpace(
325 file_url_.GetOrigin(), storage_type_,
326 base::Bind(&QuotaFileIO::DidQueryAvailableSpace,
327 weak_factory_.GetWeakPtr()));
328 }
329 pending_operations_.push_back(op.release());
330 return true;
331 }
332
333 void QuotaFileIO::DidQueryInfoForQuota(
334 base::PlatformFileError error_code,
335 const base::PlatformFileInfo& file_info) {
336 if (error_code != base::PLATFORM_FILE_OK)
337 ++outstanding_errors_;
338 cached_file_size_ = file_info.size;
339 DCHECK_GT(outstanding_quota_queries_, 0);
340 if (--outstanding_quota_queries_ == 0)
341 DidQueryForQuotaCheck();
342 }
343
344 void QuotaFileIO::DidQueryAvailableSpace(int64_t avail_space) {
345 cached_available_space_ = avail_space;
346 DCHECK_GT(outstanding_quota_queries_, 0);
347 if (--outstanding_quota_queries_ == 0)
348 DidQueryForQuotaCheck();
349 }
350
351 void QuotaFileIO::DidQueryForQuotaCheck() {
352 DCHECK(!pending_operations_.empty());
353 DCHECK_GT(inflight_operations_, 0);
354 while (!pending_operations_.empty()) {
355 PendingOperationBase* op = pending_operations_.front();
356 pending_operations_.pop_front();
357 pending_callbacks_.push_back(op);
358 if (outstanding_errors_ > 0) {
359 op->DidFail(base::PLATFORM_FILE_ERROR_FAILED);
360 continue;
361 }
362 op->Run();
363 }
364 }
365
366 bool QuotaFileIO::CheckIfExceedsQuota(int64_t new_file_size) const {
367 DCHECK_GE(cached_file_size_, 0);
368 DCHECK_GE(cached_available_space_, 0);
369 return new_file_size - cached_file_size_ > cached_available_space_;
370 }
371
372 void QuotaFileIO::WillUpdate() {
373 if (inflight_operations_++ == 0) {
374 PluginDelegate* plugin_delegate = GetPluginDelegate();
375 if (plugin_delegate)
376 plugin_delegate->WillUpdateFile(file_url_);
377 DCHECK_EQ(0, max_written_offset_);
378 }
379 }
380
381 void QuotaFileIO::DidWrite(WriteOperation* op,
382 int64_t written_offset_end) {
383 max_written_offset_ = std::max(max_written_offset_, written_offset_end);
384 DCHECK_GT(inflight_operations_, 0);
385 DCHECK(!pending_callbacks_.empty());
386 // Fire callbacks for finished operations.
387 while (!pending_callbacks_.empty()) {
388 WriteOperation* op = static_cast<WriteOperation*>(
389 pending_callbacks_.front());
390 if (!op->finished())
391 break;
392 pending_callbacks_.pop_front();
393 op->WillRunCallback();
394 }
395 // If we have no more pending writes, notify the browser that we did
396 // update the file.
397 if (--inflight_operations_ == 0) {
398 DCHECK(pending_operations_.empty());
399 int64_t growth = max_written_offset_ - cached_file_size_;
400 growth = growth < 0 ? 0 : growth;
401
402 PluginDelegate* plugin_delegate = GetPluginDelegate();
403 if (plugin_delegate)
404 plugin_delegate->DidUpdateFile(file_url_, growth);
405 max_written_offset_ = 0;
406 }
407 }
408
409 void QuotaFileIO::DidSetLength(PlatformFileError error, int64_t new_file_size) {
410 DCHECK_EQ(1, inflight_operations_);
411 pending_callbacks_.pop_front();
412 DCHECK(pending_callbacks_.empty());
413 int64_t delta = (error != base::PLATFORM_FILE_OK) ? 0 :
414 new_file_size - cached_file_size_;
415
416
417 PluginDelegate* plugin_delegate = GetPluginDelegate();
418 if (plugin_delegate)
419 plugin_delegate->DidUpdateFile(file_url_, delta);
420 inflight_operations_ = 0;
421 }
422
423 } // namespace ppapi
424 } // namespace webkit
OLDNEW
« no previous file with comments | « webkit/plugins/ppapi/quota_file_io.h ('k') | webkit/plugins/ppapi/quota_file_io_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698