OLD | NEW |
| (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_mount_point_provider.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/command_line.h" | |
9 #include "base/file_util.h" | |
10 #include "base/logging.h" | |
11 #include "base/memory/scoped_ptr.h" | |
12 #include "base/metrics/histogram.h" | |
13 #include "base/stl_util.h" | |
14 #include "base/task_runner_util.h" | |
15 #include "googleurl/src/gurl.h" | |
16 #include "net/base/net_util.h" | |
17 #include "webkit/browser/fileapi/file_system_usage_cache.h" | |
18 #include "webkit/fileapi/async_file_util_adapter.h" | |
19 #include "webkit/fileapi/copy_or_move_file_validator.h" | |
20 #include "webkit/fileapi/file_system_context.h" | |
21 #include "webkit/fileapi/file_system_file_stream_reader.h" | |
22 #include "webkit/fileapi/file_system_operation_context.h" | |
23 #include "webkit/fileapi/file_system_options.h" | |
24 #include "webkit/fileapi/file_system_task_runners.h" | |
25 #include "webkit/fileapi/file_system_types.h" | |
26 #include "webkit/fileapi/file_system_util.h" | |
27 #include "webkit/fileapi/local_file_system_operation.h" | |
28 #include "webkit/fileapi/obfuscated_file_util.h" | |
29 #include "webkit/fileapi/sandbox_file_stream_writer.h" | |
30 #include "webkit/fileapi/sandbox_quota_observer.h" | |
31 #include "webkit/fileapi/syncable/syncable_file_system_operation.h" | |
32 #include "webkit/quota/quota_manager.h" | |
33 | |
34 using quota::QuotaManagerProxy; | |
35 | |
36 namespace fileapi { | |
37 | |
38 namespace { | |
39 | |
40 const char kChromeScheme[] = "chrome"; | |
41 const char kExtensionScheme[] = "chrome-extension"; | |
42 | |
43 const char kOpenFileSystemLabel[] = "FileSystem.OpenFileSystem"; | |
44 const char kOpenFileSystemDetailLabel[] = "FileSystem.OpenFileSystemDetail"; | |
45 const char kOpenFileSystemDetailNonThrottledLabel[] = | |
46 "FileSystem.OpenFileSystemDetailNonthrottled"; | |
47 int64 kMinimumStatsCollectionIntervalHours = 1; | |
48 | |
49 // A command line switch to disable usage tracking. | |
50 const char kDisableUsageTracking[] = "disable-file-system-usage-tracking"; | |
51 | |
52 enum FileSystemError { | |
53 kOK = 0, | |
54 kIncognito, | |
55 kInvalidSchemeError, | |
56 kCreateDirectoryError, | |
57 kNotFound, | |
58 kUnknownError, | |
59 kFileSystemErrorMax, | |
60 }; | |
61 | |
62 const char kTemporaryOriginsCountLabel[] = "FileSystem.TemporaryOriginsCount"; | |
63 const char kPersistentOriginsCountLabel[] = "FileSystem.PersistentOriginsCount"; | |
64 const char kSyncableOriginsCountLabel[] = "FileSystem.SyncableOriginsCount"; | |
65 | |
66 // Restricted names. | |
67 // http://dev.w3.org/2009/dap/file-system/file-dir-sys.html#naming-restrictions | |
68 const base::FilePath::CharType* const kRestrictedNames[] = { | |
69 FILE_PATH_LITERAL("."), FILE_PATH_LITERAL(".."), | |
70 }; | |
71 | |
72 // Restricted chars. | |
73 const base::FilePath::CharType kRestrictedChars[] = { | |
74 FILE_PATH_LITERAL('/'), FILE_PATH_LITERAL('\\'), | |
75 }; | |
76 | |
77 class ObfuscatedOriginEnumerator | |
78 : public SandboxMountPointProvider::OriginEnumerator { | |
79 public: | |
80 explicit ObfuscatedOriginEnumerator(ObfuscatedFileUtil* file_util) { | |
81 enum_.reset(file_util->CreateOriginEnumerator()); | |
82 } | |
83 virtual ~ObfuscatedOriginEnumerator() {} | |
84 | |
85 virtual GURL Next() OVERRIDE { | |
86 return enum_->Next(); | |
87 } | |
88 | |
89 virtual bool HasFileSystemType(fileapi::FileSystemType type) const OVERRIDE { | |
90 return enum_->HasFileSystemType(type); | |
91 } | |
92 | |
93 private: | |
94 scoped_ptr<ObfuscatedFileUtil::AbstractOriginEnumerator> enum_; | |
95 }; | |
96 | |
97 void DidValidateFileSystemRoot( | |
98 base::WeakPtr<SandboxMountPointProvider> mount_point_provider, | |
99 const FileSystemMountPointProvider::ValidateFileSystemCallback& callback, | |
100 base::PlatformFileError* error) { | |
101 if (mount_point_provider) | |
102 mount_point_provider.get()->CollectOpenFileSystemMetrics(*error); | |
103 callback.Run(*error); | |
104 } | |
105 | |
106 void ValidateRootOnFileThread( | |
107 ObfuscatedFileUtil* file_util, | |
108 const GURL& origin_url, | |
109 FileSystemType type, | |
110 bool create, | |
111 base::PlatformFileError* error_ptr) { | |
112 DCHECK(error_ptr); | |
113 | |
114 base::FilePath root_path = | |
115 file_util->GetDirectoryForOriginAndType( | |
116 origin_url, type, create, error_ptr); | |
117 if (*error_ptr != base::PLATFORM_FILE_OK) { | |
118 UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemLabel, | |
119 kCreateDirectoryError, | |
120 kFileSystemErrorMax); | |
121 } else { | |
122 UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemLabel, kOK, kFileSystemErrorMax); | |
123 } | |
124 // The reference of file_util will be derefed on the FILE thread | |
125 // when the storage of this callback gets deleted regardless of whether | |
126 // this method is called or not. | |
127 } | |
128 | |
129 } // anonymous namespace | |
130 | |
131 const base::FilePath::CharType | |
132 SandboxMountPointProvider::kFileSystemDirectory[] = | |
133 FILE_PATH_LITERAL("File System"); | |
134 | |
135 // static | |
136 bool SandboxMountPointProvider::IsSandboxType(FileSystemType type) { | |
137 return type == kFileSystemTypeTemporary || | |
138 type == kFileSystemTypePersistent || | |
139 type == kFileSystemTypeSyncable; | |
140 } | |
141 | |
142 SandboxMountPointProvider::SandboxMountPointProvider( | |
143 quota::QuotaManagerProxy* quota_manager_proxy, | |
144 base::SequencedTaskRunner* file_task_runner, | |
145 const base::FilePath& profile_path, | |
146 const FileSystemOptions& file_system_options, | |
147 quota::SpecialStoragePolicy* special_storage_policy) | |
148 : file_task_runner_(file_task_runner), | |
149 profile_path_(profile_path), | |
150 file_system_options_(file_system_options), | |
151 enable_temporary_file_system_in_incognito_(false), | |
152 sandbox_file_util_( | |
153 new AsyncFileUtilAdapter( | |
154 new ObfuscatedFileUtil( | |
155 profile_path.Append(kFileSystemDirectory)))), | |
156 file_system_usage_cache_(new FileSystemUsageCache(file_task_runner)), | |
157 quota_observer_(new SandboxQuotaObserver( | |
158 quota_manager_proxy, | |
159 file_task_runner, | |
160 sandbox_sync_file_util(), | |
161 file_system_usage_cache_.get())), | |
162 enable_usage_tracking_( | |
163 !CommandLine::ForCurrentProcess()->HasSwitch( | |
164 kDisableUsageTracking)), | |
165 special_storage_policy_(special_storage_policy), | |
166 weak_factory_(this) { | |
167 // Set quota observers. | |
168 UpdateObserverList::Source update_observers_src; | |
169 AccessObserverList::Source access_observers_src; | |
170 | |
171 if (enable_usage_tracking_) { | |
172 update_observers_src.AddObserver(quota_observer_.get(), file_task_runner_); | |
173 access_observers_src.AddObserver(quota_observer_.get(), NULL); | |
174 } | |
175 | |
176 update_observers_ = UpdateObserverList(update_observers_src); | |
177 access_observers_ = AccessObserverList(access_observers_src); | |
178 syncable_update_observers_ = UpdateObserverList(update_observers_src); | |
179 } | |
180 | |
181 SandboxMountPointProvider::~SandboxMountPointProvider() { | |
182 if (!file_task_runner_->RunsTasksOnCurrentThread()) { | |
183 AsyncFileUtilAdapter* sandbox_file_util = sandbox_file_util_.release(); | |
184 SandboxQuotaObserver* quota_observer = quota_observer_.release(); | |
185 FileSystemUsageCache* file_system_usage_cache = | |
186 file_system_usage_cache_.release(); | |
187 if (!file_task_runner_->DeleteSoon(FROM_HERE, sandbox_file_util)) | |
188 delete sandbox_file_util; | |
189 if (!file_task_runner_->DeleteSoon(FROM_HERE, quota_observer)) | |
190 delete quota_observer; | |
191 if (!file_task_runner_->DeleteSoon(FROM_HERE, file_system_usage_cache)) | |
192 delete file_system_usage_cache; | |
193 } | |
194 } | |
195 | |
196 bool SandboxMountPointProvider::CanHandleType(FileSystemType type) const { | |
197 return IsSandboxType(type); | |
198 } | |
199 | |
200 void SandboxMountPointProvider::ValidateFileSystemRoot( | |
201 const GURL& origin_url, fileapi::FileSystemType type, bool create, | |
202 const ValidateFileSystemCallback& callback) { | |
203 if (file_system_options_.is_incognito() && | |
204 !(type == kFileSystemTypeTemporary && | |
205 enable_temporary_file_system_in_incognito_)) { | |
206 // TODO(kinuko): return an isolated temporary directory. | |
207 callback.Run(base::PLATFORM_FILE_ERROR_SECURITY); | |
208 UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemLabel, | |
209 kIncognito, | |
210 kFileSystemErrorMax); | |
211 return; | |
212 } | |
213 | |
214 if (!IsAllowedScheme(origin_url)) { | |
215 callback.Run(base::PLATFORM_FILE_ERROR_SECURITY); | |
216 UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemLabel, | |
217 kInvalidSchemeError, | |
218 kFileSystemErrorMax); | |
219 return; | |
220 } | |
221 | |
222 base::PlatformFileError* error_ptr = new base::PlatformFileError; | |
223 file_task_runner_->PostTaskAndReply( | |
224 FROM_HERE, | |
225 base::Bind(&ValidateRootOnFileThread, | |
226 sandbox_sync_file_util(), | |
227 origin_url, type, create, | |
228 base::Unretained(error_ptr)), | |
229 base::Bind(&DidValidateFileSystemRoot, | |
230 weak_factory_.GetWeakPtr(), | |
231 callback, base::Owned(error_ptr))); | |
232 | |
233 if (enable_usage_tracking_) | |
234 return; | |
235 | |
236 // Schedule full usage recalculation on the next launch without | |
237 // --disable-file-system-usage-tracking. | |
238 file_task_runner_->PostTask( | |
239 FROM_HERE, | |
240 base::Bind(&SandboxMountPointProvider::InvalidateUsageCacheOnFileThread, | |
241 sandbox_sync_file_util(), origin_url, type, | |
242 file_system_usage_cache_.get())); | |
243 }; | |
244 | |
245 base::FilePath | |
246 SandboxMountPointProvider::GetFileSystemRootPathOnFileThread( | |
247 const FileSystemURL& url, | |
248 bool create) { | |
249 if (file_system_options_.is_incognito() && | |
250 !(enable_temporary_file_system_in_incognito_ && | |
251 url.type() == kFileSystemTypeTemporary)) { | |
252 // TODO(kinuko): return an isolated temporary directory. | |
253 return base::FilePath(); | |
254 } | |
255 | |
256 if (!IsAllowedScheme(url.origin())) | |
257 return base::FilePath(); | |
258 | |
259 return GetBaseDirectoryForOriginAndType(url.origin(), url.type(), create); | |
260 } | |
261 | |
262 FileSystemFileUtil* SandboxMountPointProvider::GetFileUtil( | |
263 FileSystemType type) { | |
264 DCHECK(sandbox_file_util_.get()); | |
265 return sandbox_file_util_->sync_file_util(); | |
266 } | |
267 | |
268 AsyncFileUtil* SandboxMountPointProvider::GetAsyncFileUtil( | |
269 FileSystemType type) { | |
270 return sandbox_file_util_.get(); | |
271 } | |
272 | |
273 CopyOrMoveFileValidatorFactory* | |
274 SandboxMountPointProvider::GetCopyOrMoveFileValidatorFactory( | |
275 FileSystemType type, | |
276 base::PlatformFileError* error_code) { | |
277 DCHECK(error_code); | |
278 *error_code = base::PLATFORM_FILE_OK; | |
279 return NULL; | |
280 } | |
281 | |
282 void SandboxMountPointProvider::InitializeCopyOrMoveFileValidatorFactory( | |
283 FileSystemType type, | |
284 scoped_ptr<CopyOrMoveFileValidatorFactory> factory) { | |
285 DCHECK(!factory); | |
286 } | |
287 | |
288 FilePermissionPolicy SandboxMountPointProvider::GetPermissionPolicy( | |
289 const FileSystemURL& url, int permissions) const { | |
290 if (!CanHandleType(url.type()) || !IsAllowedScheme(url.origin())) | |
291 return FILE_PERMISSION_ALWAYS_DENY; | |
292 | |
293 if (url.path().ReferencesParent()) | |
294 return FILE_PERMISSION_ALWAYS_DENY; | |
295 | |
296 // Any write access is disallowed on the root path. | |
297 if ((url.path().empty() || VirtualPath::DirName(url.path()) == url.path()) | |
298 && (permissions & ~kReadFilePermissions)) | |
299 return FILE_PERMISSION_ALWAYS_DENY; | |
300 | |
301 if ((permissions & kCreateFilePermissions) == kCreateFilePermissions) { | |
302 base::FilePath filename = VirtualPath::BaseName(url.path()); | |
303 // See if the name is allowed to create. | |
304 for (size_t i = 0; i < arraysize(kRestrictedNames); ++i) { | |
305 if (filename.value() == kRestrictedNames[i]) | |
306 return FILE_PERMISSION_ALWAYS_DENY; | |
307 } | |
308 for (size_t i = 0; i < arraysize(kRestrictedChars); ++i) { | |
309 if (filename.value().find(kRestrictedChars[i]) != | |
310 base::FilePath::StringType::npos) | |
311 return FILE_PERMISSION_ALWAYS_DENY; | |
312 } | |
313 } | |
314 | |
315 // Access to the sandbox directory (and only to the directory) should be | |
316 // always allowed. | |
317 return FILE_PERMISSION_ALWAYS_ALLOW; | |
318 } | |
319 | |
320 FileSystemOperation* SandboxMountPointProvider::CreateFileSystemOperation( | |
321 const FileSystemURL& url, | |
322 FileSystemContext* context, | |
323 base::PlatformFileError* error_code) const { | |
324 scoped_ptr<FileSystemOperationContext> operation_context( | |
325 new FileSystemOperationContext(context)); | |
326 | |
327 // Copy the observer lists (assuming we only have small number of observers). | |
328 if (url.type() == kFileSystemTypeSyncable) { | |
329 operation_context->set_update_observers(syncable_update_observers_); | |
330 operation_context->set_change_observers(syncable_change_observers_); | |
331 operation_context->set_access_observers(access_observers_); | |
332 return new sync_file_system::SyncableFileSystemOperation( | |
333 context, operation_context.Pass()); | |
334 } | |
335 | |
336 // For regular sandboxed types. | |
337 operation_context->set_update_observers(update_observers_); | |
338 operation_context->set_access_observers(access_observers_); | |
339 | |
340 if (special_storage_policy_ && | |
341 special_storage_policy_->IsStorageUnlimited(url.origin())) { | |
342 operation_context->set_quota_limit_type(quota::kQuotaLimitTypeUnlimited); | |
343 } else { | |
344 operation_context->set_quota_limit_type(quota::kQuotaLimitTypeLimited); | |
345 } | |
346 | |
347 // Temporarily disable returning unlimited storage policy for non-PERSISTENT | |
348 // storage. Since it may hurt performance for all FileSystem operation. | |
349 if (url.type() != kFileSystemTypePersistent && | |
350 operation_context->quota_limit_type() == quota::kQuotaLimitTypeUnlimited) | |
351 operation_context->set_quota_limit_type(quota::kQuotaLimitTypeLimited); | |
352 | |
353 return new LocalFileSystemOperation(context, operation_context.Pass()); | |
354 } | |
355 | |
356 scoped_ptr<webkit_blob::FileStreamReader> | |
357 SandboxMountPointProvider::CreateFileStreamReader( | |
358 const FileSystemURL& url, | |
359 int64 offset, | |
360 const base::Time& expected_modification_time, | |
361 FileSystemContext* context) const { | |
362 return scoped_ptr<webkit_blob::FileStreamReader>( | |
363 new FileSystemFileStreamReader( | |
364 context, url, offset, expected_modification_time)); | |
365 } | |
366 | |
367 scoped_ptr<fileapi::FileStreamWriter> | |
368 SandboxMountPointProvider::CreateFileStreamWriter( | |
369 const FileSystemURL& url, | |
370 int64 offset, | |
371 FileSystemContext* context) const { | |
372 return scoped_ptr<fileapi::FileStreamWriter>( | |
373 new SandboxFileStreamWriter(context, url, offset, update_observers_)); | |
374 } | |
375 | |
376 FileSystemQuotaUtil* SandboxMountPointProvider::GetQuotaUtil() { | |
377 return this; | |
378 } | |
379 | |
380 void SandboxMountPointProvider::DeleteFileSystem( | |
381 const GURL& origin_url, | |
382 FileSystemType type, | |
383 FileSystemContext* context, | |
384 const DeleteFileSystemCallback& callback) { | |
385 base::PostTaskAndReplyWithResult( | |
386 context->task_runners()->file_task_runner(), | |
387 FROM_HERE, | |
388 // It is safe to pass Unretained(this) since context owns it. | |
389 base::Bind(&SandboxMountPointProvider::DeleteOriginDataOnFileThread, | |
390 base::Unretained(this), | |
391 make_scoped_refptr(context), | |
392 base::Unretained(context->quota_manager_proxy()), | |
393 origin_url, | |
394 type), | |
395 callback); | |
396 } | |
397 | |
398 SandboxMountPointProvider::OriginEnumerator* | |
399 SandboxMountPointProvider::CreateOriginEnumerator() { | |
400 return new ObfuscatedOriginEnumerator(sandbox_sync_file_util()); | |
401 } | |
402 | |
403 base::FilePath SandboxMountPointProvider::GetBaseDirectoryForOriginAndType( | |
404 const GURL& origin_url, fileapi::FileSystemType type, bool create) { | |
405 | |
406 base::PlatformFileError error = base::PLATFORM_FILE_OK; | |
407 base::FilePath path = sandbox_sync_file_util()->GetDirectoryForOriginAndType( | |
408 origin_url, type, create, &error); | |
409 if (error != base::PLATFORM_FILE_OK) | |
410 return base::FilePath(); | |
411 return path; | |
412 } | |
413 | |
414 base::PlatformFileError | |
415 SandboxMountPointProvider::DeleteOriginDataOnFileThread( | |
416 FileSystemContext* file_system_context, | |
417 QuotaManagerProxy* proxy, | |
418 const GURL& origin_url, | |
419 fileapi::FileSystemType type) { | |
420 | |
421 int64 usage = GetOriginUsageOnFileThread(file_system_context, | |
422 origin_url, type); | |
423 | |
424 file_system_usage_cache_->CloseCacheFiles(); | |
425 bool result = sandbox_sync_file_util()->DeleteDirectoryForOriginAndType( | |
426 origin_url, type); | |
427 if (result && proxy) { | |
428 proxy->NotifyStorageModified( | |
429 quota::QuotaClient::kFileSystem, | |
430 origin_url, | |
431 FileSystemTypeToQuotaStorageType(type), | |
432 -usage); | |
433 } | |
434 | |
435 if (result) | |
436 return base::PLATFORM_FILE_OK; | |
437 return base::PLATFORM_FILE_ERROR_FAILED; | |
438 } | |
439 | |
440 void SandboxMountPointProvider::GetOriginsForTypeOnFileThread( | |
441 fileapi::FileSystemType type, std::set<GURL>* origins) { | |
442 DCHECK(CanHandleType(type)); | |
443 DCHECK(origins); | |
444 scoped_ptr<OriginEnumerator> enumerator(CreateOriginEnumerator()); | |
445 GURL origin; | |
446 while (!(origin = enumerator->Next()).is_empty()) { | |
447 if (enumerator->HasFileSystemType(type)) | |
448 origins->insert(origin); | |
449 } | |
450 switch (type) { | |
451 case kFileSystemTypeTemporary: | |
452 UMA_HISTOGRAM_COUNTS(kTemporaryOriginsCountLabel, origins->size()); | |
453 break; | |
454 case kFileSystemTypePersistent: | |
455 UMA_HISTOGRAM_COUNTS(kPersistentOriginsCountLabel, origins->size()); | |
456 break; | |
457 case kFileSystemTypeSyncable: | |
458 UMA_HISTOGRAM_COUNTS(kSyncableOriginsCountLabel, origins->size()); | |
459 break; | |
460 default: | |
461 break; | |
462 } | |
463 } | |
464 | |
465 void SandboxMountPointProvider::GetOriginsForHostOnFileThread( | |
466 fileapi::FileSystemType type, const std::string& host, | |
467 std::set<GURL>* origins) { | |
468 DCHECK(CanHandleType(type)); | |
469 DCHECK(origins); | |
470 scoped_ptr<OriginEnumerator> enumerator(CreateOriginEnumerator()); | |
471 GURL origin; | |
472 while (!(origin = enumerator->Next()).is_empty()) { | |
473 if (host == net::GetHostOrSpecFromURL(origin) && | |
474 enumerator->HasFileSystemType(type)) | |
475 origins->insert(origin); | |
476 } | |
477 } | |
478 | |
479 int64 SandboxMountPointProvider::GetOriginUsageOnFileThread( | |
480 FileSystemContext* file_system_context, | |
481 const GURL& origin_url, | |
482 fileapi::FileSystemType type) { | |
483 DCHECK(CanHandleType(type)); | |
484 if (!enable_usage_tracking_) | |
485 return 0; | |
486 | |
487 // Don't use usage cache and return recalculated usage for sticky invalidated | |
488 // origins. | |
489 if (ContainsKey(sticky_dirty_origins_, std::make_pair(origin_url, type))) | |
490 return RecalculateUsage(file_system_context, origin_url, type); | |
491 | |
492 base::FilePath base_path = | |
493 GetBaseDirectoryForOriginAndType(origin_url, type, false); | |
494 if (base_path.empty() || !file_util::DirectoryExists(base_path)) | |
495 return 0; | |
496 base::FilePath usage_file_path = | |
497 base_path.Append(FileSystemUsageCache::kUsageFileName); | |
498 | |
499 bool is_valid = file_system_usage_cache_->IsValid(usage_file_path); | |
500 uint32 dirty_status = 0; | |
501 bool dirty_status_available = | |
502 file_system_usage_cache_->GetDirty(usage_file_path, &dirty_status); | |
503 bool visited = !visited_origins_.insert(origin_url).second; | |
504 if (is_valid && (dirty_status == 0 || (dirty_status_available && visited))) { | |
505 // The usage cache is clean (dirty == 0) or the origin is already | |
506 // initialized and running. Read the cache file to get the usage. | |
507 int64 usage = 0; | |
508 return file_system_usage_cache_->GetUsage(usage_file_path, &usage) ? | |
509 usage : -1; | |
510 } | |
511 // The usage cache has not been initialized or the cache is dirty. | |
512 // Get the directory size now and update the cache. | |
513 file_system_usage_cache_->Delete(usage_file_path); | |
514 | |
515 int64 usage = RecalculateUsage(file_system_context, origin_url, type); | |
516 | |
517 // This clears the dirty flag too. | |
518 file_system_usage_cache_->UpdateUsage(usage_file_path, usage); | |
519 return usage; | |
520 } | |
521 | |
522 void SandboxMountPointProvider::InvalidateUsageCache( | |
523 const GURL& origin, | |
524 fileapi::FileSystemType type) { | |
525 DCHECK(CanHandleType(type)); | |
526 base::PlatformFileError error = base::PLATFORM_FILE_OK; | |
527 base::FilePath usage_file_path = GetUsageCachePathForOriginAndType( | |
528 sandbox_sync_file_util(), origin, type, &error); | |
529 if (error != base::PLATFORM_FILE_OK) | |
530 return; | |
531 file_system_usage_cache_->IncrementDirty(usage_file_path); | |
532 } | |
533 | |
534 void SandboxMountPointProvider::StickyInvalidateUsageCache( | |
535 const GURL& origin, | |
536 fileapi::FileSystemType type) { | |
537 DCHECK(CanHandleType(type)); | |
538 sticky_dirty_origins_.insert(std::make_pair(origin, type)); | |
539 quota_observer_->SetUsageCacheEnabled(origin, type, false); | |
540 InvalidateUsageCache(origin, type); | |
541 } | |
542 | |
543 void SandboxMountPointProvider::CollectOpenFileSystemMetrics( | |
544 base::PlatformFileError error_code) { | |
545 base::Time now = base::Time::Now(); | |
546 bool throttled = now < next_release_time_for_open_filesystem_stat_; | |
547 if (!throttled) { | |
548 next_release_time_for_open_filesystem_stat_ = | |
549 now + base::TimeDelta::FromHours(kMinimumStatsCollectionIntervalHours); | |
550 } | |
551 | |
552 #define REPORT(report_value) \ | |
553 UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemDetailLabel, \ | |
554 (report_value), \ | |
555 kFileSystemErrorMax); \ | |
556 if (!throttled) { \ | |
557 UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemDetailNonThrottledLabel, \ | |
558 (report_value), \ | |
559 kFileSystemErrorMax); \ | |
560 } | |
561 | |
562 switch (error_code) { | |
563 case base::PLATFORM_FILE_OK: | |
564 REPORT(kOK); | |
565 break; | |
566 case base::PLATFORM_FILE_ERROR_INVALID_URL: | |
567 REPORT(kInvalidSchemeError); | |
568 break; | |
569 case base::PLATFORM_FILE_ERROR_NOT_FOUND: | |
570 REPORT(kNotFound); | |
571 break; | |
572 case base::PLATFORM_FILE_ERROR_FAILED: | |
573 default: | |
574 REPORT(kUnknownError); | |
575 break; | |
576 } | |
577 #undef REPORT | |
578 } | |
579 | |
580 const UpdateObserverList* SandboxMountPointProvider::GetUpdateObservers( | |
581 FileSystemType type) const { | |
582 DCHECK(CanHandleType(type)); | |
583 if (type == kFileSystemTypeSyncable) | |
584 return &syncable_update_observers_; | |
585 return &update_observers_; | |
586 } | |
587 | |
588 void SandboxMountPointProvider::AddSyncableFileUpdateObserver( | |
589 FileUpdateObserver* observer, | |
590 base::SequencedTaskRunner* task_runner) { | |
591 UpdateObserverList::Source observer_source = | |
592 syncable_update_observers_.source(); | |
593 observer_source.AddObserver(observer, task_runner); | |
594 syncable_update_observers_ = UpdateObserverList(observer_source); | |
595 } | |
596 | |
597 void SandboxMountPointProvider::AddSyncableFileChangeObserver( | |
598 FileChangeObserver* observer, | |
599 base::SequencedTaskRunner* task_runner) { | |
600 ChangeObserverList::Source observer_source = | |
601 syncable_change_observers_.source(); | |
602 observer_source.AddObserver(observer, task_runner); | |
603 syncable_change_observers_ = ChangeObserverList(observer_source); | |
604 } | |
605 | |
606 LocalFileSystemOperation* | |
607 SandboxMountPointProvider::CreateFileSystemOperationForSync( | |
608 FileSystemContext* file_system_context) { | |
609 scoped_ptr<FileSystemOperationContext> operation_context( | |
610 new FileSystemOperationContext(file_system_context)); | |
611 operation_context->set_update_observers(update_observers_); | |
612 operation_context->set_access_observers(access_observers_); | |
613 return new LocalFileSystemOperation(file_system_context, | |
614 operation_context.Pass()); | |
615 } | |
616 | |
617 base::FilePath SandboxMountPointProvider::GetUsageCachePathForOriginAndType( | |
618 const GURL& origin_url, | |
619 FileSystemType type) { | |
620 base::PlatformFileError error; | |
621 base::FilePath path = GetUsageCachePathForOriginAndType( | |
622 sandbox_sync_file_util(), origin_url, type, &error); | |
623 if (error != base::PLATFORM_FILE_OK) | |
624 return base::FilePath(); | |
625 return path; | |
626 } | |
627 | |
628 // static | |
629 base::FilePath SandboxMountPointProvider::GetUsageCachePathForOriginAndType( | |
630 ObfuscatedFileUtil* sandbox_file_util, | |
631 const GURL& origin_url, | |
632 fileapi::FileSystemType type, | |
633 base::PlatformFileError* error_out) { | |
634 DCHECK(error_out); | |
635 *error_out = base::PLATFORM_FILE_OK; | |
636 base::FilePath base_path = sandbox_file_util->GetDirectoryForOriginAndType( | |
637 origin_url, type, false /* create */, error_out); | |
638 if (*error_out != base::PLATFORM_FILE_OK) | |
639 return base::FilePath(); | |
640 return base_path.Append(FileSystemUsageCache::kUsageFileName); | |
641 } | |
642 | |
643 bool SandboxMountPointProvider::IsAllowedScheme(const GURL& url) const { | |
644 // Basically we only accept http or https. We allow file:// URLs | |
645 // only if --allow-file-access-from-files flag is given. | |
646 if (url.SchemeIs("http") || url.SchemeIs("https")) | |
647 return true; | |
648 if (url.SchemeIsFileSystem()) | |
649 return url.inner_url() && IsAllowedScheme(*url.inner_url()); | |
650 | |
651 for (size_t i = 0; | |
652 i < file_system_options_.additional_allowed_schemes().size(); | |
653 ++i) { | |
654 if (url.SchemeIs( | |
655 file_system_options_.additional_allowed_schemes()[i].c_str())) | |
656 return true; | |
657 } | |
658 return false; | |
659 } | |
660 | |
661 ObfuscatedFileUtil* SandboxMountPointProvider::sandbox_sync_file_util() { | |
662 DCHECK(sandbox_file_util_.get()); | |
663 return static_cast<ObfuscatedFileUtil*>(sandbox_file_util_->sync_file_util()); | |
664 } | |
665 | |
666 // static | |
667 void SandboxMountPointProvider::InvalidateUsageCacheOnFileThread( | |
668 ObfuscatedFileUtil* file_util, | |
669 const GURL& origin, | |
670 FileSystemType type, | |
671 FileSystemUsageCache* usage_cache) { | |
672 base::PlatformFileError error = base::PLATFORM_FILE_OK; | |
673 base::FilePath usage_cache_path = GetUsageCachePathForOriginAndType( | |
674 file_util, origin, type, &error); | |
675 if (error == base::PLATFORM_FILE_OK) | |
676 usage_cache->IncrementDirty(usage_cache_path); | |
677 } | |
678 | |
679 int64 SandboxMountPointProvider::RecalculateUsage(FileSystemContext* context, | |
680 const GURL& origin, | |
681 FileSystemType type) { | |
682 FileSystemOperationContext operation_context(context); | |
683 FileSystemURL url = context->CreateCrackedFileSystemURL( | |
684 origin, type, base::FilePath()); | |
685 scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator> enumerator( | |
686 sandbox_sync_file_util()->CreateFileEnumerator( | |
687 &operation_context, url, true)); | |
688 | |
689 base::FilePath file_path_each; | |
690 int64 usage = 0; | |
691 | |
692 while (!(file_path_each = enumerator->Next()).empty()) { | |
693 usage += enumerator->Size(); | |
694 usage += ObfuscatedFileUtil::ComputeFilePathCost(file_path_each); | |
695 } | |
696 | |
697 return usage; | |
698 } | |
699 | |
700 } // namespace fileapi | |
OLD | NEW |