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 "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