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 "storage/browser/fileapi/sandbox_file_system_backend_delegate.h"
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/fileapi/async_file_util_adapter.h"
16 #include "storage/browser/fileapi/file_stream_reader.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"
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 ~ObfuscatedOriginEnumerator() override
{}
97 GURL
Next() override
{ return enum_
->Next(); }
99 bool HasFileSystemType(FileSystemType type
) const override
{
100 return enum_
->HasTypeDirectory(
101 SandboxFileSystemBackendDelegate::GetTypeString(type
));
105 scoped_ptr
<ObfuscatedFileUtil::AbstractOriginEnumerator
> enum_
;
108 void OpenFileSystemOnFileTaskRunner(
109 ObfuscatedFileUtil
* file_util
,
110 const GURL
& origin_url
,
112 OpenFileSystemMode mode
,
113 base::File::Error
* error_ptr
) {
115 const bool create
= (mode
== OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT
);
116 file_util
->GetDirectoryForOriginAndType(
117 origin_url
, SandboxFileSystemBackendDelegate::GetTypeString(type
),
119 if (*error_ptr
!= base::File::FILE_OK
) {
120 UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemLabel
,
121 kCreateDirectoryError
,
122 kFileSystemErrorMax
);
124 UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemLabel
, kOK
, kFileSystemErrorMax
);
126 // The reference of file_util will be derefed on the FILE thread
127 // when the storage of this callback gets deleted regardless of whether
128 // this method is called or not.
131 void DidOpenFileSystem(
132 base::WeakPtr
<SandboxFileSystemBackendDelegate
> delegate
,
133 const base::Callback
<void(base::File::Error error
)>& callback
,
134 base::File::Error
* error
) {
136 delegate
.get()->CollectOpenFileSystemMetrics(*error
);
137 callback
.Run(*error
);
140 template <typename T
>
141 void DeleteSoon(base::SequencedTaskRunner
* runner
, T
* ptr
) {
142 if (!runner
->DeleteSoon(FROM_HERE
, ptr
))
148 const base::FilePath::CharType
149 SandboxFileSystemBackendDelegate::kFileSystemDirectory
[] =
150 FILE_PATH_LITERAL("File System");
153 std::string
SandboxFileSystemBackendDelegate::GetTypeString(
154 FileSystemType type
) {
156 case kFileSystemTypeTemporary
:
157 return kTemporaryDirectoryName
;
158 case kFileSystemTypePersistent
:
159 return kPersistentDirectoryName
;
160 case kFileSystemTypeSyncable
:
161 case kFileSystemTypeSyncableForInternalSync
:
162 return kSyncableDirectoryName
;
163 case kFileSystemTypeUnknown
:
165 NOTREACHED() << "Unknown filesystem type requested:" << type
;
166 return std::string();
170 SandboxFileSystemBackendDelegate::SandboxFileSystemBackendDelegate(
171 storage::QuotaManagerProxy
* quota_manager_proxy
,
172 base::SequencedTaskRunner
* file_task_runner
,
173 const base::FilePath
& profile_path
,
174 storage::SpecialStoragePolicy
* special_storage_policy
,
175 const FileSystemOptions
& file_system_options
)
176 : file_task_runner_(file_task_runner
),
177 sandbox_file_util_(new AsyncFileUtilAdapter(
178 new ObfuscatedFileUtil(special_storage_policy
,
179 profile_path
.Append(kFileSystemDirectory
),
180 file_system_options
.env_override(),
182 base::Bind(&GetTypeStringForURL
),
183 GetKnownTypeStrings(),
185 file_system_usage_cache_(new FileSystemUsageCache(file_task_runner
)),
186 quota_observer_(new SandboxQuotaObserver(quota_manager_proxy
,
188 obfuscated_file_util(),
190 quota_reservation_manager_(new QuotaReservationManager(
191 scoped_ptr
<QuotaReservationManager::QuotaBackend
>(
192 new QuotaBackendImpl(file_task_runner_
.get(),
193 obfuscated_file_util(),
195 quota_manager_proxy
)))),
196 special_storage_policy_(special_storage_policy
),
197 file_system_options_(file_system_options
),
198 is_filesystem_opened_(false),
199 weak_factory_(this) {
200 // Prepopulate database only if it can run asynchronously (i.e. the current
201 // thread is not file_task_runner). Usually this is the case but may not
203 if (!file_system_options
.is_incognito() &&
204 !file_task_runner_
->RunsTasksOnCurrentThread()) {
205 std::vector
<std::string
> types_to_prepopulate(
206 &kPrepopulateTypes
[0],
207 &kPrepopulateTypes
[arraysize(kPrepopulateTypes
)]);
208 file_task_runner_
->PostTask(
210 base::Bind(&ObfuscatedFileUtil::MaybePrepopulateDatabase
,
211 base::Unretained(obfuscated_file_util()),
212 types_to_prepopulate
));
216 SandboxFileSystemBackendDelegate::~SandboxFileSystemBackendDelegate() {
217 io_thread_checker_
.DetachFromThread();
219 if (!file_task_runner_
->RunsTasksOnCurrentThread()) {
220 DeleteSoon(file_task_runner_
.get(), quota_reservation_manager_
.release());
221 DeleteSoon(file_task_runner_
.get(), sandbox_file_util_
.release());
222 DeleteSoon(file_task_runner_
.get(), quota_observer_
.release());
223 DeleteSoon(file_task_runner_
.get(), file_system_usage_cache_
.release());
227 SandboxFileSystemBackendDelegate::OriginEnumerator
*
228 SandboxFileSystemBackendDelegate::CreateOriginEnumerator() {
229 return new ObfuscatedOriginEnumerator(obfuscated_file_util());
233 SandboxFileSystemBackendDelegate::GetBaseDirectoryForOriginAndType(
234 const GURL
& origin_url
,
237 base::File::Error error
= base::File::FILE_OK
;
238 base::FilePath path
= obfuscated_file_util()->GetDirectoryForOriginAndType(
239 origin_url
, GetTypeString(type
), create
, &error
);
240 if (error
!= base::File::FILE_OK
)
241 return base::FilePath();
245 void SandboxFileSystemBackendDelegate::OpenFileSystem(
246 const GURL
& origin_url
,
248 OpenFileSystemMode mode
,
249 const OpenFileSystemCallback
& callback
,
250 const GURL
& root_url
) {
251 if (!IsAllowedScheme(origin_url
)) {
252 callback
.Run(GURL(), std::string(), base::File::FILE_ERROR_SECURITY
);
256 std::string name
= GetFileSystemName(origin_url
, type
);
258 base::File::Error
* error_ptr
= new base::File::Error
;
259 file_task_runner_
->PostTaskAndReply(
261 base::Bind(&OpenFileSystemOnFileTaskRunner
,
262 obfuscated_file_util(), origin_url
, type
, mode
,
263 base::Unretained(error_ptr
)),
264 base::Bind(&DidOpenFileSystem
,
265 weak_factory_
.GetWeakPtr(),
266 base::Bind(callback
, root_url
, name
),
267 base::Owned(error_ptr
)));
269 io_thread_checker_
.DetachFromThread();
270 is_filesystem_opened_
= true;
273 scoped_ptr
<FileSystemOperationContext
>
274 SandboxFileSystemBackendDelegate::CreateFileSystemOperationContext(
275 const FileSystemURL
& url
,
276 FileSystemContext
* context
,
277 base::File::Error
* error_code
) const {
278 if (!IsAccessValid(url
)) {
279 *error_code
= base::File::FILE_ERROR_SECURITY
;
280 return scoped_ptr
<FileSystemOperationContext
>();
283 const UpdateObserverList
* update_observers
= GetUpdateObservers(url
.type());
284 const ChangeObserverList
* change_observers
= GetChangeObservers(url
.type());
285 DCHECK(update_observers
);
287 scoped_ptr
<FileSystemOperationContext
> operation_context(
288 new FileSystemOperationContext(context
));
289 operation_context
->set_update_observers(*update_observers
);
290 operation_context
->set_change_observers(
291 change_observers
? *change_observers
: ChangeObserverList());
293 return operation_context
.Pass();
296 scoped_ptr
<storage::FileStreamReader
>
297 SandboxFileSystemBackendDelegate::CreateFileStreamReader(
298 const FileSystemURL
& url
,
300 const base::Time
& expected_modification_time
,
301 FileSystemContext
* context
) const {
302 if (!IsAccessValid(url
))
303 return scoped_ptr
<storage::FileStreamReader
>();
304 return scoped_ptr
<storage::FileStreamReader
>(
305 storage::FileStreamReader::CreateForFileSystemFile(
306 context
, url
, offset
, expected_modification_time
));
309 scoped_ptr
<FileStreamWriter
>
310 SandboxFileSystemBackendDelegate::CreateFileStreamWriter(
311 const FileSystemURL
& url
,
313 FileSystemContext
* context
,
314 FileSystemType type
) const {
315 if (!IsAccessValid(url
))
316 return scoped_ptr
<FileStreamWriter
>();
317 const UpdateObserverList
* observers
= GetUpdateObservers(type
);
319 return scoped_ptr
<FileStreamWriter
>(
320 new SandboxFileStreamWriter(context
, url
, offset
, *observers
));
324 SandboxFileSystemBackendDelegate::DeleteOriginDataOnFileTaskRunner(
325 FileSystemContext
* file_system_context
,
326 storage::QuotaManagerProxy
* proxy
,
327 const GURL
& origin_url
,
328 FileSystemType type
) {
329 DCHECK(file_task_runner_
->RunsTasksOnCurrentThread());
330 int64 usage
= GetOriginUsageOnFileTaskRunner(
331 file_system_context
, origin_url
, type
);
332 usage_cache()->CloseCacheFiles();
333 bool result
= obfuscated_file_util()->DeleteDirectoryForOriginAndType(
334 origin_url
, GetTypeString(type
));
335 if (result
&& proxy
) {
336 proxy
->NotifyStorageModified(storage::QuotaClient::kFileSystem
,
338 FileSystemTypeToQuotaStorageType(type
),
343 return base::File::FILE_OK
;
344 return base::File::FILE_ERROR_FAILED
;
347 void SandboxFileSystemBackendDelegate::GetOriginsForTypeOnFileTaskRunner(
348 FileSystemType type
, std::set
<GURL
>* origins
) {
349 DCHECK(file_task_runner_
->RunsTasksOnCurrentThread());
351 scoped_ptr
<OriginEnumerator
> enumerator(CreateOriginEnumerator());
353 while (!(origin
= enumerator
->Next()).is_empty()) {
354 if (enumerator
->HasFileSystemType(type
))
355 origins
->insert(origin
);
358 case kFileSystemTypeTemporary
:
359 UMA_HISTOGRAM_COUNTS(kTemporaryOriginsCountLabel
, origins
->size());
361 case kFileSystemTypePersistent
:
362 UMA_HISTOGRAM_COUNTS(kPersistentOriginsCountLabel
, origins
->size());
369 void SandboxFileSystemBackendDelegate::GetOriginsForHostOnFileTaskRunner(
370 FileSystemType type
, const std::string
& host
,
371 std::set
<GURL
>* origins
) {
372 DCHECK(file_task_runner_
->RunsTasksOnCurrentThread());
374 scoped_ptr
<OriginEnumerator
> enumerator(CreateOriginEnumerator());
376 while (!(origin
= enumerator
->Next()).is_empty()) {
377 if (host
== net::GetHostOrSpecFromURL(origin
) &&
378 enumerator
->HasFileSystemType(type
))
379 origins
->insert(origin
);
383 int64
SandboxFileSystemBackendDelegate::GetOriginUsageOnFileTaskRunner(
384 FileSystemContext
* file_system_context
,
385 const GURL
& origin_url
,
386 FileSystemType type
) {
387 DCHECK(file_task_runner_
->RunsTasksOnCurrentThread());
389 // Don't use usage cache and return recalculated usage for sticky invalidated
391 if (ContainsKey(sticky_dirty_origins_
, std::make_pair(origin_url
, type
)))
392 return RecalculateUsage(file_system_context
, origin_url
, type
);
394 base::FilePath base_path
=
395 GetBaseDirectoryForOriginAndType(origin_url
, type
, false);
396 if (base_path
.empty() || !base::DirectoryExists(base_path
))
398 base::FilePath usage_file_path
=
399 base_path
.Append(FileSystemUsageCache::kUsageFileName
);
401 bool is_valid
= usage_cache()->IsValid(usage_file_path
);
402 uint32 dirty_status
= 0;
403 bool dirty_status_available
=
404 usage_cache()->GetDirty(usage_file_path
, &dirty_status
);
405 bool visited
= !visited_origins_
.insert(origin_url
).second
;
406 if (is_valid
&& (dirty_status
== 0 || (dirty_status_available
&& visited
))) {
407 // The usage cache is clean (dirty == 0) or the origin is already
408 // initialized and running. Read the cache file to get the usage.
410 return usage_cache()->GetUsage(usage_file_path
, &usage
) ? usage
: -1;
412 // The usage cache has not been initialized or the cache is dirty.
413 // Get the directory size now and update the cache.
414 usage_cache()->Delete(usage_file_path
);
416 int64 usage
= RecalculateUsage(file_system_context
, origin_url
, type
);
418 // This clears the dirty flag too.
419 usage_cache()->UpdateUsage(usage_file_path
, usage
);
423 scoped_refptr
<QuotaReservation
>
424 SandboxFileSystemBackendDelegate::CreateQuotaReservationOnFileTaskRunner(
426 FileSystemType type
) {
427 DCHECK(file_task_runner_
->RunsTasksOnCurrentThread());
428 DCHECK(quota_reservation_manager_
);
429 return quota_reservation_manager_
->CreateReservation(origin
, type
);
432 void SandboxFileSystemBackendDelegate::AddFileUpdateObserver(
434 FileUpdateObserver
* observer
,
435 base::SequencedTaskRunner
* task_runner
) {
436 DCHECK(!is_filesystem_opened_
|| io_thread_checker_
.CalledOnValidThread());
437 update_observers_
[type
] =
438 update_observers_
[type
].AddObserver(observer
, task_runner
);
441 void SandboxFileSystemBackendDelegate::AddFileChangeObserver(
443 FileChangeObserver
* observer
,
444 base::SequencedTaskRunner
* task_runner
) {
445 DCHECK(!is_filesystem_opened_
|| io_thread_checker_
.CalledOnValidThread());
446 change_observers_
[type
] =
447 change_observers_
[type
].AddObserver(observer
, task_runner
);
450 void SandboxFileSystemBackendDelegate::AddFileAccessObserver(
452 FileAccessObserver
* observer
,
453 base::SequencedTaskRunner
* task_runner
) {
454 DCHECK(!is_filesystem_opened_
|| io_thread_checker_
.CalledOnValidThread());
455 access_observers_
[type
] =
456 access_observers_
[type
].AddObserver(observer
, task_runner
);
459 const UpdateObserverList
* SandboxFileSystemBackendDelegate::GetUpdateObservers(
460 FileSystemType type
) const {
461 std::map
<FileSystemType
, UpdateObserverList
>::const_iterator iter
=
462 update_observers_
.find(type
);
463 if (iter
== update_observers_
.end())
465 return &iter
->second
;
468 const ChangeObserverList
* SandboxFileSystemBackendDelegate::GetChangeObservers(
469 FileSystemType type
) const {
470 std::map
<FileSystemType
, ChangeObserverList
>::const_iterator iter
=
471 change_observers_
.find(type
);
472 if (iter
== change_observers_
.end())
474 return &iter
->second
;
477 const AccessObserverList
* SandboxFileSystemBackendDelegate::GetAccessObservers(
478 FileSystemType type
) const {
479 std::map
<FileSystemType
, AccessObserverList
>::const_iterator iter
=
480 access_observers_
.find(type
);
481 if (iter
== access_observers_
.end())
483 return &iter
->second
;
486 void SandboxFileSystemBackendDelegate::RegisterQuotaUpdateObserver(
487 FileSystemType type
) {
488 AddFileUpdateObserver(type
, quota_observer_
.get(), file_task_runner_
.get());
491 void SandboxFileSystemBackendDelegate::InvalidateUsageCache(
493 FileSystemType type
) {
494 base::File::Error error
= base::File::FILE_OK
;
495 base::FilePath usage_file_path
= GetUsageCachePathForOriginAndType(
496 obfuscated_file_util(), origin
, type
, &error
);
497 if (error
!= base::File::FILE_OK
)
499 usage_cache()->IncrementDirty(usage_file_path
);
502 void SandboxFileSystemBackendDelegate::StickyInvalidateUsageCache(
504 FileSystemType type
) {
505 sticky_dirty_origins_
.insert(std::make_pair(origin
, type
));
506 quota_observer()->SetUsageCacheEnabled(origin
, type
, false);
507 InvalidateUsageCache(origin
, type
);
510 FileSystemFileUtil
* SandboxFileSystemBackendDelegate::sync_file_util() {
511 return static_cast<AsyncFileUtilAdapter
*>(file_util())->sync_file_util();
514 bool SandboxFileSystemBackendDelegate::IsAccessValid(
515 const FileSystemURL
& url
) const {
516 if (!IsAllowedScheme(url
.origin()))
519 if (url
.path().ReferencesParent())
522 // Return earlier if the path is '/', because VirtualPath::BaseName()
523 // returns '/' for '/' and we fail the "basename != '/'" check below.
524 // (We exclude '.' because it's disallowed by spec.)
525 if (VirtualPath::IsRootPath(url
.path()) &&
526 url
.path() != base::FilePath(base::FilePath::kCurrentDirectory
))
529 // Restricted names specified in
530 // http://dev.w3.org/2009/dap/file-system/file-dir-sys.html#naming-restrictions
531 base::FilePath filename
= VirtualPath::BaseName(url
.path());
532 // See if the name is allowed to create.
533 for (size_t i
= 0; i
< arraysize(kRestrictedNames
); ++i
) {
534 if (filename
.value() == kRestrictedNames
[i
])
537 for (size_t i
= 0; i
< arraysize(kRestrictedChars
); ++i
) {
538 if (filename
.value().find(kRestrictedChars
[i
]) !=
539 base::FilePath::StringType::npos
)
546 bool SandboxFileSystemBackendDelegate::IsAllowedScheme(const GURL
& url
) const {
547 // Basically we only accept http or https. We allow file:// URLs
548 // only if --allow-file-access-from-files flag is given.
549 if (url
.SchemeIsHTTPOrHTTPS())
551 if (url
.SchemeIsFileSystem())
552 return url
.inner_url() && IsAllowedScheme(*url
.inner_url());
555 i
< file_system_options_
.additional_allowed_schemes().size();
558 file_system_options_
.additional_allowed_schemes()[i
].c_str()))
565 SandboxFileSystemBackendDelegate::GetUsageCachePathForOriginAndType(
566 const GURL
& origin_url
,
567 FileSystemType type
) {
568 base::File::Error error
;
569 base::FilePath path
= GetUsageCachePathForOriginAndType(
570 obfuscated_file_util(), origin_url
, type
, &error
);
571 if (error
!= base::File::FILE_OK
)
572 return base::FilePath();
578 SandboxFileSystemBackendDelegate::GetUsageCachePathForOriginAndType(
579 ObfuscatedFileUtil
* sandbox_file_util
,
580 const GURL
& origin_url
,
582 base::File::Error
* error_out
) {
584 *error_out
= base::File::FILE_OK
;
585 base::FilePath base_path
= sandbox_file_util
->GetDirectoryForOriginAndType(
586 origin_url
, GetTypeString(type
), false /* create */, error_out
);
587 if (*error_out
!= base::File::FILE_OK
)
588 return base::FilePath();
589 return base_path
.Append(FileSystemUsageCache::kUsageFileName
);
592 int64
SandboxFileSystemBackendDelegate::RecalculateUsage(
593 FileSystemContext
* context
,
595 FileSystemType type
) {
596 FileSystemOperationContext
operation_context(context
);
597 FileSystemURL url
= context
->CreateCrackedFileSystemURL(
598 origin
, type
, base::FilePath());
599 scoped_ptr
<FileSystemFileUtil::AbstractFileEnumerator
> enumerator(
600 obfuscated_file_util()->CreateFileEnumerator(
601 &operation_context
, url
, true));
603 base::FilePath file_path_each
;
606 while (!(file_path_each
= enumerator
->Next()).empty()) {
607 usage
+= enumerator
->Size();
608 usage
+= ObfuscatedFileUtil::ComputeFilePathCost(file_path_each
);
614 void SandboxFileSystemBackendDelegate::CollectOpenFileSystemMetrics(
615 base::File::Error error_code
) {
616 base::Time now
= base::Time::Now();
617 bool throttled
= now
< next_release_time_for_open_filesystem_stat_
;
619 next_release_time_for_open_filesystem_stat_
=
620 now
+ base::TimeDelta::FromHours(kMinimumStatsCollectionIntervalHours
);
623 #define REPORT(report_value) \
624 UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemDetailLabel, \
626 kFileSystemErrorMax); \
628 UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemDetailNonThrottledLabel, \
630 kFileSystemErrorMax); \
633 switch (error_code
) {
634 case base::File::FILE_OK
:
637 case base::File::FILE_ERROR_INVALID_URL
:
638 REPORT(kInvalidSchemeError
);
640 case base::File::FILE_ERROR_NOT_FOUND
:
643 case base::File::FILE_ERROR_FAILED
:
645 REPORT(kUnknownError
);
651 void SandboxFileSystemBackendDelegate::CopyFileSystem(
652 const GURL
& origin_url
,
654 SandboxFileSystemBackendDelegate
* destination
) {
655 DCHECK(file_task_runner()->RunsTasksOnCurrentThread());
657 base::FilePath base_path
=
658 GetBaseDirectoryForOriginAndType(origin_url
, type
, false /* create */);
659 if (base::PathExists(base_path
)) {
660 // Delete any existing file system directories in the destination. A
661 // previously failed migration
662 // may have left behind partially copied directories.
663 base::FilePath dest_path
= destination
->GetBaseDirectoryForOriginAndType(
664 origin_url
, type
, false /* create */);
666 // Make sure we're not about to delete our own file system.
667 CHECK_NE(base_path
.value(), dest_path
.value());
668 base::DeleteFile(dest_path
, true);
670 dest_path
= destination
->GetBaseDirectoryForOriginAndType(
671 origin_url
, type
, true /* create */);
673 obfuscated_file_util()->CloseFileSystemForOriginAndType(
674 origin_url
, GetTypeString(type
));
675 base::CopyDirectory(base_path
, dest_path
.DirName(), true /* rescursive */);
679 ObfuscatedFileUtil
* SandboxFileSystemBackendDelegate::obfuscated_file_util() {
680 return static_cast<ObfuscatedFileUtil
*>(sync_file_util());
683 // Declared in obfuscated_file_util.h.
685 ObfuscatedFileUtil
* ObfuscatedFileUtil::CreateForTesting(
686 storage::SpecialStoragePolicy
* special_storage_policy
,
687 const base::FilePath
& file_system_directory
,
688 leveldb::Env
* env_override
,
689 base::SequencedTaskRunner
* file_task_runner
) {
690 return new ObfuscatedFileUtil(special_storage_policy
,
691 file_system_directory
,
694 base::Bind(&GetTypeStringForURL
),
695 GetKnownTypeStrings(),
699 } // namespace storage