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_proxy.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 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 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_system_options.env_override(), 184 file_task_runner, 185 base::Bind(&GetTypeStringForURL), 186 GetKnownTypeStrings(), 187 this))), 188 file_system_usage_cache_(new FileSystemUsageCache(file_task_runner)), 189 quota_observer_(new SandboxQuotaObserver( 190 quota_manager_proxy, 191 file_task_runner, 192 obfuscated_file_util(), 193 usage_cache())), 194 quota_reservation_manager_(new QuotaReservationManager( 195 scoped_ptr<QuotaReservationManager::QuotaBackend>( 196 new QuotaBackendImpl(file_task_runner_, 197 obfuscated_file_util(), 198 usage_cache(), 199 quota_manager_proxy)))), 200 special_storage_policy_(special_storage_policy), 201 file_system_options_(file_system_options), 202 is_filesystem_opened_(false), 203 weak_factory_(this) { 204 // Prepopulate database only if it can run asynchronously (i.e. the current 205 // thread is not file_task_runner). Usually this is the case but may not 206 // in test code. 207 if (!file_system_options.is_incognito() && 208 !file_task_runner_->RunsTasksOnCurrentThread()) { 209 std::vector<std::string> types_to_prepopulate( 210 &kPrepopulateTypes[0], 211 &kPrepopulateTypes[arraysize(kPrepopulateTypes)]); 212 file_task_runner_->PostTask( 213 FROM_HERE, 214 base::Bind(&ObfuscatedFileUtil::MaybePrepopulateDatabase, 215 base::Unretained(obfuscated_file_util()), 216 types_to_prepopulate)); 217 } 218 } 219 220 SandboxFileSystemBackendDelegate::~SandboxFileSystemBackendDelegate() { 221 io_thread_checker_.DetachFromThread(); 222 223 if (!file_task_runner_->RunsTasksOnCurrentThread()) { 224 DeleteSoon(file_task_runner_.get(), quota_reservation_manager_.release()); 225 DeleteSoon(file_task_runner_.get(), sandbox_file_util_.release()); 226 DeleteSoon(file_task_runner_.get(), quota_observer_.release()); 227 DeleteSoon(file_task_runner_.get(), file_system_usage_cache_.release()); 228 } 229 } 230 231 SandboxFileSystemBackendDelegate::OriginEnumerator* 232 SandboxFileSystemBackendDelegate::CreateOriginEnumerator() { 233 return new ObfuscatedOriginEnumerator(obfuscated_file_util()); 234 } 235 236 base::FilePath 237 SandboxFileSystemBackendDelegate::GetBaseDirectoryForOriginAndType( 238 const GURL& origin_url, 239 FileSystemType type, 240 bool create) { 241 base::File::Error error = base::File::FILE_OK; 242 base::FilePath path = obfuscated_file_util()->GetDirectoryForOriginAndType( 243 origin_url, GetTypeString(type), create, &error); 244 if (error != base::File::FILE_OK) 245 return base::FilePath(); 246 return path; 247 } 248 249 void SandboxFileSystemBackendDelegate::OpenFileSystem( 250 const GURL& origin_url, 251 FileSystemType type, 252 OpenFileSystemMode mode, 253 const OpenFileSystemCallback& callback, 254 const GURL& root_url) { 255 if (!IsAllowedScheme(origin_url)) { 256 callback.Run(GURL(), std::string(), base::File::FILE_ERROR_SECURITY); 257 return; 258 } 259 260 std::string name = GetFileSystemName(origin_url, type); 261 262 base::File::Error* error_ptr = new base::File::Error; 263 file_task_runner_->PostTaskAndReply( 264 FROM_HERE, 265 base::Bind(&OpenFileSystemOnFileTaskRunner, 266 obfuscated_file_util(), origin_url, type, mode, 267 base::Unretained(error_ptr)), 268 base::Bind(&DidOpenFileSystem, 269 weak_factory_.GetWeakPtr(), 270 base::Bind(callback, root_url, name), 271 base::Owned(error_ptr))); 272 273 io_thread_checker_.DetachFromThread(); 274 is_filesystem_opened_ = true; 275 } 276 277 scoped_ptr<FileSystemOperationContext> 278 SandboxFileSystemBackendDelegate::CreateFileSystemOperationContext( 279 const FileSystemURL& url, 280 FileSystemContext* context, 281 base::File::Error* error_code) const { 282 if (!IsAccessValid(url)) { 283 *error_code = base::File::FILE_ERROR_SECURITY; 284 return scoped_ptr<FileSystemOperationContext>(); 285 } 286 287 const UpdateObserverList* update_observers = GetUpdateObservers(url.type()); 288 const ChangeObserverList* change_observers = GetChangeObservers(url.type()); 289 DCHECK(update_observers); 290 291 scoped_ptr<FileSystemOperationContext> operation_context( 292 new FileSystemOperationContext(context)); 293 operation_context->set_update_observers(*update_observers); 294 operation_context->set_change_observers( 295 change_observers ? *change_observers : ChangeObserverList()); 296 297 return operation_context.Pass(); 298 } 299 300 scoped_ptr<webkit_blob::FileStreamReader> 301 SandboxFileSystemBackendDelegate::CreateFileStreamReader( 302 const FileSystemURL& url, 303 int64 offset, 304 const base::Time& expected_modification_time, 305 FileSystemContext* context) const { 306 if (!IsAccessValid(url)) 307 return scoped_ptr<webkit_blob::FileStreamReader>(); 308 return scoped_ptr<webkit_blob::FileStreamReader>( 309 webkit_blob::FileStreamReader::CreateForFileSystemFile( 310 context, url, offset, expected_modification_time)); 311 } 312 313 scoped_ptr<FileStreamWriter> 314 SandboxFileSystemBackendDelegate::CreateFileStreamWriter( 315 const FileSystemURL& url, 316 int64 offset, 317 FileSystemContext* context, 318 FileSystemType type) const { 319 if (!IsAccessValid(url)) 320 return scoped_ptr<FileStreamWriter>(); 321 const UpdateObserverList* observers = GetUpdateObservers(type); 322 DCHECK(observers); 323 return scoped_ptr<FileStreamWriter>( 324 new SandboxFileStreamWriter(context, url, offset, *observers)); 325 } 326 327 base::File::Error 328 SandboxFileSystemBackendDelegate::DeleteOriginDataOnFileTaskRunner( 329 FileSystemContext* file_system_context, 330 quota::QuotaManagerProxy* proxy, 331 const GURL& origin_url, 332 FileSystemType type) { 333 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); 334 int64 usage = GetOriginUsageOnFileTaskRunner( 335 file_system_context, origin_url, type); 336 usage_cache()->CloseCacheFiles(); 337 bool result = obfuscated_file_util()->DeleteDirectoryForOriginAndType( 338 origin_url, GetTypeString(type)); 339 if (result && proxy) { 340 proxy->NotifyStorageModified( 341 quota::QuotaClient::kFileSystem, 342 origin_url, 343 FileSystemTypeToQuotaStorageType(type), 344 -usage); 345 } 346 347 if (result) 348 return base::File::FILE_OK; 349 return base::File::FILE_ERROR_FAILED; 350 } 351 352 void SandboxFileSystemBackendDelegate::GetOriginsForTypeOnFileTaskRunner( 353 FileSystemType type, std::set<GURL>* origins) { 354 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); 355 DCHECK(origins); 356 scoped_ptr<OriginEnumerator> enumerator(CreateOriginEnumerator()); 357 GURL origin; 358 while (!(origin = enumerator->Next()).is_empty()) { 359 if (enumerator->HasFileSystemType(type)) 360 origins->insert(origin); 361 } 362 switch (type) { 363 case kFileSystemTypeTemporary: 364 UMA_HISTOGRAM_COUNTS(kTemporaryOriginsCountLabel, origins->size()); 365 break; 366 case kFileSystemTypePersistent: 367 UMA_HISTOGRAM_COUNTS(kPersistentOriginsCountLabel, origins->size()); 368 break; 369 default: 370 break; 371 } 372 } 373 374 void SandboxFileSystemBackendDelegate::GetOriginsForHostOnFileTaskRunner( 375 FileSystemType type, const std::string& host, 376 std::set<GURL>* origins) { 377 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); 378 DCHECK(origins); 379 scoped_ptr<OriginEnumerator> enumerator(CreateOriginEnumerator()); 380 GURL origin; 381 while (!(origin = enumerator->Next()).is_empty()) { 382 if (host == net::GetHostOrSpecFromURL(origin) && 383 enumerator->HasFileSystemType(type)) 384 origins->insert(origin); 385 } 386 } 387 388 int64 SandboxFileSystemBackendDelegate::GetOriginUsageOnFileTaskRunner( 389 FileSystemContext* file_system_context, 390 const GURL& origin_url, 391 FileSystemType type) { 392 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); 393 394 // Don't use usage cache and return recalculated usage for sticky invalidated 395 // origins. 396 if (ContainsKey(sticky_dirty_origins_, std::make_pair(origin_url, type))) 397 return RecalculateUsage(file_system_context, origin_url, type); 398 399 base::FilePath base_path = 400 GetBaseDirectoryForOriginAndType(origin_url, type, false); 401 if (base_path.empty() || !base::DirectoryExists(base_path)) 402 return 0; 403 base::FilePath usage_file_path = 404 base_path.Append(FileSystemUsageCache::kUsageFileName); 405 406 bool is_valid = usage_cache()->IsValid(usage_file_path); 407 uint32 dirty_status = 0; 408 bool dirty_status_available = 409 usage_cache()->GetDirty(usage_file_path, &dirty_status); 410 bool visited = !visited_origins_.insert(origin_url).second; 411 if (is_valid && (dirty_status == 0 || (dirty_status_available && visited))) { 412 // The usage cache is clean (dirty == 0) or the origin is already 413 // initialized and running. Read the cache file to get the usage. 414 int64 usage = 0; 415 return usage_cache()->GetUsage(usage_file_path, &usage) ? usage : -1; 416 } 417 // The usage cache has not been initialized or the cache is dirty. 418 // Get the directory size now and update the cache. 419 usage_cache()->Delete(usage_file_path); 420 421 int64 usage = RecalculateUsage(file_system_context, origin_url, type); 422 423 // This clears the dirty flag too. 424 usage_cache()->UpdateUsage(usage_file_path, usage); 425 return usage; 426 } 427 428 scoped_refptr<QuotaReservation> 429 SandboxFileSystemBackendDelegate::CreateQuotaReservationOnFileTaskRunner( 430 const GURL& origin, 431 FileSystemType type) { 432 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); 433 DCHECK(quota_reservation_manager_); 434 return quota_reservation_manager_->CreateReservation(origin, type); 435 } 436 437 void SandboxFileSystemBackendDelegate::AddFileUpdateObserver( 438 FileSystemType type, 439 FileUpdateObserver* observer, 440 base::SequencedTaskRunner* task_runner) { 441 DCHECK(!is_filesystem_opened_ || io_thread_checker_.CalledOnValidThread()); 442 update_observers_[type] = 443 update_observers_[type].AddObserver(observer, task_runner); 444 } 445 446 void SandboxFileSystemBackendDelegate::AddFileChangeObserver( 447 FileSystemType type, 448 FileChangeObserver* observer, 449 base::SequencedTaskRunner* task_runner) { 450 DCHECK(!is_filesystem_opened_ || io_thread_checker_.CalledOnValidThread()); 451 change_observers_[type] = 452 change_observers_[type].AddObserver(observer, task_runner); 453 } 454 455 void SandboxFileSystemBackendDelegate::AddFileAccessObserver( 456 FileSystemType type, 457 FileAccessObserver* observer, 458 base::SequencedTaskRunner* task_runner) { 459 DCHECK(!is_filesystem_opened_ || io_thread_checker_.CalledOnValidThread()); 460 access_observers_[type] = 461 access_observers_[type].AddObserver(observer, task_runner); 462 } 463 464 const UpdateObserverList* SandboxFileSystemBackendDelegate::GetUpdateObservers( 465 FileSystemType type) const { 466 std::map<FileSystemType, UpdateObserverList>::const_iterator iter = 467 update_observers_.find(type); 468 if (iter == update_observers_.end()) 469 return NULL; 470 return &iter->second; 471 } 472 473 const ChangeObserverList* SandboxFileSystemBackendDelegate::GetChangeObservers( 474 FileSystemType type) const { 475 std::map<FileSystemType, ChangeObserverList>::const_iterator iter = 476 change_observers_.find(type); 477 if (iter == change_observers_.end()) 478 return NULL; 479 return &iter->second; 480 } 481 482 const AccessObserverList* SandboxFileSystemBackendDelegate::GetAccessObservers( 483 FileSystemType type) const { 484 std::map<FileSystemType, AccessObserverList>::const_iterator iter = 485 access_observers_.find(type); 486 if (iter == access_observers_.end()) 487 return NULL; 488 return &iter->second; 489 } 490 491 void SandboxFileSystemBackendDelegate::RegisterQuotaUpdateObserver( 492 FileSystemType type) { 493 AddFileUpdateObserver(type, quota_observer_.get(), file_task_runner_.get()); 494 } 495 496 void SandboxFileSystemBackendDelegate::InvalidateUsageCache( 497 const GURL& origin, 498 FileSystemType type) { 499 base::File::Error error = base::File::FILE_OK; 500 base::FilePath usage_file_path = GetUsageCachePathForOriginAndType( 501 obfuscated_file_util(), origin, type, &error); 502 if (error != base::File::FILE_OK) 503 return; 504 usage_cache()->IncrementDirty(usage_file_path); 505 } 506 507 void SandboxFileSystemBackendDelegate::StickyInvalidateUsageCache( 508 const GURL& origin, 509 FileSystemType type) { 510 sticky_dirty_origins_.insert(std::make_pair(origin, type)); 511 quota_observer()->SetUsageCacheEnabled(origin, type, false); 512 InvalidateUsageCache(origin, type); 513 } 514 515 FileSystemFileUtil* SandboxFileSystemBackendDelegate::sync_file_util() { 516 return static_cast<AsyncFileUtilAdapter*>(file_util())->sync_file_util(); 517 } 518 519 bool SandboxFileSystemBackendDelegate::IsAccessValid( 520 const FileSystemURL& url) const { 521 if (!IsAllowedScheme(url.origin())) 522 return false; 523 524 if (url.path().ReferencesParent()) 525 return false; 526 527 // Return earlier if the path is '/', because VirtualPath::BaseName() 528 // returns '/' for '/' and we fail the "basename != '/'" check below. 529 // (We exclude '.' because it's disallowed by spec.) 530 if (VirtualPath::IsRootPath(url.path()) && 531 url.path() != base::FilePath(base::FilePath::kCurrentDirectory)) 532 return true; 533 534 // Restricted names specified in 535 // http://dev.w3.org/2009/dap/file-system/file-dir-sys.html#naming-restrictions 536 base::FilePath filename = VirtualPath::BaseName(url.path()); 537 // See if the name is allowed to create. 538 for (size_t i = 0; i < arraysize(kRestrictedNames); ++i) { 539 if (filename.value() == kRestrictedNames[i]) 540 return false; 541 } 542 for (size_t i = 0; i < arraysize(kRestrictedChars); ++i) { 543 if (filename.value().find(kRestrictedChars[i]) != 544 base::FilePath::StringType::npos) 545 return false; 546 } 547 548 return true; 549 } 550 551 bool SandboxFileSystemBackendDelegate::IsAllowedScheme(const GURL& url) const { 552 // Basically we only accept http or https. We allow file:// URLs 553 // only if --allow-file-access-from-files flag is given. 554 if (url.SchemeIsHTTPOrHTTPS()) 555 return true; 556 if (url.SchemeIsFileSystem()) 557 return url.inner_url() && IsAllowedScheme(*url.inner_url()); 558 559 for (size_t i = 0; 560 i < file_system_options_.additional_allowed_schemes().size(); 561 ++i) { 562 if (url.SchemeIs( 563 file_system_options_.additional_allowed_schemes()[i].c_str())) 564 return true; 565 } 566 return false; 567 } 568 569 base::FilePath 570 SandboxFileSystemBackendDelegate::GetUsageCachePathForOriginAndType( 571 const GURL& origin_url, 572 FileSystemType type) { 573 base::File::Error error; 574 base::FilePath path = GetUsageCachePathForOriginAndType( 575 obfuscated_file_util(), origin_url, type, &error); 576 if (error != base::File::FILE_OK) 577 return base::FilePath(); 578 return path; 579 } 580 581 // static 582 base::FilePath 583 SandboxFileSystemBackendDelegate::GetUsageCachePathForOriginAndType( 584 ObfuscatedFileUtil* sandbox_file_util, 585 const GURL& origin_url, 586 FileSystemType type, 587 base::File::Error* error_out) { 588 DCHECK(error_out); 589 *error_out = base::File::FILE_OK; 590 base::FilePath base_path = sandbox_file_util->GetDirectoryForOriginAndType( 591 origin_url, GetTypeString(type), false /* create */, error_out); 592 if (*error_out != base::File::FILE_OK) 593 return base::FilePath(); 594 return base_path.Append(FileSystemUsageCache::kUsageFileName); 595 } 596 597 int64 SandboxFileSystemBackendDelegate::RecalculateUsage( 598 FileSystemContext* context, 599 const GURL& origin, 600 FileSystemType type) { 601 FileSystemOperationContext operation_context(context); 602 FileSystemURL url = context->CreateCrackedFileSystemURL( 603 origin, type, base::FilePath()); 604 scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator> enumerator( 605 obfuscated_file_util()->CreateFileEnumerator( 606 &operation_context, url, true)); 607 608 base::FilePath file_path_each; 609 int64 usage = 0; 610 611 while (!(file_path_each = enumerator->Next()).empty()) { 612 usage += enumerator->Size(); 613 usage += ObfuscatedFileUtil::ComputeFilePathCost(file_path_each); 614 } 615 616 return usage; 617 } 618 619 void SandboxFileSystemBackendDelegate::CollectOpenFileSystemMetrics( 620 base::File::Error error_code) { 621 base::Time now = base::Time::Now(); 622 bool throttled = now < next_release_time_for_open_filesystem_stat_; 623 if (!throttled) { 624 next_release_time_for_open_filesystem_stat_ = 625 now + base::TimeDelta::FromHours(kMinimumStatsCollectionIntervalHours); 626 } 627 628 #define REPORT(report_value) \ 629 UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemDetailLabel, \ 630 (report_value), \ 631 kFileSystemErrorMax); \ 632 if (!throttled) { \ 633 UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemDetailNonThrottledLabel, \ 634 (report_value), \ 635 kFileSystemErrorMax); \ 636 } 637 638 switch (error_code) { 639 case base::File::FILE_OK: 640 REPORT(kOK); 641 break; 642 case base::File::FILE_ERROR_INVALID_URL: 643 REPORT(kInvalidSchemeError); 644 break; 645 case base::File::FILE_ERROR_NOT_FOUND: 646 REPORT(kNotFound); 647 break; 648 case base::File::FILE_ERROR_FAILED: 649 default: 650 REPORT(kUnknownError); 651 break; 652 } 653 #undef REPORT 654 } 655 656 ObfuscatedFileUtil* SandboxFileSystemBackendDelegate::obfuscated_file_util() { 657 return static_cast<ObfuscatedFileUtil*>(sync_file_util()); 658 } 659 660 // Declared in obfuscated_file_util.h. 661 // static 662 ObfuscatedFileUtil* ObfuscatedFileUtil::CreateForTesting( 663 quota::SpecialStoragePolicy* special_storage_policy, 664 const base::FilePath& file_system_directory, 665 leveldb::Env* env_override, 666 base::SequencedTaskRunner* file_task_runner) { 667 return new ObfuscatedFileUtil(special_storage_policy, 668 file_system_directory, 669 env_override, 670 file_task_runner, 671 base::Bind(&GetTypeStringForURL), 672 GetKnownTypeStrings(), 673 NULL); 674 } 675 676 } // namespace fileapi 677