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.
5 #include "webkit/browser/fileapi/sandbox_file_system_backend_delegate.h"
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"
35 const char kTemporaryOriginsCountLabel
[] = "FileSystem.TemporaryOriginsCount";
36 const char kPersistentOriginsCountLabel
[] = "FileSystem.PersistentOriginsCount";
38 const char kOpenFileSystemLabel
[] = "FileSystem.OpenFileSystem";
39 const char kOpenFileSystemDetailLabel
[] = "FileSystem.OpenFileSystemDetail";
40 const char kOpenFileSystemDetailNonThrottledLabel
[] =
41 "FileSystem.OpenFileSystemDetailNonthrottled";
42 int64 kMinimumStatsCollectionIntervalHours
= 1;
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";
51 const char* kPrepopulateTypes
[] = {
52 kPersistentDirectoryName
,
53 kTemporaryDirectoryName
56 enum FileSystemError
{
60 kCreateDirectoryError
,
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(".."),
73 const base::FilePath::CharType kRestrictedChars
[] = {
74 FILE_PATH_LITERAL('/'), FILE_PATH_LITERAL('\\'),
77 std::string
GetTypeStringForURL(const FileSystemURL
& url
) {
78 return SandboxFileSystemBackendDelegate::GetTypeString(url
.type());
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
;
89 class ObfuscatedOriginEnumerator
90 : public SandboxFileSystemBackendDelegate::OriginEnumerator
{
92 explicit ObfuscatedOriginEnumerator(ObfuscatedFileUtil
* file_util
) {
93 enum_
.reset(file_util
->CreateOriginEnumerator());
95 virtual ~ObfuscatedOriginEnumerator() {}
97 virtual GURL
Next() OVERRIDE
{
101 virtual bool HasFileSystemType(FileSystemType type
) const OVERRIDE
{
102 return enum_
->HasTypeDirectory(
103 SandboxFileSystemBackendDelegate::GetTypeString(type
));
107 scoped_ptr
<ObfuscatedFileUtil::AbstractOriginEnumerator
> enum_
;
110 void OpenFileSystemOnFileTaskRunner(
111 ObfuscatedFileUtil
* file_util
,
112 const GURL
& origin_url
,
114 OpenFileSystemMode mode
,
115 base::File::Error
* error_ptr
) {
117 const bool create
= (mode
== OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT
);
118 file_util
->GetDirectoryForOriginAndType(
119 origin_url
, SandboxFileSystemBackendDelegate::GetTypeString(type
),
121 if (*error_ptr
!= base::File::FILE_OK
) {
122 UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemLabel
,
123 kCreateDirectoryError
,
124 kFileSystemErrorMax
);
126 UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemLabel
, kOK
, kFileSystemErrorMax
);
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.
133 void DidOpenFileSystem(
134 base::WeakPtr
<SandboxFileSystemBackendDelegate
> delegate
,
135 const base::Callback
<void(base::File::Error error
)>& callback
,
136 base::File::Error
* error
) {
138 delegate
.get()->CollectOpenFileSystemMetrics(*error
);
139 callback
.Run(*error
);
142 template <typename T
>
143 void DeleteSoon(base::SequencedTaskRunner
* runner
, T
* ptr
) {
144 if (!runner
->DeleteSoon(FROM_HERE
, ptr
))
150 const base::FilePath::CharType
151 SandboxFileSystemBackendDelegate::kFileSystemDirectory
[] =
152 FILE_PATH_LITERAL("File System");
155 std::string
SandboxFileSystemBackendDelegate::GetTypeString(
156 FileSystemType 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
:
167 NOTREACHED() << "Unknown filesystem type requested:" << type
;
168 return std::string();
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(),
185 base::Bind(&GetTypeStringForURL
),
186 GetKnownTypeStrings(),
188 file_system_usage_cache_(new FileSystemUsageCache(file_task_runner
)),
189 quota_observer_(new SandboxQuotaObserver(
192 obfuscated_file_util(),
194 quota_reservation_manager_(new QuotaReservationManager(
195 scoped_ptr
<QuotaReservationManager::QuotaBackend
>(
196 new QuotaBackendImpl(file_task_runner_
,
197 obfuscated_file_util(),
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
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(
214 base::Bind(&ObfuscatedFileUtil::MaybePrepopulateDatabase
,
215 base::Unretained(obfuscated_file_util()),
216 types_to_prepopulate
));
220 SandboxFileSystemBackendDelegate::~SandboxFileSystemBackendDelegate() {
221 io_thread_checker_
.DetachFromThread();
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());
231 SandboxFileSystemBackendDelegate::OriginEnumerator
*
232 SandboxFileSystemBackendDelegate::CreateOriginEnumerator() {
233 return new ObfuscatedOriginEnumerator(obfuscated_file_util());
237 SandboxFileSystemBackendDelegate::GetBaseDirectoryForOriginAndType(
238 const GURL
& origin_url
,
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();
249 void SandboxFileSystemBackendDelegate::OpenFileSystem(
250 const GURL
& origin_url
,
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
);
260 std::string name
= GetFileSystemName(origin_url
, type
);
262 base::File::Error
* error_ptr
= new base::File::Error
;
263 file_task_runner_
->PostTaskAndReply(
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
)));
273 io_thread_checker_
.DetachFromThread();
274 is_filesystem_opened_
= true;
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
>();
287 const UpdateObserverList
* update_observers
= GetUpdateObservers(url
.type());
288 const ChangeObserverList
* change_observers
= GetChangeObservers(url
.type());
289 DCHECK(update_observers
);
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());
297 return operation_context
.Pass();
300 scoped_ptr
<webkit_blob::FileStreamReader
>
301 SandboxFileSystemBackendDelegate::CreateFileStreamReader(
302 const FileSystemURL
& url
,
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
));
313 scoped_ptr
<FileStreamWriter
>
314 SandboxFileSystemBackendDelegate::CreateFileStreamWriter(
315 const FileSystemURL
& url
,
317 FileSystemContext
* context
,
318 FileSystemType type
) const {
319 if (!IsAccessValid(url
))
320 return scoped_ptr
<FileStreamWriter
>();
321 const UpdateObserverList
* observers
= GetUpdateObservers(type
);
323 return scoped_ptr
<FileStreamWriter
>(
324 new SandboxFileStreamWriter(context
, url
, offset
, *observers
));
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
,
343 FileSystemTypeToQuotaStorageType(type
),
348 return base::File::FILE_OK
;
349 return base::File::FILE_ERROR_FAILED
;
352 void SandboxFileSystemBackendDelegate::GetOriginsForTypeOnFileTaskRunner(
353 FileSystemType type
, std::set
<GURL
>* origins
) {
354 DCHECK(file_task_runner_
->RunsTasksOnCurrentThread());
356 scoped_ptr
<OriginEnumerator
> enumerator(CreateOriginEnumerator());
358 while (!(origin
= enumerator
->Next()).is_empty()) {
359 if (enumerator
->HasFileSystemType(type
))
360 origins
->insert(origin
);
363 case kFileSystemTypeTemporary
:
364 UMA_HISTOGRAM_COUNTS(kTemporaryOriginsCountLabel
, origins
->size());
366 case kFileSystemTypePersistent
:
367 UMA_HISTOGRAM_COUNTS(kPersistentOriginsCountLabel
, origins
->size());
374 void SandboxFileSystemBackendDelegate::GetOriginsForHostOnFileTaskRunner(
375 FileSystemType type
, const std::string
& host
,
376 std::set
<GURL
>* origins
) {
377 DCHECK(file_task_runner_
->RunsTasksOnCurrentThread());
379 scoped_ptr
<OriginEnumerator
> enumerator(CreateOriginEnumerator());
381 while (!(origin
= enumerator
->Next()).is_empty()) {
382 if (host
== net::GetHostOrSpecFromURL(origin
) &&
383 enumerator
->HasFileSystemType(type
))
384 origins
->insert(origin
);
388 int64
SandboxFileSystemBackendDelegate::GetOriginUsageOnFileTaskRunner(
389 FileSystemContext
* file_system_context
,
390 const GURL
& origin_url
,
391 FileSystemType type
) {
392 DCHECK(file_task_runner_
->RunsTasksOnCurrentThread());
394 // Don't use usage cache and return recalculated usage for sticky invalidated
396 if (ContainsKey(sticky_dirty_origins_
, std::make_pair(origin_url
, type
)))
397 return RecalculateUsage(file_system_context
, origin_url
, type
);
399 base::FilePath base_path
=
400 GetBaseDirectoryForOriginAndType(origin_url
, type
, false);
401 if (base_path
.empty() || !base::DirectoryExists(base_path
))
403 base::FilePath usage_file_path
=
404 base_path
.Append(FileSystemUsageCache::kUsageFileName
);
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.
415 return usage_cache()->GetUsage(usage_file_path
, &usage
) ? usage
: -1;
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
);
421 int64 usage
= RecalculateUsage(file_system_context
, origin_url
, type
);
423 // This clears the dirty flag too.
424 usage_cache()->UpdateUsage(usage_file_path
, usage
);
428 scoped_refptr
<QuotaReservation
>
429 SandboxFileSystemBackendDelegate::CreateQuotaReservationOnFileTaskRunner(
431 FileSystemType type
) {
432 DCHECK(file_task_runner_
->RunsTasksOnCurrentThread());
433 DCHECK(quota_reservation_manager_
);
434 return quota_reservation_manager_
->CreateReservation(origin
, type
);
437 void SandboxFileSystemBackendDelegate::AddFileUpdateObserver(
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
);
446 void SandboxFileSystemBackendDelegate::AddFileChangeObserver(
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
);
455 void SandboxFileSystemBackendDelegate::AddFileAccessObserver(
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
);
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())
470 return &iter
->second
;
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())
479 return &iter
->second
;
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())
488 return &iter
->second
;
491 void SandboxFileSystemBackendDelegate::RegisterQuotaUpdateObserver(
492 FileSystemType type
) {
493 AddFileUpdateObserver(type
, quota_observer_
.get(), file_task_runner_
.get());
496 void SandboxFileSystemBackendDelegate::InvalidateUsageCache(
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
)
504 usage_cache()->IncrementDirty(usage_file_path
);
507 void SandboxFileSystemBackendDelegate::StickyInvalidateUsageCache(
509 FileSystemType type
) {
510 sticky_dirty_origins_
.insert(std::make_pair(origin
, type
));
511 quota_observer()->SetUsageCacheEnabled(origin
, type
, false);
512 InvalidateUsageCache(origin
, type
);
515 FileSystemFileUtil
* SandboxFileSystemBackendDelegate::sync_file_util() {
516 return static_cast<AsyncFileUtilAdapter
*>(file_util())->sync_file_util();
519 bool SandboxFileSystemBackendDelegate::IsAccessValid(
520 const FileSystemURL
& url
) const {
521 if (!IsAllowedScheme(url
.origin()))
524 if (url
.path().ReferencesParent())
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
))
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
])
542 for (size_t i
= 0; i
< arraysize(kRestrictedChars
); ++i
) {
543 if (filename
.value().find(kRestrictedChars
[i
]) !=
544 base::FilePath::StringType::npos
)
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())
556 if (url
.SchemeIsFileSystem())
557 return url
.inner_url() && IsAllowedScheme(*url
.inner_url());
560 i
< file_system_options_
.additional_allowed_schemes().size();
563 file_system_options_
.additional_allowed_schemes()[i
].c_str()))
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();
583 SandboxFileSystemBackendDelegate::GetUsageCachePathForOriginAndType(
584 ObfuscatedFileUtil
* sandbox_file_util
,
585 const GURL
& origin_url
,
587 base::File::Error
* 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
);
597 int64
SandboxFileSystemBackendDelegate::RecalculateUsage(
598 FileSystemContext
* context
,
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));
608 base::FilePath file_path_each
;
611 while (!(file_path_each
= enumerator
->Next()).empty()) {
612 usage
+= enumerator
->Size();
613 usage
+= ObfuscatedFileUtil::ComputeFilePathCost(file_path_each
);
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_
;
624 next_release_time_for_open_filesystem_stat_
=
625 now
+ base::TimeDelta::FromHours(kMinimumStatsCollectionIntervalHours
);
628 #define REPORT(report_value) \
629 UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemDetailLabel, \
631 kFileSystemErrorMax); \
633 UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemDetailNonThrottledLabel, \
635 kFileSystemErrorMax); \
638 switch (error_code
) {
639 case base::File::FILE_OK
:
642 case base::File::FILE_ERROR_INVALID_URL
:
643 REPORT(kInvalidSchemeError
);
645 case base::File::FILE_ERROR_NOT_FOUND
:
648 case base::File::FILE_ERROR_FAILED
:
650 REPORT(kUnknownError
);
656 ObfuscatedFileUtil
* SandboxFileSystemBackendDelegate::obfuscated_file_util() {
657 return static_cast<ObfuscatedFileUtil
*>(sync_file_util());
660 // Declared in obfuscated_file_util.h.
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
,
671 base::Bind(&GetTypeStringForURL
),
672 GetKnownTypeStrings(),
676 } // namespace fileapi