OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "webkit/fileapi/quota_file_util.h" | 5 #include "webkit/fileapi/quota_file_util.h" |
6 | 6 |
7 #include "base/file_util.h" | 7 #include "base/file_util.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "webkit/fileapi/file_system_context.h" | 9 #include "webkit/fileapi/file_system_context.h" |
10 #include "webkit/fileapi/file_system_operation_context.h" | 10 #include "webkit/fileapi/file_system_operation_context.h" |
11 #include "webkit/fileapi/file_system_path_manager.h" | 11 #include "webkit/fileapi/file_system_path_manager.h" |
12 #include "webkit/fileapi/file_system_quota_util.h" | 12 #include "webkit/fileapi/file_system_quota_util.h" |
13 #include "webkit/quota/quota_manager.h" | 13 #include "webkit/quota/quota_manager.h" |
14 | 14 |
15 using quota::QuotaManagerProxy; | 15 using quota::QuotaManagerProxy; |
16 | 16 |
17 namespace fileapi { | 17 namespace fileapi { |
18 | 18 |
19 const int64 QuotaFileUtil::kNoLimit = kint64max; | 19 const int64 QuotaFileUtil::kNoLimit = kint64max; |
20 | 20 |
21 // See the comment in the header file as for these constants. | 21 namespace { |
22 const int64 QuotaFileUtil::kFilePathCostPerChar = 2; | |
23 const int64 QuotaFileUtil::kFilePathCostPerFile = 146; | |
24 | 22 |
25 namespace { | 23 // Checks if copying in the same filesystem can be performed. |
| 24 // This method is not called for moving within a single filesystem. |
| 25 bool CanCopy( |
| 26 const FilePath& src_file_path, |
| 27 const FilePath& dest_file_path, |
| 28 int64 allowed_bytes_growth, |
| 29 int64* growth) { |
| 30 base::PlatformFileInfo src_file_info; |
| 31 if (!file_util::GetFileInfo(src_file_path, &src_file_info)) { |
| 32 // Falling through to the actual copy/move operation. |
| 33 return true; |
| 34 } |
| 35 base::PlatformFileInfo dest_file_info; |
| 36 if (!file_util::GetFileInfo(dest_file_path, &dest_file_info)) |
| 37 dest_file_info.size = 0; |
| 38 if (allowed_bytes_growth != QuotaFileUtil::kNoLimit && |
| 39 src_file_info.size - dest_file_info.size > allowed_bytes_growth) |
| 40 return false; |
| 41 if (growth != NULL) |
| 42 *growth = src_file_info.size - dest_file_info.size; |
| 43 |
| 44 return true; |
| 45 } |
26 | 46 |
27 // A helper class to hook quota_util() methods before and after modifications. | 47 // A helper class to hook quota_util() methods before and after modifications. |
28 class ScopedOriginUpdateHelper { | 48 class ScopedOriginUpdateHelper { |
29 public: | 49 public: |
30 explicit ScopedOriginUpdateHelper( | 50 explicit ScopedOriginUpdateHelper( |
31 FileSystemOperationContext* operation_context, | 51 FileSystemOperationContext* operation_context, |
32 const GURL& origin_url, | 52 const GURL& origin_url, |
33 FileSystemType type) | 53 FileSystemType type) |
34 : operation_context_(operation_context), | 54 : operation_context_(operation_context), |
35 origin_url_(origin_url), | 55 origin_url_(origin_url), |
36 type_(type) { | 56 type_(type) { |
37 DCHECK(operation_context_); | 57 DCHECK(operation_context_); |
38 DCHECK(operation_context_->file_system_context()); | 58 DCHECK(operation_context_->file_system_context()); |
39 DCHECK(type != kFileSystemTypeUnknown); | 59 DCHECK(type != kFileSystemTypeUnknown); |
40 quota_util_ = | 60 quota_util_ = |
41 operation_context_->file_system_context()->GetQuotaUtil(type_); | 61 operation_context_->file_system_context()->GetQuotaUtil(type_); |
42 quota_manager_proxy_ = | 62 quota_manager_proxy_ = |
43 operation_context_->file_system_context()->quota_manager_proxy(); | 63 operation_context_->file_system_context()->quota_manager_proxy(); |
44 if (quota_util_) | 64 if (quota_util_) |
45 quota_util_->StartUpdateOriginOnFileThread(origin_url_, type_); | 65 quota_util_->StartUpdateOriginOnFileThread(origin_url_, type_); |
46 } | 66 } |
47 | 67 |
48 ~ScopedOriginUpdateHelper() { | 68 ~ScopedOriginUpdateHelper() { |
49 if (quota_util_) | 69 if (quota_util_) |
50 quota_util_->EndUpdateOriginOnFileThread(origin_url_, type_); | 70 quota_util_->EndUpdateOriginOnFileThread(origin_url_, type_); |
51 } | 71 } |
52 | 72 |
53 void NotifyUpdate(int64 growth) { | 73 void NotifyUpdate(int64 growth) { |
54 if (operation_context_->allowed_bytes_growth() != QuotaFileUtil::kNoLimit) | 74 operation_context_->set_allowed_bytes_growth( |
55 operation_context_->set_allowed_bytes_growth( | 75 operation_context_->allowed_bytes_growth() - growth); |
56 operation_context_->allowed_bytes_growth() - growth); | |
57 if (quota_util_) | 76 if (quota_util_) |
58 quota_util_->UpdateOriginUsageOnFileThread( | 77 quota_util_->UpdateOriginUsageOnFileThread( |
59 quota_manager_proxy_, origin_url_, type_, growth); | 78 quota_manager_proxy_, origin_url_, type_, growth); |
60 } | 79 } |
61 | 80 |
62 private: | 81 private: |
63 FileSystemOperationContext* operation_context_; | 82 FileSystemOperationContext* operation_context_; |
64 FileSystemQuotaUtil* quota_util_; | 83 FileSystemQuotaUtil* quota_util_; |
65 QuotaManagerProxy* quota_manager_proxy_; | 84 QuotaManagerProxy* quota_manager_proxy_; |
66 const GURL& origin_url_; | 85 const GURL& origin_url_; |
67 FileSystemType type_; | 86 FileSystemType type_; |
68 DISALLOW_COPY_AND_ASSIGN(ScopedOriginUpdateHelper); | 87 DISALLOW_COPY_AND_ASSIGN(ScopedOriginUpdateHelper); |
69 }; | 88 }; |
70 | 89 |
71 } // namespace (anonymous) | 90 } // namespace (anonymous) |
72 | 91 |
73 QuotaFileUtil::QuotaFileUtil(FileSystemFileUtil* underlying_file_util) | 92 QuotaFileUtil::QuotaFileUtil(FileSystemFileUtil* underlying_file_util) |
74 : underlying_file_util_(underlying_file_util) { | 93 : underlying_file_util_(underlying_file_util) { |
75 } | 94 } |
76 | 95 |
77 QuotaFileUtil::~QuotaFileUtil() { | 96 QuotaFileUtil::~QuotaFileUtil() { |
78 } | 97 } |
79 | 98 |
80 // static | 99 // static |
81 QuotaFileUtil* QuotaFileUtil::CreateDefault() { | 100 QuotaFileUtil* QuotaFileUtil::CreateDefault() { |
82 return new QuotaFileUtil(new FileSystemFileUtil()); | 101 return new QuotaFileUtil(new FileSystemFileUtil()); |
83 } | 102 } |
84 | 103 |
85 int64 QuotaFileUtil::ComputeFilePathCost(const FilePath& file_path) const { | |
86 return kFilePathCostPerFile + | |
87 file_path.BaseName().value().length() * kFilePathCostPerChar; | |
88 } | |
89 | |
90 PlatformFileError QuotaFileUtil::CreateOrOpen( | |
91 FileSystemOperationContext* fs_context, | |
92 const FilePath& file_path, int file_flags, | |
93 PlatformFile* file_handle, bool* created) { | |
94 DCHECK(fs_context); | |
95 scoped_ptr<ScopedOriginUpdateHelper> helper; | |
96 | |
97 int64 allowed_bytes_growth = fs_context->allowed_bytes_growth(); | |
98 int64 growth = 0; | |
99 | |
100 if (!file_util::PathExists(file_path)) | |
101 growth = ComputeFilePathCost(fs_context->src_virtual_path()); | |
102 | |
103 if (growth > 0) { | |
104 helper.reset(new ScopedOriginUpdateHelper( | |
105 fs_context, | |
106 fs_context->src_origin_url(), | |
107 fs_context->src_type())); | |
108 | |
109 if (allowed_bytes_growth != kNoLimit && growth > allowed_bytes_growth) | |
110 return base::PLATFORM_FILE_ERROR_NO_SPACE; | |
111 } | |
112 | |
113 base::PlatformFileError error = underlying_file_util_->CreateOrOpen( | |
114 fs_context, file_path, file_flags, file_handle, created); | |
115 | |
116 if (growth > 0) { | |
117 if (error == base::PLATFORM_FILE_OK) | |
118 helper->NotifyUpdate(growth); | |
119 } | |
120 | |
121 return error; | |
122 } | |
123 | |
124 PlatformFileError QuotaFileUtil::EnsureFileExists( | |
125 FileSystemOperationContext* fs_context, | |
126 const FilePath& file_path, | |
127 bool* created) { | |
128 DCHECK(fs_context); | |
129 scoped_ptr<ScopedOriginUpdateHelper> helper; | |
130 | |
131 int64 allowed_bytes_growth = fs_context->allowed_bytes_growth(); | |
132 int64 growth = 0; | |
133 | |
134 if (!file_util::PathExists(file_path)) | |
135 growth = ComputeFilePathCost(fs_context->src_virtual_path()); | |
136 | |
137 if (growth > 0) { | |
138 helper.reset(new ScopedOriginUpdateHelper( | |
139 fs_context, | |
140 fs_context->src_origin_url(), | |
141 fs_context->src_type())); | |
142 | |
143 if (allowed_bytes_growth != kNoLimit && growth > allowed_bytes_growth) | |
144 return base::PLATFORM_FILE_ERROR_NO_SPACE; | |
145 } | |
146 | |
147 base::PlatformFileError error = underlying_file_util_->EnsureFileExists( | |
148 fs_context, file_path, created); | |
149 | |
150 if (growth > 0 &&error == base::PLATFORM_FILE_OK) | |
151 helper->NotifyUpdate(growth); | |
152 | |
153 return error; | |
154 } | |
155 | |
156 PlatformFileError QuotaFileUtil::CreateDirectory( | |
157 FileSystemOperationContext* fs_context, | |
158 const FilePath& file_path, | |
159 bool exclusive, | |
160 bool recursive) { | |
161 DCHECK(fs_context); | |
162 scoped_ptr<ScopedOriginUpdateHelper> helper; | |
163 | |
164 int64 allowed_bytes_growth = fs_context->allowed_bytes_growth(); | |
165 int64 growth = 0; | |
166 | |
167 if (!exclusive || !file_util::PathExists(file_path)) { | |
168 if (recursive) { | |
169 FilePath last_path; | |
170 for (FilePath path = fs_context->src_virtual_path(); | |
171 path.value() != last_path.value() && | |
172 !fs_context->src_file_system_file_util()->PathExists( | |
173 fs_context, fs_context->src_virtual_path()); | |
174 path = path.DirName()) { | |
175 growth += ComputeFilePathCost(fs_context->src_virtual_path()); | |
176 last_path = path; | |
177 } | |
178 } else { | |
179 growth += ComputeFilePathCost(fs_context->src_virtual_path()); | |
180 } | |
181 } | |
182 | |
183 if (growth > 0) { | |
184 helper.reset(new ScopedOriginUpdateHelper( | |
185 fs_context, | |
186 fs_context->src_origin_url(), | |
187 fs_context->src_type())); | |
188 | |
189 if (allowed_bytes_growth != kNoLimit && growth > allowed_bytes_growth) | |
190 return base::PLATFORM_FILE_ERROR_NO_SPACE; | |
191 } | |
192 | |
193 base::PlatformFileError error = base::PLATFORM_FILE_OK; | |
194 error = underlying_file_util_->CreateDirectory( | |
195 fs_context, file_path, exclusive, recursive); | |
196 | |
197 if (growth > 0 && error == base::PLATFORM_FILE_OK) | |
198 helper->NotifyUpdate(growth); | |
199 | |
200 return error; | |
201 } | |
202 | |
203 base::PlatformFileError QuotaFileUtil::CopyOrMoveFile( | 104 base::PlatformFileError QuotaFileUtil::CopyOrMoveFile( |
204 FileSystemOperationContext* fs_context, | 105 FileSystemOperationContext* fs_context, |
205 const FilePath& src_file_path, | 106 const FilePath& src_file_path, |
206 const FilePath& dest_file_path, | 107 const FilePath& dest_file_path, |
207 bool copy) { | 108 bool copy) { |
208 DCHECK(fs_context); | 109 DCHECK(fs_context); |
209 | 110 |
210 // TODO(kinuko): For cross-filesystem move case we need 2 helpers, one for | 111 // TODO(kinuko): For cross-filesystem move case we need 2 helpers, one for |
211 // src and one for dest. | 112 // src and one for dest. |
212 ScopedOriginUpdateHelper helper( | 113 ScopedOriginUpdateHelper helper( |
213 fs_context, | 114 fs_context, |
214 fs_context->dest_origin_url(), | 115 fs_context->dest_origin_url(), |
215 fs_context->dest_type()); | 116 fs_context->dest_type()); |
216 | 117 |
217 int64 growth = 0; | 118 int64 growth = 0; |
218 | 119 |
219 // It assumes copy/move operations are always in the same fs currently. | 120 // It assumes copy/move operations are always in the same fs currently. |
220 // TODO(dmikurube): Do quota check if moving between different fs. | 121 // TODO(dmikurube): Do quota check if moving between different fs. |
221 if (copy) { | 122 if (copy) { |
222 int64 allowed_bytes_growth = fs_context->allowed_bytes_growth(); | 123 int64 allowed_bytes_growth = fs_context->allowed_bytes_growth(); |
223 // The third argument (growth) is not used for now. | 124 // The third argument (growth) is not used for now. |
224 if (!CanCopyFile(fs_context, src_file_path, dest_file_path, | 125 if (!CanCopy(src_file_path, dest_file_path, allowed_bytes_growth, &growth)) |
225 allowed_bytes_growth, &growth)) | |
226 return base::PLATFORM_FILE_ERROR_NO_SPACE; | 126 return base::PLATFORM_FILE_ERROR_NO_SPACE; |
227 } else { // move | 127 } else { |
228 int64 allowed_bytes_growth = fs_context->allowed_bytes_growth(); | |
229 base::PlatformFileInfo dest_file_info; | 128 base::PlatformFileInfo dest_file_info; |
230 int64 src_file_path_cost = | |
231 ComputeFilePathCost(fs_context->src_virtual_path()); | |
232 int64 dest_file_path_cost = | |
233 ComputeFilePathCost(fs_context->dest_virtual_path()); | |
234 if (!file_util::GetFileInfo(dest_file_path, &dest_file_info)) | 129 if (!file_util::GetFileInfo(dest_file_path, &dest_file_info)) |
235 dest_file_info.size = 0; | 130 dest_file_info.size = 0; |
236 growth = -dest_file_info.size - src_file_path_cost + dest_file_path_cost; | 131 growth = -dest_file_info.size; |
237 if (allowed_bytes_growth != kNoLimit && growth > allowed_bytes_growth) | |
238 return base::PLATFORM_FILE_ERROR_NO_SPACE; | |
239 } | 132 } |
240 | 133 |
241 base::PlatformFileError error = underlying_file_util_->CopyOrMoveFile( | 134 base::PlatformFileError error = underlying_file_util_->CopyOrMoveFile( |
242 fs_context, src_file_path, dest_file_path, copy); | 135 fs_context, src_file_path, dest_file_path, copy); |
243 | 136 |
244 if (error == base::PLATFORM_FILE_OK) { | 137 if (error == base::PLATFORM_FILE_OK) { |
245 // TODO(kinuko): For cross-filesystem move case, call this with -growth | 138 // TODO(kinuko): For cross-filesystem move case, call this with -growth |
246 // for source and growth for dest. | 139 // for source and growth for dest. |
247 helper.NotifyUpdate(growth); | 140 helper.NotifyUpdate(growth); |
248 } | 141 } |
249 | 142 |
250 return error; | 143 return error; |
251 } | 144 } |
252 | 145 |
253 base::PlatformFileError QuotaFileUtil::DeleteFile( | 146 base::PlatformFileError QuotaFileUtil::DeleteFile( |
254 FileSystemOperationContext* fs_context, | 147 FileSystemOperationContext* fs_context, |
255 const FilePath& file_path) { | 148 const FilePath& file_path) { |
256 DCHECK(fs_context); | 149 DCHECK(fs_context); |
257 ScopedOriginUpdateHelper helper( | 150 ScopedOriginUpdateHelper helper( |
258 fs_context, | 151 fs_context, |
259 fs_context->src_origin_url(), | 152 fs_context->src_origin_url(), |
260 fs_context->src_type()); | 153 fs_context->src_type()); |
261 | 154 |
262 int64 growth = 0; | 155 int64 growth = 0; |
263 base::PlatformFileInfo file_info; | 156 base::PlatformFileInfo file_info; |
264 if (file_util::GetFileInfo(file_path, &file_info)) { | 157 if (!file_util::GetFileInfo(file_path, &file_info)) |
265 growth -= file_info.size + | 158 file_info.size = 0; |
266 ComputeFilePathCost(fs_context->src_virtual_path()); | 159 growth = -file_info.size; |
267 } | |
268 | 160 |
269 base::PlatformFileError error = underlying_file_util_->DeleteFile( | 161 base::PlatformFileError error = underlying_file_util_->DeleteFile( |
270 fs_context, file_path); | 162 fs_context, file_path); |
271 | 163 |
272 if (error == base::PLATFORM_FILE_OK) | 164 if (error == base::PLATFORM_FILE_OK) |
273 helper.NotifyUpdate(growth); | 165 helper.NotifyUpdate(growth); |
274 | 166 |
275 return error; | 167 return error; |
276 } | 168 } |
277 | 169 |
278 base::PlatformFileError QuotaFileUtil::DeleteSingleDirectory( | |
279 FileSystemOperationContext* fs_context, | |
280 const FilePath& file_path) { | |
281 DCHECK(fs_context); | |
282 ScopedOriginUpdateHelper helper( | |
283 fs_context, | |
284 fs_context->src_origin_url(), | |
285 fs_context->src_type()); | |
286 | |
287 int64 growth = 0; | |
288 if (file_util::DirectoryExists(file_path)) | |
289 growth -= ComputeFilePathCost(fs_context->src_virtual_path()); | |
290 | |
291 base::PlatformFileError error = underlying_file_util_->DeleteSingleDirectory( | |
292 fs_context, file_path); | |
293 | |
294 if (error == base::PLATFORM_FILE_OK) | |
295 helper.NotifyUpdate(growth); | |
296 | |
297 return error; | |
298 } | |
299 | |
300 base::PlatformFileError QuotaFileUtil::Truncate( | 170 base::PlatformFileError QuotaFileUtil::Truncate( |
301 FileSystemOperationContext* fs_context, | 171 FileSystemOperationContext* fs_context, |
302 const FilePath& path, | 172 const FilePath& path, |
303 int64 length) { | 173 int64 length) { |
304 int64 allowed_bytes_growth = fs_context->allowed_bytes_growth(); | 174 int64 allowed_bytes_growth = fs_context->allowed_bytes_growth(); |
305 ScopedOriginUpdateHelper helper( | 175 ScopedOriginUpdateHelper helper( |
306 fs_context, | 176 fs_context, |
307 fs_context->src_origin_url(), | 177 fs_context->src_origin_url(), |
308 fs_context->src_type()); | 178 fs_context->src_type()); |
309 | 179 |
310 int64 growth = 0; | 180 int64 growth = 0; |
311 base::PlatformFileInfo file_info; | 181 base::PlatformFileInfo file_info; |
312 if (!file_util::GetFileInfo(path, &file_info)) | 182 if (!file_util::GetFileInfo(path, &file_info)) |
313 return base::PLATFORM_FILE_ERROR_FAILED; | 183 return base::PLATFORM_FILE_ERROR_FAILED; |
314 | 184 |
315 growth = length - file_info.size; | 185 growth = length - file_info.size; |
316 if (allowed_bytes_growth != kNoLimit && growth > allowed_bytes_growth) | 186 if (allowed_bytes_growth != kNoLimit && growth > allowed_bytes_growth) |
317 return base::PLATFORM_FILE_ERROR_NO_SPACE; | 187 return base::PLATFORM_FILE_ERROR_NO_SPACE; |
318 | 188 |
319 base::PlatformFileError error = underlying_file_util_->Truncate( | 189 base::PlatformFileError error = underlying_file_util_->Truncate( |
320 fs_context, path, length); | 190 fs_context, path, length); |
321 | 191 |
322 if (error == base::PLATFORM_FILE_OK) | 192 if (error == base::PLATFORM_FILE_OK) |
323 helper.NotifyUpdate(growth); | 193 helper.NotifyUpdate(growth); |
324 | 194 |
325 return error; | 195 return error; |
326 } | 196 } |
327 | 197 |
328 // Checks if copying in the same filesystem can be performed. | |
329 // This method is not called for moving within a single filesystem. | |
330 bool QuotaFileUtil::CanCopyFile( | |
331 FileSystemOperationContext* fs_context, | |
332 const FilePath& src_file_path, | |
333 const FilePath& dest_file_path, | |
334 int64 allowed_bytes_growth, | |
335 int64* growth) const { | |
336 DCHECK(growth); | |
337 base::PlatformFileInfo src_file_info; | |
338 if (!file_util::GetFileInfo(src_file_path, &src_file_info)) { | |
339 // Falling through to the actual copy/move operation. | |
340 return true; | |
341 } | |
342 base::PlatformFileInfo dest_file_info; | |
343 int dest_file_path_cost = 0; | |
344 if (!file_util::GetFileInfo(dest_file_path, &dest_file_info)) { | |
345 dest_file_info.size = 0; | |
346 dest_file_path_cost = ComputeFilePathCost(fs_context->dest_virtual_path()); | |
347 } | |
348 *growth = src_file_info.size - dest_file_info.size + dest_file_path_cost; | |
349 if (allowed_bytes_growth != QuotaFileUtil::kNoLimit && | |
350 *growth > allowed_bytes_growth) | |
351 return false; | |
352 | |
353 return true; | |
354 } | |
355 | |
356 } // namespace fileapi | 198 } // namespace fileapi |
OLD | NEW |