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 "storage/browser/fileapi/sandbox_file_system_backend_delegate.h" 6 7 #include <vector> 8 9 #include "base/command_line.h" 10 #include "base/files/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 "storage/browser/blob/file_stream_reader.h" 16 #include "storage/browser/fileapi/async_file_util_adapter.h" 17 #include "storage/browser/fileapi/file_system_context.h" 18 #include "storage/browser/fileapi/file_system_operation_context.h" 19 #include "storage/browser/fileapi/file_system_url.h" 20 #include "storage/browser/fileapi/file_system_usage_cache.h" 21 #include "storage/browser/fileapi/obfuscated_file_util.h" 22 #include "storage/browser/fileapi/quota/quota_backend_impl.h" 23 #include "storage/browser/fileapi/quota/quota_reservation.h" 24 #include "storage/browser/fileapi/quota/quota_reservation_manager.h" 25 #include "storage/browser/fileapi/sandbox_file_stream_writer.h" 26 #include "storage/browser/fileapi/sandbox_file_system_backend.h" 27 #include "storage/browser/fileapi/sandbox_quota_observer.h" 28 #include "storage/browser/quota/quota_manager_proxy.h" 29 #include "storage/common/fileapi/file_system_util.h" 30 31 namespace storage { 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 OpenFileSystemOnFileTaskRunner( 111 ObfuscatedFileUtil* file_util, 112 const GURL& origin_url, 113 FileSystemType type, 114 OpenFileSystemMode mode, 115 base::File::Error* 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::File::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::File::Error error)>& callback, 136 base::File::Error* 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 storage::QuotaManagerProxy* quota_manager_proxy, 174 base::SequencedTaskRunner* file_task_runner, 175 const base::FilePath& profile_path, 176 storage::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(special_storage_policy, 181 profile_path.Append(kFileSystemDirectory), 182 file_system_options.env_override(), 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(quota_manager_proxy, 189 file_task_runner, 190 obfuscated_file_util(), 191 usage_cache())), 192 quota_reservation_manager_(new QuotaReservationManager( 193 scoped_ptr<QuotaReservationManager::QuotaBackend>( 194 new QuotaBackendImpl(file_task_runner_.get(), 195 obfuscated_file_util(), 196 usage_cache(), 197 quota_manager_proxy)))), 198 special_storage_policy_(special_storage_policy), 199 file_system_options_(file_system_options), 200 is_filesystem_opened_(false), 201 weak_factory_(this) { 202 // Prepopulate database only if it can run asynchronously (i.e. the current 203 // thread is not file_task_runner). Usually this is the case but may not 204 // in test code. 205 if (!file_system_options.is_incognito() && 206 !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::File::Error error = base::File::FILE_OK; 240 base::FilePath path = obfuscated_file_util()->GetDirectoryForOriginAndType( 241 origin_url, GetTypeString(type), create, &error); 242 if (error != base::File::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::File::FILE_ERROR_SECURITY); 255 return; 256 } 257 258 std::string name = GetFileSystemName(origin_url, type); 259 260 base::File::Error* error_ptr = new base::File::Error; 261 file_task_runner_->PostTaskAndReply( 262 FROM_HERE, 263 base::Bind(&OpenFileSystemOnFileTaskRunner, 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::File::Error* error_code) const { 280 if (!IsAccessValid(url)) { 281 *error_code = base::File::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<storage::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<storage::FileStreamReader>(); 306 return scoped_ptr<storage::FileStreamReader>( 307 storage::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::File::Error 326 SandboxFileSystemBackendDelegate::DeleteOriginDataOnFileTaskRunner( 327 FileSystemContext* file_system_context, 328 storage::QuotaManagerProxy* proxy, 329 const GURL& origin_url, 330 FileSystemType type) { 331 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); 332 int64 usage = GetOriginUsageOnFileTaskRunner( 333 file_system_context, origin_url, type); 334 usage_cache()->CloseCacheFiles(); 335 bool result = obfuscated_file_util()->DeleteDirectoryForOriginAndType( 336 origin_url, GetTypeString(type)); 337 if (result && proxy) { 338 proxy->NotifyStorageModified(storage::QuotaClient::kFileSystem, 339 origin_url, 340 FileSystemTypeToQuotaStorageType(type), 341 -usage); 342 } 343 344 if (result) 345 return base::File::FILE_OK; 346 return base::File::FILE_ERROR_FAILED; 347 } 348 349 void SandboxFileSystemBackendDelegate::GetOriginsForTypeOnFileTaskRunner( 350 FileSystemType type, std::set<GURL>* origins) { 351 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); 352 DCHECK(origins); 353 scoped_ptr<OriginEnumerator> enumerator(CreateOriginEnumerator()); 354 GURL origin; 355 while (!(origin = enumerator->Next()).is_empty()) { 356 if (enumerator->HasFileSystemType(type)) 357 origins->insert(origin); 358 } 359 switch (type) { 360 case kFileSystemTypeTemporary: 361 UMA_HISTOGRAM_COUNTS(kTemporaryOriginsCountLabel, origins->size()); 362 break; 363 case kFileSystemTypePersistent: 364 UMA_HISTOGRAM_COUNTS(kPersistentOriginsCountLabel, origins->size()); 365 break; 366 default: 367 break; 368 } 369 } 370 371 void SandboxFileSystemBackendDelegate::GetOriginsForHostOnFileTaskRunner( 372 FileSystemType type, const std::string& host, 373 std::set<GURL>* origins) { 374 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); 375 DCHECK(origins); 376 scoped_ptr<OriginEnumerator> enumerator(CreateOriginEnumerator()); 377 GURL origin; 378 while (!(origin = enumerator->Next()).is_empty()) { 379 if (host == net::GetHostOrSpecFromURL(origin) && 380 enumerator->HasFileSystemType(type)) 381 origins->insert(origin); 382 } 383 } 384 385 int64 SandboxFileSystemBackendDelegate::GetOriginUsageOnFileTaskRunner( 386 FileSystemContext* file_system_context, 387 const GURL& origin_url, 388 FileSystemType type) { 389 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); 390 391 // Don't use usage cache and return recalculated usage for sticky invalidated 392 // origins. 393 if (ContainsKey(sticky_dirty_origins_, std::make_pair(origin_url, type))) 394 return RecalculateUsage(file_system_context, origin_url, type); 395 396 base::FilePath base_path = 397 GetBaseDirectoryForOriginAndType(origin_url, type, false); 398 if (base_path.empty() || !base::DirectoryExists(base_path)) 399 return 0; 400 base::FilePath usage_file_path = 401 base_path.Append(FileSystemUsageCache::kUsageFileName); 402 403 bool is_valid = usage_cache()->IsValid(usage_file_path); 404 uint32 dirty_status = 0; 405 bool dirty_status_available = 406 usage_cache()->GetDirty(usage_file_path, &dirty_status); 407 bool visited = !visited_origins_.insert(origin_url).second; 408 if (is_valid && (dirty_status == 0 || (dirty_status_available && visited))) { 409 // The usage cache is clean (dirty == 0) or the origin is already 410 // initialized and running. Read the cache file to get the usage. 411 int64 usage = 0; 412 return usage_cache()->GetUsage(usage_file_path, &usage) ? usage : -1; 413 } 414 // The usage cache has not been initialized or the cache is dirty. 415 // Get the directory size now and update the cache. 416 usage_cache()->Delete(usage_file_path); 417 418 int64 usage = RecalculateUsage(file_system_context, origin_url, type); 419 420 // This clears the dirty flag too. 421 usage_cache()->UpdateUsage(usage_file_path, usage); 422 return usage; 423 } 424 425 scoped_refptr<QuotaReservation> 426 SandboxFileSystemBackendDelegate::CreateQuotaReservationOnFileTaskRunner( 427 const GURL& origin, 428 FileSystemType type) { 429 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); 430 DCHECK(quota_reservation_manager_); 431 return quota_reservation_manager_->CreateReservation(origin, type); 432 } 433 434 void SandboxFileSystemBackendDelegate::AddFileUpdateObserver( 435 FileSystemType type, 436 FileUpdateObserver* observer, 437 base::SequencedTaskRunner* task_runner) { 438 DCHECK(!is_filesystem_opened_ || io_thread_checker_.CalledOnValidThread()); 439 update_observers_[type] = 440 update_observers_[type].AddObserver(observer, task_runner); 441 } 442 443 void SandboxFileSystemBackendDelegate::AddFileChangeObserver( 444 FileSystemType type, 445 FileChangeObserver* observer, 446 base::SequencedTaskRunner* task_runner) { 447 DCHECK(!is_filesystem_opened_ || io_thread_checker_.CalledOnValidThread()); 448 change_observers_[type] = 449 change_observers_[type].AddObserver(observer, task_runner); 450 } 451 452 void SandboxFileSystemBackendDelegate::AddFileAccessObserver( 453 FileSystemType type, 454 FileAccessObserver* observer, 455 base::SequencedTaskRunner* task_runner) { 456 DCHECK(!is_filesystem_opened_ || io_thread_checker_.CalledOnValidThread()); 457 access_observers_[type] = 458 access_observers_[type].AddObserver(observer, task_runner); 459 } 460 461 const UpdateObserverList* SandboxFileSystemBackendDelegate::GetUpdateObservers( 462 FileSystemType type) const { 463 std::map<FileSystemType, UpdateObserverList>::const_iterator iter = 464 update_observers_.find(type); 465 if (iter == update_observers_.end()) 466 return NULL; 467 return &iter->second; 468 } 469 470 const ChangeObserverList* SandboxFileSystemBackendDelegate::GetChangeObservers( 471 FileSystemType type) const { 472 std::map<FileSystemType, ChangeObserverList>::const_iterator iter = 473 change_observers_.find(type); 474 if (iter == change_observers_.end()) 475 return NULL; 476 return &iter->second; 477 } 478 479 const AccessObserverList* SandboxFileSystemBackendDelegate::GetAccessObservers( 480 FileSystemType type) const { 481 std::map<FileSystemType, AccessObserverList>::const_iterator iter = 482 access_observers_.find(type); 483 if (iter == access_observers_.end()) 484 return NULL; 485 return &iter->second; 486 } 487 488 void SandboxFileSystemBackendDelegate::RegisterQuotaUpdateObserver( 489 FileSystemType type) { 490 AddFileUpdateObserver(type, quota_observer_.get(), file_task_runner_.get()); 491 } 492 493 void SandboxFileSystemBackendDelegate::InvalidateUsageCache( 494 const GURL& origin, 495 FileSystemType type) { 496 base::File::Error error = base::File::FILE_OK; 497 base::FilePath usage_file_path = GetUsageCachePathForOriginAndType( 498 obfuscated_file_util(), origin, type, &error); 499 if (error != base::File::FILE_OK) 500 return; 501 usage_cache()->IncrementDirty(usage_file_path); 502 } 503 504 void SandboxFileSystemBackendDelegate::StickyInvalidateUsageCache( 505 const GURL& origin, 506 FileSystemType type) { 507 sticky_dirty_origins_.insert(std::make_pair(origin, type)); 508 quota_observer()->SetUsageCacheEnabled(origin, type, false); 509 InvalidateUsageCache(origin, type); 510 } 511 512 FileSystemFileUtil* SandboxFileSystemBackendDelegate::sync_file_util() { 513 return static_cast<AsyncFileUtilAdapter*>(file_util())->sync_file_util(); 514 } 515 516 bool SandboxFileSystemBackendDelegate::IsAccessValid( 517 const FileSystemURL& url) const { 518 if (!IsAllowedScheme(url.origin())) 519 return false; 520 521 if (url.path().ReferencesParent()) 522 return false; 523 524 // Return earlier if the path is '/', because VirtualPath::BaseName() 525 // returns '/' for '/' and we fail the "basename != '/'" check below. 526 // (We exclude '.' because it's disallowed by spec.) 527 if (VirtualPath::IsRootPath(url.path()) && 528 url.path() != base::FilePath(base::FilePath::kCurrentDirectory)) 529 return true; 530 531 // Restricted names specified in 532 // http://dev.w3.org/2009/dap/file-system/file-dir-sys.html#naming-restrictions 533 base::FilePath filename = VirtualPath::BaseName(url.path()); 534 // See if the name is allowed to create. 535 for (size_t i = 0; i < arraysize(kRestrictedNames); ++i) { 536 if (filename.value() == kRestrictedNames[i]) 537 return false; 538 } 539 for (size_t i = 0; i < arraysize(kRestrictedChars); ++i) { 540 if (filename.value().find(kRestrictedChars[i]) != 541 base::FilePath::StringType::npos) 542 return false; 543 } 544 545 return true; 546 } 547 548 bool SandboxFileSystemBackendDelegate::IsAllowedScheme(const GURL& url) const { 549 // Basically we only accept http or https. We allow file:// URLs 550 // only if --allow-file-access-from-files flag is given. 551 if (url.SchemeIsHTTPOrHTTPS()) 552 return true; 553 if (url.SchemeIsFileSystem()) 554 return url.inner_url() && IsAllowedScheme(*url.inner_url()); 555 556 for (size_t i = 0; 557 i < file_system_options_.additional_allowed_schemes().size(); 558 ++i) { 559 if (url.SchemeIs( 560 file_system_options_.additional_allowed_schemes()[i].c_str())) 561 return true; 562 } 563 return false; 564 } 565 566 base::FilePath 567 SandboxFileSystemBackendDelegate::GetUsageCachePathForOriginAndType( 568 const GURL& origin_url, 569 FileSystemType type) { 570 base::File::Error error; 571 base::FilePath path = GetUsageCachePathForOriginAndType( 572 obfuscated_file_util(), origin_url, type, &error); 573 if (error != base::File::FILE_OK) 574 return base::FilePath(); 575 return path; 576 } 577 578 // static 579 base::FilePath 580 SandboxFileSystemBackendDelegate::GetUsageCachePathForOriginAndType( 581 ObfuscatedFileUtil* sandbox_file_util, 582 const GURL& origin_url, 583 FileSystemType type, 584 base::File::Error* error_out) { 585 DCHECK(error_out); 586 *error_out = base::File::FILE_OK; 587 base::FilePath base_path = sandbox_file_util->GetDirectoryForOriginAndType( 588 origin_url, GetTypeString(type), false /* create */, error_out); 589 if (*error_out != base::File::FILE_OK) 590 return base::FilePath(); 591 return base_path.Append(FileSystemUsageCache::kUsageFileName); 592 } 593 594 int64 SandboxFileSystemBackendDelegate::RecalculateUsage( 595 FileSystemContext* context, 596 const GURL& origin, 597 FileSystemType type) { 598 FileSystemOperationContext operation_context(context); 599 FileSystemURL url = context->CreateCrackedFileSystemURL( 600 origin, type, base::FilePath()); 601 scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator> enumerator( 602 obfuscated_file_util()->CreateFileEnumerator( 603 &operation_context, url, true)); 604 605 base::FilePath file_path_each; 606 int64 usage = 0; 607 608 while (!(file_path_each = enumerator->Next()).empty()) { 609 usage += enumerator->Size(); 610 usage += ObfuscatedFileUtil::ComputeFilePathCost(file_path_each); 611 } 612 613 return usage; 614 } 615 616 void SandboxFileSystemBackendDelegate::CollectOpenFileSystemMetrics( 617 base::File::Error error_code) { 618 base::Time now = base::Time::Now(); 619 bool throttled = now < next_release_time_for_open_filesystem_stat_; 620 if (!throttled) { 621 next_release_time_for_open_filesystem_stat_ = 622 now + base::TimeDelta::FromHours(kMinimumStatsCollectionIntervalHours); 623 } 624 625 #define REPORT(report_value) \ 626 UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemDetailLabel, \ 627 (report_value), \ 628 kFileSystemErrorMax); \ 629 if (!throttled) { \ 630 UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemDetailNonThrottledLabel, \ 631 (report_value), \ 632 kFileSystemErrorMax); \ 633 } 634 635 switch (error_code) { 636 case base::File::FILE_OK: 637 REPORT(kOK); 638 break; 639 case base::File::FILE_ERROR_INVALID_URL: 640 REPORT(kInvalidSchemeError); 641 break; 642 case base::File::FILE_ERROR_NOT_FOUND: 643 REPORT(kNotFound); 644 break; 645 case base::File::FILE_ERROR_FAILED: 646 default: 647 REPORT(kUnknownError); 648 break; 649 } 650 #undef REPORT 651 } 652 653 ObfuscatedFileUtil* SandboxFileSystemBackendDelegate::obfuscated_file_util() { 654 return static_cast<ObfuscatedFileUtil*>(sync_file_util()); 655 } 656 657 // Declared in obfuscated_file_util.h. 658 // static 659 ObfuscatedFileUtil* ObfuscatedFileUtil::CreateForTesting( 660 storage::SpecialStoragePolicy* special_storage_policy, 661 const base::FilePath& file_system_directory, 662 leveldb::Env* env_override, 663 base::SequencedTaskRunner* file_task_runner) { 664 return new ObfuscatedFileUtil(special_storage_policy, 665 file_system_directory, 666 env_override, 667 file_task_runner, 668 base::Bind(&GetTypeStringForURL), 669 GetKnownTypeStrings(), 670 NULL); 671 } 672 673 } // namespace storage 674