Include all dupe types (event when value is zero) in scan stats.
[chromium-blink-merge.git] / storage / browser / fileapi / sandbox_file_system_backend_delegate.cc
blobcf06875b197822126ffbbd765c34976fc29ee69d
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"
7 #include <vector>
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"
31 namespace storage {
33 namespace {
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 {
57 kOK = 0,
58 kIncognito,
59 kInvalidSchemeError,
60 kCreateDirectoryError,
61 kNotFound,
62 kUnknownError,
63 kFileSystemErrorMax,
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(".."),
72 // Restricted chars.
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 {
91 public:
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));
104 private:
105 scoped_ptr<ObfuscatedFileUtil::AbstractOriginEnumerator> enum_;
108 void OpenFileSystemOnFileTaskRunner(
109 ObfuscatedFileUtil* file_util,
110 const GURL& origin_url,
111 FileSystemType type,
112 OpenFileSystemMode mode,
113 base::File::Error* error_ptr) {
114 DCHECK(error_ptr);
115 const bool create = (mode == OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT);
116 file_util->GetDirectoryForOriginAndType(
117 origin_url, SandboxFileSystemBackendDelegate::GetTypeString(type),
118 create, error_ptr);
119 if (*error_ptr != base::File::FILE_OK) {
120 UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemLabel,
121 kCreateDirectoryError,
122 kFileSystemErrorMax);
123 } else {
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) {
135 if (delegate.get())
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))
143 delete ptr;
146 } // namespace
148 const base::FilePath::CharType
149 SandboxFileSystemBackendDelegate::kFileSystemDirectory[] =
150 FILE_PATH_LITERAL("File System");
152 // static
153 std::string SandboxFileSystemBackendDelegate::GetTypeString(
154 FileSystemType type) {
155 switch (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:
164 default:
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(),
181 file_task_runner,
182 base::Bind(&GetTypeStringForURL),
183 GetKnownTypeStrings(),
184 this))),
185 file_system_usage_cache_(new FileSystemUsageCache(file_task_runner)),
186 quota_observer_(new SandboxQuotaObserver(quota_manager_proxy,
187 file_task_runner,
188 obfuscated_file_util(),
189 usage_cache())),
190 quota_reservation_manager_(new QuotaReservationManager(
191 scoped_ptr<QuotaReservationManager::QuotaBackend>(
192 new QuotaBackendImpl(file_task_runner_.get(),
193 obfuscated_file_util(),
194 usage_cache(),
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
202 // in test code.
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(
209 FROM_HERE,
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());
232 base::FilePath
233 SandboxFileSystemBackendDelegate::GetBaseDirectoryForOriginAndType(
234 const GURL& origin_url,
235 FileSystemType type,
236 bool create) {
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();
242 return path;
245 void SandboxFileSystemBackendDelegate::OpenFileSystem(
246 const GURL& origin_url,
247 FileSystemType type,
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);
253 return;
256 std::string name = GetFileSystemName(origin_url, type);
258 base::File::Error* error_ptr = new base::File::Error;
259 file_task_runner_->PostTaskAndReply(
260 FROM_HERE,
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,
299 int64 offset,
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,
312 int64 offset,
313 FileSystemContext* context,
314 FileSystemType type) const {
315 if (!IsAccessValid(url))
316 return scoped_ptr<FileStreamWriter>();
317 const UpdateObserverList* observers = GetUpdateObservers(type);
318 DCHECK(observers);
319 return scoped_ptr<FileStreamWriter>(
320 new SandboxFileStreamWriter(context, url, offset, *observers));
323 base::File::Error
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,
337 origin_url,
338 FileSystemTypeToQuotaStorageType(type),
339 -usage);
342 if (result)
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());
350 DCHECK(origins);
351 scoped_ptr<OriginEnumerator> enumerator(CreateOriginEnumerator());
352 GURL origin;
353 while (!(origin = enumerator->Next()).is_empty()) {
354 if (enumerator->HasFileSystemType(type))
355 origins->insert(origin);
357 switch (type) {
358 case kFileSystemTypeTemporary:
359 UMA_HISTOGRAM_COUNTS(kTemporaryOriginsCountLabel, origins->size());
360 break;
361 case kFileSystemTypePersistent:
362 UMA_HISTOGRAM_COUNTS(kPersistentOriginsCountLabel, origins->size());
363 break;
364 default:
365 break;
369 void SandboxFileSystemBackendDelegate::GetOriginsForHostOnFileTaskRunner(
370 FileSystemType type, const std::string& host,
371 std::set<GURL>* origins) {
372 DCHECK(file_task_runner_->RunsTasksOnCurrentThread());
373 DCHECK(origins);
374 scoped_ptr<OriginEnumerator> enumerator(CreateOriginEnumerator());
375 GURL origin;
376 while (!(origin = enumerator->Next()).is_empty()) {
377 if (host == net::GetHostOrSpecFromURL(origin) &&
378 enumerator->HasFileSystemType(type))
379 origins->insert(origin);
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
390 // origins.
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))
397 return 0;
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.
409 int64 usage = 0;
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);
420 return usage;
423 scoped_refptr<QuotaReservation>
424 SandboxFileSystemBackendDelegate::CreateQuotaReservationOnFileTaskRunner(
425 const GURL& origin,
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(
433 FileSystemType type,
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(
442 FileSystemType type,
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(
451 FileSystemType type,
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())
464 return NULL;
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())
473 return NULL;
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())
482 return NULL;
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(
492 const GURL& origin,
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)
498 return;
499 usage_cache()->IncrementDirty(usage_file_path);
502 void SandboxFileSystemBackendDelegate::StickyInvalidateUsageCache(
503 const GURL& origin,
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()))
517 return false;
519 if (url.path().ReferencesParent())
520 return false;
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))
527 return true;
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])
535 return false;
537 for (size_t i = 0; i < arraysize(kRestrictedChars); ++i) {
538 if (filename.value().find(kRestrictedChars[i]) !=
539 base::FilePath::StringType::npos)
540 return false;
543 return true;
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())
550 return true;
551 if (url.SchemeIsFileSystem())
552 return url.inner_url() && IsAllowedScheme(*url.inner_url());
554 for (size_t i = 0;
555 i < file_system_options_.additional_allowed_schemes().size();
556 ++i) {
557 if (url.SchemeIs(
558 file_system_options_.additional_allowed_schemes()[i].c_str()))
559 return true;
561 return false;
564 base::FilePath
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();
573 return path;
576 // static
577 base::FilePath
578 SandboxFileSystemBackendDelegate::GetUsageCachePathForOriginAndType(
579 ObfuscatedFileUtil* sandbox_file_util,
580 const GURL& origin_url,
581 FileSystemType type,
582 base::File::Error* error_out) {
583 DCHECK(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,
594 const GURL& origin,
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;
604 int64 usage = 0;
606 while (!(file_path_each = enumerator->Next()).empty()) {
607 usage += enumerator->Size();
608 usage += ObfuscatedFileUtil::ComputeFilePathCost(file_path_each);
611 return usage;
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_;
618 if (!throttled) {
619 next_release_time_for_open_filesystem_stat_ =
620 now + base::TimeDelta::FromHours(kMinimumStatsCollectionIntervalHours);
623 #define REPORT(report_value) \
624 UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemDetailLabel, \
625 (report_value), \
626 kFileSystemErrorMax); \
627 if (!throttled) { \
628 UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemDetailNonThrottledLabel, \
629 (report_value), \
630 kFileSystemErrorMax); \
633 switch (error_code) {
634 case base::File::FILE_OK:
635 REPORT(kOK);
636 break;
637 case base::File::FILE_ERROR_INVALID_URL:
638 REPORT(kInvalidSchemeError);
639 break;
640 case base::File::FILE_ERROR_NOT_FOUND:
641 REPORT(kNotFound);
642 break;
643 case base::File::FILE_ERROR_FAILED:
644 default:
645 REPORT(kUnknownError);
646 break;
648 #undef REPORT
651 void SandboxFileSystemBackendDelegate::CopyFileSystem(
652 const GURL& origin_url,
653 FileSystemType type,
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.
684 // static
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,
692 env_override,
693 file_task_runner,
694 base::Bind(&GetTypeStringForURL),
695 GetKnownTypeStrings(),
696 NULL);
699 } // namespace storage