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