1// Copyright 2013 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 "content/browser/renderer_host/pepper/quota_reservation.h"
6
7#include "base/bind.h"
8#include "base/callback.h"
9#include "content/public/browser/browser_thread.h"
10#include "storage/browser/fileapi/file_system_operation_runner.h"
11#include "storage/browser/fileapi/quota/open_file_handle.h"
12#include "storage/browser/fileapi/quota/quota_reservation.h"
13#include "storage/common/fileapi/file_system_util.h"
14
15namespace content {
16
17// static
18scoped_refptr<QuotaReservation> QuotaReservation::Create(
19    scoped_refptr<storage::FileSystemContext> file_system_context,
20    const GURL& origin_url,
21    storage::FileSystemType type) {
22  return scoped_refptr<QuotaReservation>(
23      new QuotaReservation(file_system_context, origin_url, type));
24}
25
26QuotaReservation::QuotaReservation(
27    scoped_refptr<storage::FileSystemContext> file_system_context,
28    const GURL& origin_url,
29    storage::FileSystemType file_system_type)
30    : file_system_context_(file_system_context) {
31  quota_reservation_ =
32      file_system_context->CreateQuotaReservationOnFileTaskRunner(
33          origin_url, file_system_type);
34}
35
36// For unit testing only.
37QuotaReservation::QuotaReservation(
38    scoped_refptr<storage::QuotaReservation> quota_reservation,
39    const GURL& /* origin_url */,
40    storage::FileSystemType /* file_system_type */)
41    : quota_reservation_(quota_reservation) {
42}
43
44QuotaReservation::~QuotaReservation() {
45  // We should have no open files at this point.
46  DCHECK(files_.size() == 0);
47  for (FileMap::iterator it = files_.begin(); it != files_.end(); ++it)
48    delete it->second;
49}
50
51int64_t QuotaReservation::OpenFile(int32_t id,
52                                   const storage::FileSystemURL& url) {
53  base::FilePath platform_file_path;
54  if (file_system_context_.get()) {
55    base::File::Error error =
56        file_system_context_->operation_runner()->SyncGetPlatformPath(
57            url, &platform_file_path);
58    if (error != base::File::FILE_OK) {
59      NOTREACHED();
60      return 0;
61    }
62  } else {
63    // For test.
64    platform_file_path = url.path();
65  }
66
67  scoped_ptr<storage::OpenFileHandle> file_handle =
68      quota_reservation_->GetOpenFileHandle(platform_file_path);
69  std::pair<FileMap::iterator, bool> insert_result =
70      files_.insert(std::make_pair(id, file_handle.get()));
71  if (insert_result.second) {
72    int64_t max_written_offset = file_handle->GetMaxWrittenOffset();
73    ignore_result(file_handle.release());
74    return max_written_offset;
75  }
76  NOTREACHED();
77  return 0;
78}
79
80void QuotaReservation::CloseFile(int32_t id,
81                                 const ppapi::FileGrowth& file_growth) {
82  FileMap::iterator it = files_.find(id);
83  if (it != files_.end()) {
84    it->second->UpdateMaxWrittenOffset(file_growth.max_written_offset);
85    it->second->AddAppendModeWriteAmount(file_growth.append_mode_write_amount);
86    delete it->second;
87    files_.erase(it);
88  } else {
89    NOTREACHED();
90  }
91}
92
93void QuotaReservation::ReserveQuota(int64_t amount,
94                                    const ppapi::FileGrowthMap& file_growths,
95                                    const ReserveQuotaCallback& callback) {
96  for (FileMap::iterator it = files_.begin(); it != files_.end(); ++it) {
97    ppapi::FileGrowthMap::const_iterator growth_it =
98        file_growths.find(it->first);
99    if (growth_it != file_growths.end()) {
100      it->second->UpdateMaxWrittenOffset(growth_it->second.max_written_offset);
101      it->second->AddAppendModeWriteAmount(
102          growth_it->second.append_mode_write_amount);
103    } else {
104      NOTREACHED();
105    }
106  }
107
108  quota_reservation_->RefreshReservation(
109      amount, base::Bind(&QuotaReservation::GotReservedQuota, this, callback));
110}
111
112void QuotaReservation::OnClientCrash() { quota_reservation_->OnClientCrash(); }
113
114void QuotaReservation::GotReservedQuota(const ReserveQuotaCallback& callback,
115                                        base::File::Error error) {
116  ppapi::FileSizeMap file_sizes;
117  for (FileMap::iterator it = files_.begin(); it != files_.end(); ++it)
118    file_sizes[it->first] = it->second->GetMaxWrittenOffset();
119
120  if (file_system_context_.get()) {
121    BrowserThread::PostTask(
122        BrowserThread::IO,
123        FROM_HERE,
124        base::Bind(
125            callback, quota_reservation_->remaining_quota(), file_sizes));
126  } else {
127    // Unit testing code path.
128    callback.Run(quota_reservation_->remaining_quota(), file_sizes);
129  }
130}
131
132void QuotaReservation::DeleteOnCorrectThread() const {
133  if (file_system_context_.get() &&
134      !file_system_context_->default_file_task_runner()
135           ->RunsTasksOnCurrentThread()) {
136    file_system_context_->default_file_task_runner()->DeleteSoon(FROM_HERE,
137                                                                 this);
138  } else {
139    // We're on the right thread to delete, or unit test.
140    delete this;
141  }
142}
143
144}  // namespace content
145