Home | History | Annotate | Download | only in fileapi
      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