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 "webkit/browser/fileapi/sandbox_file_system_backend_delegate.h" 6 7 #include <vector> 8 9 #include "base/command_line.h" 10 #include "base/file_util.h" 11 #include "base/metrics/histogram.h" 12 #include "base/stl_util.h" 13 #include "base/task_runner_util.h" 14 #include "net/base/net_util.h" 15 #include "webkit/browser/blob/file_stream_reader.h" 16 #include "webkit/browser/fileapi/async_file_util_adapter.h" 17 #include "webkit/browser/fileapi/file_system_context.h" 18 #include "webkit/browser/fileapi/file_system_operation_context.h" 19 #include "webkit/browser/fileapi/file_system_url.h" 20 #include "webkit/browser/fileapi/file_system_usage_cache.h" 21 #include "webkit/browser/fileapi/obfuscated_file_util.h" 22 #include "webkit/browser/fileapi/quota/quota_backend_impl.h" 23 #include "webkit/browser/fileapi/quota/quota_reservation.h" 24 #include "webkit/browser/fileapi/quota/quota_reservation_manager.h" 25 #include "webkit/browser/fileapi/sandbox_file_stream_writer.h" 26 #include "webkit/browser/fileapi/sandbox_file_system_backend.h" 27 #include "webkit/browser/fileapi/sandbox_quota_observer.h" 28 #include "webkit/browser/quota/quota_manager.h" 29 #include "webkit/common/fileapi/file_system_util.h" 30 31 namespace fileapi { 32 33 namespace { 34 35 const char kTemporaryOriginsCountLabel[] = "FileSystem.TemporaryOriginsCount"; 36 const char kPersistentOriginsCountLabel[] = "FileSystem.PersistentOriginsCount"; 37 38 const char kOpenFileSystemLabel[] = "FileSystem.OpenFileSystem"; 39 const char kOpenFileSystemDetailLabel[] = "FileSystem.OpenFileSystemDetail"; 40 const char kOpenFileSystemDetailNonThrottledLabel[] = 41 "FileSystem.OpenFileSystemDetailNonthrottled"; 42 int64 kMinimumStatsCollectionIntervalHours = 1; 43 44 // For type directory names in ObfuscatedFileUtil. 45 // TODO(kinuko,nhiroki): Each type string registration should be done 46 // via its own backend. 47 const char kTemporaryDirectoryName[] = "t"; 48 const char kPersistentDirectoryName[] = "p"; 49 const char kSyncableDirectoryName[] = "s"; 50 51 const char* kPrepopulateTypes[] = { 52 kPersistentDirectoryName, 53 kTemporaryDirectoryName 54 }; 55 56 enum FileSystemError { 57 kOK = 0, 58 kIncognito, 59 kInvalidSchemeError, 60 kCreateDirectoryError, 61 kNotFound, 62 kUnknownError, 63 kFileSystemErrorMax, 64 }; 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 std::string GetTypeStringForURL(const FileSystemURL& url) { 78 return SandboxFileSystemBackendDelegate::GetTypeString(url.type()); 79 } 80 81 std::set<std::string> GetKnownTypeStrings() { 82 std::set<std::string> known_type_strings; 83 known_type_strings.insert(kTemporaryDirectoryName); 84 known_type_strings.insert(kPersistentDirectoryName); 85 known_type_strings.insert(kSyncableDirectoryName); 86 return known_type_strings; 87 } 88 89 class ObfuscatedOriginEnumerator 90 : public SandboxFileSystemBackendDelegate::OriginEnumerator { 91 public: 92 explicit ObfuscatedOriginEnumerator(ObfuscatedFileUtil* file_util) { 93 enum_.reset(file_util->CreateOriginEnumerator()); 94 } 95 virtual ~ObfuscatedOriginEnumerator() {} 96 97 virtual GURL Next() OVERRIDE { 98 return enum_->Next(); 99 } 100 101 virtual bool HasFileSystemType(FileSystemType type) const OVERRIDE { 102 return enum_->HasTypeDirectory( 103 SandboxFileSystemBackendDelegate::GetTypeString(type)); 104 } 105 106 private: 107 scoped_ptr<ObfuscatedFileUtil::AbstractOriginEnumerator> enum_; 108 }; 109 110 void OpenFileSystemOnFileThread( 111 ObfuscatedFileUtil* file_util, 112 const GURL& origin_url, 113 FileSystemType type, 114 OpenFileSystemMode mode, 115 base::PlatformFileError* error_ptr) { 116 DCHECK(error_ptr); 117 const bool create = (mode == OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT); 118 file_util->GetDirectoryForOriginAndType( 119 origin_url, SandboxFileSystemBackendDelegate::GetTypeString(type), 120 create, error_ptr); 121 if (*error_ptr != base::PLATFORM_FILE_OK) { 122 UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemLabel, 123 kCreateDirectoryError, 124 kFileSystemErrorMax); 125 } else { 126 UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemLabel, kOK, kFileSystemErrorMax); 127 } 128 // The reference of file_util will be derefed on the FILE thread 129 // when the storage of this callback gets deleted regardless of whether 130 // this method is called or not. 131 } 132 133 void DidOpenFileSystem( 134 base::WeakPtr<SandboxFileSystemBackendDelegate> delegate, 135 const base::Callback<void(base::PlatformFileError error)>& callback, 136 base::PlatformFileError* error) { 137 if (delegate.get()) 138 delegate.get()->CollectOpenFileSystemMetrics(*error); 139 callback.Run(*error); 140 } 141 142 template <typename T> 143 void DeleteSoon(base::SequencedTaskRunner* runner, T* ptr) { 144 if (!runner->DeleteSoon(FROM_HERE, ptr)) 145 delete ptr; 146 } 147 148 } // namespace 149 150 const base::FilePath::CharType 151 SandboxFileSystemBackendDelegate::kFileSystemDirectory[] = 152 FILE_PATH_LITERAL("File System"); 153 154 // static 155 std::string SandboxFileSystemBackendDelegate::GetTypeString( 156 FileSystemType type) { 157 switch (type) { 158 case kFileSystemTypeTemporary: 159 return kTemporaryDirectoryName; 160 case kFileSystemTypePersistent: 161 return kPersistentDirectoryName; 162 case kFileSystemTypeSyncable: 163 case kFileSystemTypeSyncableForInternalSync: 164 return kSyncableDirectoryName; 165 case kFileSystemTypeUnknown: 166 default: 167 NOTREACHED() << "Unknown filesystem type requested:" << type; 168 return std::string(); 169 } 170 } 171 172 SandboxFileSystemBackendDelegate::SandboxFileSystemBackendDelegate( 173 quota::QuotaManagerProxy* quota_manager_proxy, 174 base::SequencedTaskRunner* file_task_runner, 175 const base::FilePath& profile_path, 176 quota::SpecialStoragePolicy* special_storage_policy, 177 const FileSystemOptions& file_system_options) 178 : file_task_runner_(file_task_runner), 179 sandbox_file_util_(new AsyncFileUtilAdapter( 180 new ObfuscatedFileUtil( 181 special_storage_policy, 182 profile_path.Append(kFileSystemDirectory), 183 file_task_runner, 184 base::Bind(&GetTypeStringForURL), 185 GetKnownTypeStrings(), 186 this))), 187 file_system_usage_cache_(new FileSystemUsageCache(file_task_runner)), 188 quota_observer_(new SandboxQuotaObserver( 189 quota_manager_proxy, 190 file_task_runner, 191 obfuscated_file_util(), 192 usage_cache())), 193 quota_reservation_manager_(new QuotaReservationManager( 194 scoped_ptr<QuotaReservationManager::QuotaBackend>( 195 new QuotaBackendImpl(file_task_runner_, 196 obfuscated_file_util(), 197 usage_cache(), 198 quota_manager_proxy)))), 199 special_storage_policy_(special_storage_policy), 200 file_system_options_(file_system_options), 201 is_filesystem_opened_(false), 202 weak_factory_(this) { 203 // Prepopulate database only if it can run asynchronously (i.e. the current 204 // thread is not file_task_runner). Usually this is the case but may not 205 // in test code. 206 if (!file_task_runner_->RunsTasksOnCurrentThread()) { 207 std::vector<std::string> types_to_prepopulate( 208 &kPrepopulateTypes[0], 209 &kPrepopulateTypes[arraysize(kPrepopulateTypes)]); 210 file_task_runner_->PostTask( 211 FROM_HERE, 212 base::Bind(&ObfuscatedFileUtil::MaybePrepopulateDatabase, 213 base::Unretained(obfuscated_file_util()), 214 types_to_prepopulate)); 215 } 216 } 217 218 SandboxFileSystemBackendDelegate::~SandboxFileSystemBackendDelegate() { 219 io_thread_checker_.DetachFromThread(); 220 221 if (!file_task_runner_->RunsTasksOnCurrentThread()) { 222 DeleteSoon(file_task_runner_.get(), quota_reservation_manager_.release()); 223 DeleteSoon(file_task_runner_.get(), sandbox_file_util_.release()); 224 DeleteSoon(file_task_runner_.get(), quota_observer_.release()); 225 DeleteSoon(file_task_runner_.get(), file_system_usage_cache_.release()); 226 } 227 } 228 229 SandboxFileSystemBackendDelegate::OriginEnumerator* 230 SandboxFileSystemBackendDelegate::CreateOriginEnumerator() { 231 return new ObfuscatedOriginEnumerator(obfuscated_file_util()); 232 } 233 234 base::FilePath 235 SandboxFileSystemBackendDelegate::GetBaseDirectoryForOriginAndType( 236 const GURL& origin_url, 237 FileSystemType type, 238 bool create) { 239 base::PlatformFileError error = base::PLATFORM_FILE_OK; 240 base::FilePath path = obfuscated_file_util()->GetDirectoryForOriginAndType( 241 origin_url, GetTypeString(type), create, &error); 242 if (error != base::PLATFORM_FILE_OK) 243 return base::FilePath(); 244 return path; 245 } 246 247 void SandboxFileSystemBackendDelegate::OpenFileSystem( 248 const GURL& origin_url, 249 FileSystemType type, 250 OpenFileSystemMode mode, 251 const OpenFileSystemCallback& callback, 252 const GURL& root_url) { 253 if (!IsAllowedScheme(origin_url)) { 254 callback.Run(GURL(), std::string(), base::PLATFORM_FILE_ERROR_SECURITY); 255 return; 256 } 257 258 std::string name = GetFileSystemName(origin_url, type); 259 260 base::PlatformFileError* error_ptr = new base::PlatformFileError; 261 file_task_runner_->PostTaskAndReply( 262 FROM_HERE, 263 base::Bind(&OpenFileSystemOnFileThread, 264 obfuscated_file_util(), origin_url, type, mode, 265 base::Unretained(error_ptr)), 266 base::Bind(&DidOpenFileSystem, 267 weak_factory_.GetWeakPtr(), 268 base::Bind(callback, root_url, name), 269 base::Owned(error_ptr))); 270 271 io_thread_checker_.DetachFromThread(); 272 is_filesystem_opened_ = true; 273 } 274 275 scoped_ptr<FileSystemOperationContext> 276 SandboxFileSystemBackendDelegate::CreateFileSystemOperationContext( 277 const FileSystemURL& url, 278 FileSystemContext* context, 279 base::PlatformFileError* error_code) const { 280 if (!IsAccessValid(url)) { 281 *error_code = base::PLATFORM_FILE_ERROR_SECURITY; 282 return scoped_ptr<FileSystemOperationContext>(); 283 } 284 285 const UpdateObserverList* update_observers = GetUpdateObservers(url.type()); 286 const ChangeObserverList* change_observers = GetChangeObservers(url.type()); 287 DCHECK(update_observers); 288 289 scoped_ptr<FileSystemOperationContext> operation_context( 290 new FileSystemOperationContext(context)); 291 operation_context->set_update_observers(*update_observers); 292 operation_context->set_change_observers( 293 change_observers ? *change_observers : ChangeObserverList()); 294 295 return operation_context.Pass(); 296 } 297 298 scoped_ptr<webkit_blob::FileStreamReader> 299 SandboxFileSystemBackendDelegate::CreateFileStreamReader( 300 const FileSystemURL& url, 301 int64 offset, 302 const base::Time& expected_modification_time, 303 FileSystemContext* context) const { 304 if (!IsAccessValid(url)) 305 return scoped_ptr<webkit_blob::FileStreamReader>(); 306 return scoped_ptr<webkit_blob::FileStreamReader>( 307 webkit_blob::FileStreamReader::CreateForFileSystemFile( 308 context, url, offset, expected_modification_time)); 309 } 310 311 scoped_ptr<FileStreamWriter> 312 SandboxFileSystemBackendDelegate::CreateFileStreamWriter( 313 const FileSystemURL& url, 314 int64 offset, 315 FileSystemContext* context, 316 FileSystemType type) const { 317 if (!IsAccessValid(url)) 318 return scoped_ptr<FileStreamWriter>(); 319 const UpdateObserverList* observers = GetUpdateObservers(type); 320 DCHECK(observers); 321 return scoped_ptr<FileStreamWriter>( 322 new SandboxFileStreamWriter(context, url, offset, *observers)); 323 } 324 325 base::PlatformFileError 326 SandboxFileSystemBackendDelegate::DeleteOriginDataOnFileThread( 327 FileSystemContext* file_system_context, 328 quota::QuotaManagerProxy* proxy, 329 const GURL& origin_url, 330 FileSystemType type) { 331 int64 usage = GetOriginUsageOnFileThread( 332 file_system_context, origin_url, type); 333 usage_cache()->CloseCacheFiles(); 334 bool result = obfuscated_file_util()->DeleteDirectoryForOriginAndType( 335 origin_url, GetTypeString(type)); 336 if (result && proxy) { 337 proxy->NotifyStorageModified( 338 quota::QuotaClient::kFileSystem, 339 origin_url, 340 FileSystemTypeToQuotaStorageType(type), 341 -usage); 342 } 343 344 if (result) 345 return base::PLATFORM_FILE_OK; 346 return base::PLATFORM_FILE_ERROR_FAILED; 347 } 348 349 void SandboxFileSystemBackendDelegate::GetOriginsForTypeOnFileThread( 350 FileSystemType type, std::set<GURL>* origins) { 351 DCHECK(origins); 352 scoped_ptr<OriginEnumerator> enumerator(CreateOriginEnumerator()); 353 GURL origin; 354 while (!(origin = enumerator->Next()).is_empty()) { 355 if (enumerator->HasFileSystemType(type)) 356 origins->insert(origin); 357 } 358 switch (type) { 359 case kFileSystemTypeTemporary: 360 UMA_HISTOGRAM_COUNTS(kTemporaryOriginsCountLabel, origins->size()); 361 break; 362 case kFileSystemTypePersistent: 363 UMA_HISTOGRAM_COUNTS(kPersistentOriginsCountLabel, origins->size()); 364 break; 365 default: 366 break; 367 } 368 } 369 370 void SandboxFileSystemBackendDelegate::GetOriginsForHostOnFileThread( 371 FileSystemType type, const std::string& host, 372 std::set<GURL>* origins) { 373 DCHECK(origins); 374 scoped_ptr<OriginEnumerator> enumerator(CreateOriginEnumerator()); 375 GURL origin; 376 while (!(origin = enumerator->Next()).is_empty()) { 377 if (host == net::GetHostOrSpecFromURL(origin) && 378 enumerator->HasFileSystemType(type)) 379 origins->insert(origin); 380 } 381 } 382 383 int64 SandboxFileSystemBackendDelegate::GetOriginUsageOnFileThread( 384 FileSystemContext* file_system_context, 385 const GURL& origin_url, 386 FileSystemType type) { 387 // Don't use usage cache and return recalculated usage for sticky invalidated 388 // origins. 389 if (ContainsKey(sticky_dirty_origins_, std::make_pair(origin_url, type))) 390 return RecalculateUsage(file_system_context, origin_url, type); 391 392 base::FilePath base_path = 393 GetBaseDirectoryForOriginAndType(origin_url, type, false); 394 if (base_path.empty() || !base::DirectoryExists(base_path)) 395 return 0; 396 base::FilePath usage_file_path = 397 base_path.Append(FileSystemUsageCache::kUsageFileName); 398 399 bool is_valid = usage_cache()->IsValid(usage_file_path); 400 uint32 dirty_status = 0; 401 bool dirty_status_available = 402 usage_cache()->GetDirty(usage_file_path, &dirty_status); 403 bool visited = !visited_origins_.insert(origin_url).second; 404 if (is_valid && (dirty_status == 0 || (dirty_status_available && visited))) { 405 // The usage cache is clean (dirty == 0) or the origin is already 406 // initialized and running. Read the cache file to get the usage. 407 int64 usage = 0; 408 return usage_cache()->GetUsage(usage_file_path, &usage) ? usage : -1; 409 } 410 // The usage cache has not been initialized or the cache is dirty. 411 // Get the directory size now and update the cache. 412 usage_cache()->Delete(usage_file_path); 413 414 int64 usage = RecalculateUsage(file_system_context, origin_url, type); 415 416 // This clears the dirty flag too. 417 usage_cache()->UpdateUsage(usage_file_path, usage); 418 return usage; 419 } 420 421 scoped_refptr<QuotaReservation> 422 SandboxFileSystemBackendDelegate::CreateQuotaReservationOnFileTaskRunner( 423 const GURL& origin, 424 FileSystemType type) { 425 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); 426 DCHECK(quota_reservation_manager_); 427 return quota_reservation_manager_->CreateReservation(origin, type); 428 } 429 430 void SandboxFileSystemBackendDelegate::AddFileUpdateObserver( 431 FileSystemType type, 432 FileUpdateObserver* observer, 433 base::SequencedTaskRunner* task_runner) { 434 DCHECK(!is_filesystem_opened_ || io_thread_checker_.CalledOnValidThread()); 435 update_observers_[type] = 436 update_observers_[type].AddObserver(observer, task_runner); 437 } 438 439 void SandboxFileSystemBackendDelegate::AddFileChangeObserver( 440 FileSystemType type, 441 FileChangeObserver* observer, 442 base::SequencedTaskRunner* task_runner) { 443 DCHECK(!is_filesystem_opened_ || io_thread_checker_.CalledOnValidThread()); 444 change_observers_[type] = 445 change_observers_[type].AddObserver(observer, task_runner); 446 } 447 448 void SandboxFileSystemBackendDelegate::AddFileAccessObserver( 449 FileSystemType type, 450 FileAccessObserver* observer, 451 base::SequencedTaskRunner* task_runner) { 452 DCHECK(!is_filesystem_opened_ || io_thread_checker_.CalledOnValidThread()); 453 access_observers_[type] = 454 access_observers_[type].AddObserver(observer, task_runner); 455 } 456 457 const UpdateObserverList* SandboxFileSystemBackendDelegate::GetUpdateObservers( 458 FileSystemType type) const { 459 std::map<FileSystemType, UpdateObserverList>::const_iterator iter = 460 update_observers_.find(type); 461 if (iter == update_observers_.end()) 462 return NULL; 463 return &iter->second; 464 } 465 466 const ChangeObserverList* SandboxFileSystemBackendDelegate::GetChangeObservers( 467 FileSystemType type) const { 468 std::map<FileSystemType, ChangeObserverList>::const_iterator iter = 469 change_observers_.find(type); 470 if (iter == change_observers_.end()) 471 return NULL; 472 return &iter->second; 473 } 474 475 const AccessObserverList* SandboxFileSystemBackendDelegate::GetAccessObservers( 476 FileSystemType type) const { 477 std::map<FileSystemType, AccessObserverList>::const_iterator iter = 478 access_observers_.find(type); 479 if (iter == access_observers_.end()) 480 return NULL; 481 return &iter->second; 482 } 483 484 void SandboxFileSystemBackendDelegate::RegisterQuotaUpdateObserver( 485 FileSystemType type) { 486 AddFileUpdateObserver(type, quota_observer_.get(), file_task_runner_.get()); 487 } 488 489 void SandboxFileSystemBackendDelegate::InvalidateUsageCache( 490 const GURL& origin, 491 FileSystemType type) { 492 base::PlatformFileError error = base::PLATFORM_FILE_OK; 493 base::FilePath usage_file_path = GetUsageCachePathForOriginAndType( 494 obfuscated_file_util(), origin, type, &error); 495 if (error != base::PLATFORM_FILE_OK) 496 return; 497 usage_cache()->IncrementDirty(usage_file_path); 498 } 499 500 void SandboxFileSystemBackendDelegate::StickyInvalidateUsageCache( 501 const GURL& origin, 502 FileSystemType type) { 503 sticky_dirty_origins_.insert(std::make_pair(origin, type)); 504 quota_observer()->SetUsageCacheEnabled(origin, type, false); 505 InvalidateUsageCache(origin, type); 506 } 507 508 FileSystemFileUtil* SandboxFileSystemBackendDelegate::sync_file_util() { 509 return static_cast<AsyncFileUtilAdapter*>(file_util())->sync_file_util(); 510 } 511 512 bool SandboxFileSystemBackendDelegate::IsAccessValid( 513 const FileSystemURL& url) const { 514 if (!IsAllowedScheme(url.origin())) 515 return false; 516 517 if (url.path().ReferencesParent()) 518 return false; 519 520 // Return earlier if the path is '/', because VirtualPath::BaseName() 521 // returns '/' for '/' and we fail the "basename != '/'" check below. 522 // (We exclude '.' because it's disallowed by spec.) 523 if (VirtualPath::IsRootPath(url.path()) && 524 url.path() != base::FilePath(base::FilePath::kCurrentDirectory)) 525 return true; 526 527 // Restricted names specified in 528 // http://dev.w3.org/2009/dap/file-system/file-dir-sys.html#naming-restrictions 529 base::FilePath filename = VirtualPath::BaseName(url.path()); 530 // See if the name is allowed to create. 531 for (size_t i = 0; i < arraysize(kRestrictedNames); ++i) { 532 if (filename.value() == kRestrictedNames[i]) 533 return false; 534 } 535 for (size_t i = 0; i < arraysize(kRestrictedChars); ++i) { 536 if (filename.value().find(kRestrictedChars[i]) != 537 base::FilePath::StringType::npos) 538 return false; 539 } 540 541 return true; 542 } 543 544 bool SandboxFileSystemBackendDelegate::IsAllowedScheme(const GURL& url) const { 545 // Basically we only accept http or https. We allow file:// URLs 546 // only if --allow-file-access-from-files flag is given. 547 if (url.SchemeIsHTTPOrHTTPS()) 548 return true; 549 if (url.SchemeIsFileSystem()) 550 return url.inner_url() && IsAllowedScheme(*url.inner_url()); 551 552 for (size_t i = 0; 553 i < file_system_options_.additional_allowed_schemes().size(); 554 ++i) { 555 if (url.SchemeIs( 556 file_system_options_.additional_allowed_schemes()[i].c_str())) 557 return true; 558 } 559 return false; 560 } 561 562 base::FilePath 563 SandboxFileSystemBackendDelegate::GetUsageCachePathForOriginAndType( 564 const GURL& origin_url, 565 FileSystemType type) { 566 base::PlatformFileError error; 567 base::FilePath path = GetUsageCachePathForOriginAndType( 568 obfuscated_file_util(), origin_url, type, &error); 569 if (error != base::PLATFORM_FILE_OK) 570 return base::FilePath(); 571 return path; 572 } 573 574 // static 575 base::FilePath 576 SandboxFileSystemBackendDelegate::GetUsageCachePathForOriginAndType( 577 ObfuscatedFileUtil* sandbox_file_util, 578 const GURL& origin_url, 579 FileSystemType type, 580 base::PlatformFileError* error_out) { 581 DCHECK(error_out); 582 *error_out = base::PLATFORM_FILE_OK; 583 base::FilePath base_path = sandbox_file_util->GetDirectoryForOriginAndType( 584 origin_url, GetTypeString(type), false /* create */, error_out); 585 if (*error_out != base::PLATFORM_FILE_OK) 586 return base::FilePath(); 587 return base_path.Append(FileSystemUsageCache::kUsageFileName); 588 } 589 590 int64 SandboxFileSystemBackendDelegate::RecalculateUsage( 591 FileSystemContext* context, 592 const GURL& origin, 593 FileSystemType type) { 594 FileSystemOperationContext operation_context(context); 595 FileSystemURL url = context->CreateCrackedFileSystemURL( 596 origin, type, base::FilePath()); 597 scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator> enumerator( 598 obfuscated_file_util()->CreateFileEnumerator( 599 &operation_context, url, true)); 600 601 base::FilePath file_path_each; 602 int64 usage = 0; 603 604 while (!(file_path_each = enumerator->Next()).empty()) { 605 usage += enumerator->Size(); 606 usage += ObfuscatedFileUtil::ComputeFilePathCost(file_path_each); 607 } 608 609 return usage; 610 } 611 612 void SandboxFileSystemBackendDelegate::CollectOpenFileSystemMetrics( 613 base::PlatformFileError error_code) { 614 base::Time now = base::Time::Now(); 615 bool throttled = now < next_release_time_for_open_filesystem_stat_; 616 if (!throttled) { 617 next_release_time_for_open_filesystem_stat_ = 618 now + base::TimeDelta::FromHours(kMinimumStatsCollectionIntervalHours); 619 } 620 621 #define REPORT(report_value) \ 622 UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemDetailLabel, \ 623 (report_value), \ 624 kFileSystemErrorMax); \ 625 if (!throttled) { \ 626 UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemDetailNonThrottledLabel, \ 627 (report_value), \ 628 kFileSystemErrorMax); \ 629 } 630 631 switch (error_code) { 632 case base::PLATFORM_FILE_OK: 633 REPORT(kOK); 634 break; 635 case base::PLATFORM_FILE_ERROR_INVALID_URL: 636 REPORT(kInvalidSchemeError); 637 break; 638 case base::PLATFORM_FILE_ERROR_NOT_FOUND: 639 REPORT(kNotFound); 640 break; 641 case base::PLATFORM_FILE_ERROR_FAILED: 642 default: 643 REPORT(kUnknownError); 644 break; 645 } 646 #undef REPORT 647 } 648 649 ObfuscatedFileUtil* SandboxFileSystemBackendDelegate::obfuscated_file_util() { 650 return static_cast<ObfuscatedFileUtil*>(sync_file_util()); 651 } 652 653 // Declared in obfuscated_file_util.h. 654 // static 655 ObfuscatedFileUtil* ObfuscatedFileUtil::CreateForTesting( 656 quota::SpecialStoragePolicy* special_storage_policy, 657 const base::FilePath& file_system_directory, 658 base::SequencedTaskRunner* file_task_runner) { 659 return new ObfuscatedFileUtil(special_storage_policy, 660 file_system_directory, 661 file_task_runner, 662 base::Bind(&GetTypeStringForURL), 663 GetKnownTypeStrings(), 664 NULL); 665 } 666 667 } // namespace fileapi 668