1 // Copyright (c) 2012 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/fileapi/sandbox_mount_point_provider.h"
8 #include "base/command_line.h"
9 #include "base/logging.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/metrics/histogram.h"
12 #include "base/rand_util.h"
13 #include "base/single_thread_task_runner.h"
14 #include "base/string_util.h"
15 #include "base/stringprintf.h"
16 #include "base/task_runner_util.h"
17 #include "googleurl/src/gurl.h"
18 #include "net/base/net_util.h"
19 #include "webkit/fileapi/file_system_file_stream_reader.h"
20 #include "webkit/fileapi/file_system_operation_context.h"
21 #include "webkit/fileapi/file_system_options.h"
22 #include "webkit/fileapi/file_system_task_runners.h"
23 #include "webkit/fileapi/file_system_types.h"
24 #include "webkit/fileapi/file_system_usage_cache.h"
25 #include "webkit/fileapi/file_system_util.h"
26 #include "webkit/fileapi/local_file_system_operation.h"
27 #include "webkit/fileapi/native_file_util.h"
28 #include "webkit/fileapi/obfuscated_file_util.h"
29 #include "webkit/fileapi/sandbox_file_stream_writer.h"
30 #include "webkit/fileapi/sandbox_quota_observer.h"
31 #include "webkit/glue/webkit_glue.h"
32 #include "webkit/quota/quota_manager.h"
34 using quota::QuotaManagerProxy
;
40 const char kChromeScheme
[] = "chrome";
41 const char kExtensionScheme
[] = "chrome-extension";
43 const FilePath::CharType kOldFileSystemUniqueNamePrefix
[] =
44 FILE_PATH_LITERAL("chrome-");
45 const size_t kOldFileSystemUniqueLength
= 16;
46 const size_t kOldFileSystemUniqueDirectoryNameLength
=
47 kOldFileSystemUniqueLength
+ arraysize(kOldFileSystemUniqueNamePrefix
) - 1;
49 const char kOpenFileSystemLabel
[] = "FileSystem.OpenFileSystem";
50 const char kOpenFileSystemDetailLabel
[] = "FileSystem.OpenFileSystemDetail";
51 const char kOpenFileSystemDetailNonThrottledLabel
[] =
52 "FileSystem.OpenFileSystemDetailNonthrottled";
53 int64 kMinimumStatsCollectionIntervalHours
= 1;
55 enum FileSystemError
{
59 kCreateDirectoryError
,
65 const char kTemporaryOriginsCountLabel
[] = "FileSystem.TemporaryOriginsCount";
66 const char kPersistentOriginsCountLabel
[] = "FileSystem.PersistentOriginsCount";
69 // http://dev.w3.org/2009/dap/file-system/file-dir-sys.html#naming-restrictions
70 const FilePath::CharType
* const kRestrictedNames
[] = {
71 FILE_PATH_LITERAL("."), FILE_PATH_LITERAL(".."),
75 const FilePath::CharType kRestrictedChars
[] = {
76 FILE_PATH_LITERAL('/'), FILE_PATH_LITERAL('\\'),
79 FilePath::StringType
OldCreateUniqueDirectoryName(const GURL
& origin_url
) {
80 // This can be anything but need to be unpredictable.
81 static const FilePath::CharType letters
[] = FILE_PATH_LITERAL(
82 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
83 FilePath::StringType
unique(kOldFileSystemUniqueNamePrefix
);
84 for (size_t i
= 0; i
< kOldFileSystemUniqueLength
; ++i
)
85 unique
+= letters
[base::RandInt(0, arraysize(letters
) - 2)];
89 base::PlatformFileError
OldReadOriginDirectory(const FilePath
& base_path
,
91 file_util::FileEnumerator
file_enum(
92 base_path
, false /* recursive */,
93 file_util::FileEnumerator::DIRECTORIES
,
94 FilePath::StringType(kOldFileSystemUniqueNamePrefix
) +
95 FILE_PATH_LITERAL("*"));
98 while (!(current
= file_enum
.Next()).empty()) {
99 if (current
.BaseName().value().length() !=
100 kOldFileSystemUniqueDirectoryNameLength
)
103 LOG(WARNING
) << "Unexpectedly found more than one FileSystem "
105 return base::PLATFORM_FILE_ERROR_FAILED
;
111 return base::PLATFORM_FILE_ERROR_NOT_FOUND
;
112 return base::PLATFORM_FILE_OK
;
115 class ObfuscatedOriginEnumerator
116 : public SandboxMountPointProvider::OriginEnumerator
{
118 explicit ObfuscatedOriginEnumerator(ObfuscatedFileUtil
* file_util
) {
119 enum_
.reset(file_util
->CreateOriginEnumerator());
121 virtual ~ObfuscatedOriginEnumerator() {}
123 virtual GURL
Next() OVERRIDE
{
124 return enum_
->Next();
127 virtual bool HasFileSystemType(fileapi::FileSystemType type
) const OVERRIDE
{
128 return enum_
->HasFileSystemType(type
);
132 scoped_ptr
<ObfuscatedFileUtil::AbstractOriginEnumerator
> enum_
;
135 class OldSandboxOriginEnumerator
136 : public SandboxMountPointProvider::OriginEnumerator
{
138 explicit OldSandboxOriginEnumerator(const FilePath
& base_path
)
139 : enumerator_(base_path
, false /* recursive */,
140 file_util::FileEnumerator::DIRECTORIES
) {}
141 virtual ~OldSandboxOriginEnumerator() {}
143 virtual GURL
Next() OVERRIDE
{
144 current_
= enumerator_
.Next();
145 if (current_
.empty())
147 return GetOriginURLFromIdentifier(current_
.BaseName().MaybeAsASCII());
150 virtual bool HasFileSystemType(fileapi::FileSystemType type
) const OVERRIDE
{
151 if (current_
.empty())
153 std::string directory
= GetFileSystemTypeString(type
);
154 DCHECK(!directory
.empty());
155 return file_util::DirectoryExists(current_
.AppendASCII(directory
));
159 file_util::FileEnumerator enumerator_
;
163 FilePath
OldGetBaseDirectoryForOrigin(
164 const FilePath
& old_base_path
,
165 const GURL
& origin_url
) {
166 std::string id
= GetOriginIdentifierFromURL(origin_url
);
168 return old_base_path
.AppendASCII(id
);
172 FilePath
OldGetBaseDirectoryForOriginAndType(
173 const FilePath
& old_base_path
,
174 const GURL
& origin_url
, fileapi::FileSystemType type
) {
175 std::string type_string
= GetFileSystemTypeString(type
);
176 if (type_string
.empty()) {
180 FilePath base_path
= OldGetBaseDirectoryForOrigin(
181 old_base_path
, origin_url
);
182 if (base_path
.empty()) {
186 return base_path
.AppendASCII(type_string
);
189 bool MigrateOneOldFileSystem(
190 ObfuscatedFileUtil
* file_util
,
191 const FilePath
& old_base_path
, const GURL
& origin
,
192 fileapi::FileSystemType type
) {
193 FilePath base_path
= OldGetBaseDirectoryForOriginAndType(
194 old_base_path
, origin
, type
);
195 if (base_path
.empty())
199 base::PlatformFileError result
= OldReadOriginDirectory(base_path
, &root
);
200 if (base::PLATFORM_FILE_ERROR_NOT_FOUND
== result
)
201 return true; // There was nothing to migrate; call that a success.
203 // If we found more than one filesystem [a problem we don't know how to
204 // solve], the data is already not accessible through Chrome, so it won't do
205 // any harm not to migrate it. Just flag it as an error, so that we don't
207 if (base::PLATFORM_FILE_OK
!= result
)
210 if (!file_util
->MigrateFromOldSandbox(origin
, type
, root
)) {
211 LOG(WARNING
) << "Failed to migrate filesystem for origin " << origin
<<
212 " and type " << type
;
218 void MigrateAllOldFileSystems(
219 ObfuscatedFileUtil
* file_util
,
220 const FilePath
& old_base_path
) {
221 scoped_ptr
<OldSandboxOriginEnumerator
> old_origins(
222 new OldSandboxOriginEnumerator(old_base_path
));
225 while (!(origin
= old_origins
->Next()).is_empty()) {
226 int failures_this_origin
= 0;
227 if (old_origins
->HasFileSystemType(kFileSystemTypeTemporary
) &&
228 !MigrateOneOldFileSystem(
229 file_util
, old_base_path
, origin
,
230 kFileSystemTypeTemporary
))
231 ++failures_this_origin
;
232 if (old_origins
->HasFileSystemType(kFileSystemTypePersistent
) &&
233 !MigrateOneOldFileSystem(
234 file_util
, old_base_path
, origin
,
235 kFileSystemTypePersistent
))
236 ++failures_this_origin
;
237 if (!failures_this_origin
) {
238 FilePath origin_base_path
=
239 OldGetBaseDirectoryForOrigin(old_base_path
, origin
);
240 // Yes, that's an rm -rf. Make sure that path looks valid, just in case.
241 if (!origin_base_path
.empty())
242 file_util::Delete(origin_base_path
, true);
244 failures
+= failures_this_origin
;
247 file_util::Delete(old_base_path
, true);
248 if (file_util::DirectoryExists(old_base_path
)) {
249 // Move it out of the way so that we won't keep trying to migrate it. You
250 // get only one chance at this; the bits we couldn't do this time, we're
251 // unlikely to be able to do in the future. This way you can now use the
252 // new filesystem, but have a way to recover your old files if absolutely
255 old_base_path
.DirName().Append(
256 SandboxMountPointProvider::kRenamedOldFileSystemDirectory
);
257 file_util::ReplaceFile(old_base_path
, new_path
);
261 // A migration, whether successful or not, will try to move this directory out
262 // of the way so that we never try to migrate it again. We need to do this
263 // check on all public entry points in this file, so that it's guaranteed to be
264 // done before anyone looks up a filesystem. Most entry points start by trying
265 // to look up the filesystem's root, so we can take care of most of them by
266 // putting a check there.
267 void MigrateIfNeeded(
268 ObfuscatedFileUtil
* file_util
,
269 const FilePath
& old_base_path
) {
270 if (file_util::DirectoryExists(old_base_path
))
271 MigrateAllOldFileSystems(file_util
, old_base_path
);
274 void DidValidateFileSystemRoot(
275 base::WeakPtr
<SandboxMountPointProvider
> mount_point_provider
,
276 const FileSystemMountPointProvider::ValidateFileSystemCallback
& callback
,
277 base::PlatformFileError
* error
) {
278 if (mount_point_provider
.get())
279 mount_point_provider
.get()->CollectOpenFileSystemMetrics(*error
);
280 callback
.Run(*error
);
283 void ValidateRootOnFileThread(
284 ObfuscatedFileUtil
* file_util
,
285 const GURL
& origin_url
,
287 const FilePath
& old_base_path
,
289 base::PlatformFileError
* error_ptr
) {
291 MigrateIfNeeded(file_util
, old_base_path
);
294 file_util
->GetDirectoryForOriginAndType(
295 origin_url
, type
, create
, error_ptr
);
296 if (*error_ptr
!= base::PLATFORM_FILE_OK
) {
297 UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemLabel
,
298 kCreateDirectoryError
,
299 kFileSystemErrorMax
);
301 UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemLabel
, kOK
, kFileSystemErrorMax
);
303 // The reference of file_util will be derefed on the FILE thread
304 // when the storage of this callback gets deleted regardless of whether
305 // this method is called or not.
308 } // anonymous namespace
310 const FilePath::CharType
SandboxMountPointProvider::kOldFileSystemDirectory
[] =
311 FILE_PATH_LITERAL("FileSystem");
313 const FilePath::CharType
SandboxMountPointProvider::kNewFileSystemDirectory
[] =
314 FILE_PATH_LITERAL("File System");
316 const FilePath::CharType
317 SandboxMountPointProvider::kRenamedOldFileSystemDirectory
[] =
318 FILE_PATH_LITERAL("FS.old");
321 bool SandboxMountPointProvider::CanHandleType(FileSystemType type
) {
322 return type
== kFileSystemTypeTemporary
||
323 type
== kFileSystemTypePersistent
||
324 type
== kFileSystemTypeSyncable
;
327 SandboxMountPointProvider::SandboxMountPointProvider(
328 quota::QuotaManagerProxy
* quota_manager_proxy
,
329 base::SequencedTaskRunner
* file_task_runner
,
330 const FilePath
& profile_path
,
331 const FileSystemOptions
& file_system_options
)
332 : file_task_runner_(file_task_runner
),
333 profile_path_(profile_path
),
334 file_system_options_(file_system_options
),
335 sandbox_file_util_(new ObfuscatedFileUtil(
336 profile_path
.Append(kNewFileSystemDirectory
))),
337 quota_observer_(new SandboxQuotaObserver(
340 ALLOW_THIS_IN_INITIALIZER_LIST(this))),
341 weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
343 // Set quota observers.
344 UpdateObserverList::Source update_observers_src
;
345 AccessObserverList::Source access_observers_src
;
347 update_observers_src
.AddObserver(quota_observer_
.get(), file_task_runner_
);
348 access_observers_src
.AddObserver(quota_observer_
.get(), NULL
);
349 update_observers_src
.AddObserver(quota_observer_
.get(), file_task_runner_
);
350 access_observers_src
.AddObserver(quota_observer_
.get(), NULL
);
352 update_observers_
= UpdateObserverList(update_observers_src
);
353 access_observers_
= AccessObserverList(access_observers_src
);
356 SandboxMountPointProvider::~SandboxMountPointProvider() {
357 if (!file_task_runner_
->RunsTasksOnCurrentThread()) {
358 ObfuscatedFileUtil
* sandbox_file_util
= sandbox_file_util_
.release();
359 if (!file_task_runner_
->DeleteSoon(FROM_HERE
, sandbox_file_util
))
360 delete sandbox_file_util
;
364 void SandboxMountPointProvider::ValidateFileSystemRoot(
365 const GURL
& origin_url
, fileapi::FileSystemType type
, bool create
,
366 const ValidateFileSystemCallback
& callback
) {
367 if (file_system_options_
.is_incognito()) {
368 // TODO(kinuko): return an isolated temporary directory.
369 callback
.Run(base::PLATFORM_FILE_ERROR_SECURITY
);
370 UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemLabel
,
372 kFileSystemErrorMax
);
376 if (!IsAllowedScheme(origin_url
)) {
377 callback
.Run(base::PLATFORM_FILE_ERROR_SECURITY
);
378 UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemLabel
,
380 kFileSystemErrorMax
);
384 base::PlatformFileError
* error_ptr
= new base::PlatformFileError
;
385 file_task_runner_
->PostTaskAndReply(
387 base::Bind(&ValidateRootOnFileThread
,
388 sandbox_file_util_
.get(),
389 origin_url
, type
, old_base_path(), create
,
390 base::Unretained(error_ptr
)),
391 base::Bind(&DidValidateFileSystemRoot
,
392 weak_factory_
.GetWeakPtr(),
393 callback
, base::Owned(error_ptr
)));
397 SandboxMountPointProvider::GetFileSystemRootPathOnFileThread(
398 const GURL
& origin_url
, FileSystemType type
, const FilePath
& unused
,
400 if (file_system_options_
.is_incognito())
401 // TODO(kinuko): return an isolated temporary directory.
404 if (!IsAllowedScheme(origin_url
))
407 return GetBaseDirectoryForOriginAndType(origin_url
, type
, create
);
410 bool SandboxMountPointProvider::IsAccessAllowed(const FileSystemURL
& url
) {
411 FileSystemType type
= url
.type();
412 if (!CanHandleType(type
))
414 // We essentially depend on quota to do our access controls, so here
415 // we only check if the requested scheme is allowed or not.
416 return IsAllowedScheme(url
.origin());
419 bool SandboxMountPointProvider::IsRestrictedFileName(const FilePath
& filename
)
421 if (filename
.value().empty())
424 for (size_t i
= 0; i
< arraysize(kRestrictedNames
); ++i
) {
426 if (filename
.value() == kRestrictedNames
[i
])
430 for (size_t i
= 0; i
< arraysize(kRestrictedChars
); ++i
) {
431 if (filename
.value().find(kRestrictedChars
[i
]) !=
432 FilePath::StringType::npos
)
439 FileSystemFileUtil
* SandboxMountPointProvider::GetFileUtil(
440 FileSystemType type
) {
441 return sandbox_file_util_
.get();
444 FilePath
SandboxMountPointProvider::GetPathForPermissionsCheck(
445 const FilePath
& virtual_path
) const {
446 // We simply return the very top directory of the sandbox
447 // filesystem regardless of the input path.
448 return new_base_path();
451 FileSystemOperation
* SandboxMountPointProvider::CreateFileSystemOperation(
452 const FileSystemURL
& url
,
453 FileSystemContext
* context
,
454 base::PlatformFileError
* error_code
) const {
455 scoped_ptr
<FileSystemOperationContext
> operation_context(
456 new FileSystemOperationContext(context
));
458 // Copy the observer lists (assuming we only have small number of observers).
459 operation_context
->set_update_observers(update_observers_
);
460 operation_context
->set_access_observers(access_observers_
);
462 return new LocalFileSystemOperation(context
, operation_context
.Pass());
465 webkit_blob::FileStreamReader
*
466 SandboxMountPointProvider::CreateFileStreamReader(
467 const FileSystemURL
& url
,
469 FileSystemContext
* context
) const {
470 return new FileSystemFileStreamReader(context
, url
, offset
);
473 fileapi::FileStreamWriter
* SandboxMountPointProvider::CreateFileStreamWriter(
474 const FileSystemURL
& url
,
476 FileSystemContext
* context
) const {
477 return new SandboxFileStreamWriter(
478 context
, url
, offset
, update_observers_
);
481 FileSystemQuotaUtil
* SandboxMountPointProvider::GetQuotaUtil() {
485 void SandboxMountPointProvider::DeleteFileSystem(
486 const GURL
& origin_url
,
488 FileSystemContext
* context
,
489 const DeleteFileSystemCallback
& callback
) {
490 base::PostTaskAndReplyWithResult(
491 context
->task_runners()->file_task_runner(),
493 // It is safe to pass Unretained(this) since context owns it.
494 base::Bind(&SandboxMountPointProvider::DeleteOriginDataOnFileThread
,
495 base::Unretained(this),
496 make_scoped_refptr(context
),
497 base::Unretained(context
->quota_manager_proxy()),
503 FilePath
SandboxMountPointProvider::old_base_path() const {
504 return profile_path_
.Append(kOldFileSystemDirectory
);
507 FilePath
SandboxMountPointProvider::new_base_path() const {
508 return profile_path_
.Append(kNewFileSystemDirectory
);
511 FilePath
SandboxMountPointProvider::renamed_old_base_path() const {
512 return profile_path_
.Append(kRenamedOldFileSystemDirectory
);
515 SandboxMountPointProvider::OriginEnumerator
*
516 SandboxMountPointProvider::CreateOriginEnumerator() const {
517 MigrateIfNeeded(sandbox_file_util_
.get(), old_base_path());
518 return new ObfuscatedOriginEnumerator(sandbox_file_util_
.get());
521 FilePath
SandboxMountPointProvider::GetBaseDirectoryForOriginAndType(
522 const GURL
& origin_url
, fileapi::FileSystemType type
, bool create
) const {
524 MigrateIfNeeded(sandbox_file_util_
.get(), old_base_path());
526 base::PlatformFileError error
= base::PLATFORM_FILE_OK
;
527 FilePath path
= sandbox_file_util_
->GetDirectoryForOriginAndType(
528 origin_url
, type
, create
, &error
);
529 if (error
!= base::PLATFORM_FILE_OK
)
534 base::PlatformFileError
535 SandboxMountPointProvider::DeleteOriginDataOnFileThread(
536 FileSystemContext
* file_system_context
,
537 QuotaManagerProxy
* proxy
,
538 const GURL
& origin_url
,
539 fileapi::FileSystemType type
) {
540 MigrateIfNeeded(sandbox_file_util_
.get(), old_base_path());
542 int64 usage
= GetOriginUsageOnFileThread(file_system_context
,
546 sandbox_file_util_
->DeleteDirectoryForOriginAndType(origin_url
, type
);
547 if (result
&& proxy
) {
548 proxy
->NotifyStorageModified(
549 quota::QuotaClient::kFileSystem
,
551 FileSystemTypeToQuotaStorageType(type
),
556 return base::PLATFORM_FILE_OK
;
557 return base::PLATFORM_FILE_ERROR_FAILED
;
560 void SandboxMountPointProvider::GetOriginsForTypeOnFileThread(
561 fileapi::FileSystemType type
, std::set
<GURL
>* origins
) {
562 DCHECK(CanHandleType(type
));
564 scoped_ptr
<OriginEnumerator
> enumerator(CreateOriginEnumerator());
566 while (!(origin
= enumerator
->Next()).is_empty()) {
567 if (enumerator
->HasFileSystemType(type
))
568 origins
->insert(origin
);
571 case kFileSystemTypeTemporary
:
572 UMA_HISTOGRAM_COUNTS(kTemporaryOriginsCountLabel
, origins
->size());
574 case kFileSystemTypePersistent
:
575 UMA_HISTOGRAM_COUNTS(kPersistentOriginsCountLabel
, origins
->size());
582 void SandboxMountPointProvider::GetOriginsForHostOnFileThread(
583 fileapi::FileSystemType type
, const std::string
& host
,
584 std::set
<GURL
>* origins
) {
585 DCHECK(CanHandleType(type
));
587 scoped_ptr
<OriginEnumerator
> enumerator(CreateOriginEnumerator());
589 while (!(origin
= enumerator
->Next()).is_empty()) {
590 if (host
== net::GetHostOrSpecFromURL(origin
) &&
591 enumerator
->HasFileSystemType(type
))
592 origins
->insert(origin
);
596 int64
SandboxMountPointProvider::GetOriginUsageOnFileThread(
597 FileSystemContext
* file_system_context
,
598 const GURL
& origin_url
,
599 fileapi::FileSystemType type
) {
600 DCHECK(CanHandleType(type
));
602 GetBaseDirectoryForOriginAndType(origin_url
, type
, false);
603 if (base_path
.empty() || !file_util::DirectoryExists(base_path
)) return 0;
604 FilePath usage_file_path
=
605 base_path
.Append(FileSystemUsageCache::kUsageFileName
);
607 bool is_valid
= FileSystemUsageCache::IsValid(usage_file_path
);
608 int32 dirty_status
= FileSystemUsageCache::GetDirty(usage_file_path
);
609 bool visited
= (visited_origins_
.find(origin_url
) != visited_origins_
.end());
610 visited_origins_
.insert(origin_url
);
611 if (is_valid
&& (dirty_status
== 0 || (dirty_status
> 0 && visited
))) {
612 // The usage cache is clean (dirty == 0) or the origin is already
613 // initialized and running. Read the cache file to get the usage.
614 return FileSystemUsageCache::GetUsage(usage_file_path
);
616 // The usage cache has not been initialized or the cache is dirty.
617 // Get the directory size now and update the cache.
618 FileSystemUsageCache::Delete(usage_file_path
);
620 FileSystemOperationContext
context(file_system_context
);
621 FileSystemURL
url(origin_url
, type
, FilePath());
622 scoped_ptr
<FileSystemFileUtil::AbstractFileEnumerator
> enumerator(
623 sandbox_file_util_
->CreateFileEnumerator(&context
, url
, true));
625 FilePath file_path_each
;
628 while (!(file_path_each
= enumerator
->Next()).empty()) {
629 base::PlatformFileInfo file_info
;
630 FilePath platform_file_path
;
631 usage
+= enumerator
->Size();
632 usage
+= ObfuscatedFileUtil::ComputeFilePathCost(file_path_each
);
634 // This clears the dirty flag too.
635 FileSystemUsageCache::UpdateUsage(usage_file_path
, usage
);
639 void SandboxMountPointProvider::InvalidateUsageCache(
640 const GURL
& origin_url
, fileapi::FileSystemType type
) {
641 DCHECK(CanHandleType(type
));
642 FilePath usage_file_path
= GetUsageCachePathForOriginAndType(
644 FileSystemUsageCache::IncrementDirty(usage_file_path
);
647 void SandboxMountPointProvider::CollectOpenFileSystemMetrics(
648 base::PlatformFileError error_code
) {
649 base::Time now
= base::Time::Now();
650 bool throttled
= now
< next_release_time_for_open_filesystem_stat_
;
652 next_release_time_for_open_filesystem_stat_
=
653 now
+ base::TimeDelta::FromHours(kMinimumStatsCollectionIntervalHours
);
656 #define REPORT(report_value) \
657 UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemDetailLabel, \
659 kFileSystemErrorMax); \
661 UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemDetailNonThrottledLabel, \
663 kFileSystemErrorMax); \
666 switch (error_code
) {
667 case base::PLATFORM_FILE_OK
:
670 case base::PLATFORM_FILE_ERROR_INVALID_URL
:
671 REPORT(kInvalidSchemeError
);
673 case base::PLATFORM_FILE_ERROR_NOT_FOUND
:
676 case base::PLATFORM_FILE_ERROR_FAILED
:
678 REPORT(kUnknownError
);
684 const UpdateObserverList
* SandboxMountPointProvider::GetUpdateObservers(
685 FileSystemType type
) const {
686 return &update_observers_
;
689 void SandboxMountPointProvider::ResetObservers() {
690 update_observers_
= UpdateObserverList();
691 access_observers_
= AccessObserverList();
694 FilePath
SandboxMountPointProvider::GetUsageCachePathForOriginAndType(
695 const GURL
& origin_url
, fileapi::FileSystemType type
) const {
697 GetBaseDirectoryForOriginAndType(origin_url
, type
, false);
698 if (base_path
.empty())
700 return base_path
.Append(FileSystemUsageCache::kUsageFileName
);
703 FilePath
SandboxMountPointProvider::OldCreateFileSystemRootPath(
704 const GURL
& origin_url
, fileapi::FileSystemType type
) {
705 FilePath origin_base_path
=
706 OldGetBaseDirectoryForOriginAndType(old_base_path(), origin_url
, type
);
707 DCHECK(!origin_base_path
.empty());
710 base::PlatformFileError result
=
711 OldReadOriginDirectory(origin_base_path
, &root
);
712 if (base::PLATFORM_FILE_OK
== result
)
715 // We found more than on filesystem there already--we don't know how to
716 // recover from this.
717 if (base::PLATFORM_FILE_ERROR_NOT_FOUND
!= result
)
720 // Creates the root directory.
721 root
= origin_base_path
.Append(OldCreateUniqueDirectoryName(origin_url
));
722 if (!file_util::CreateDirectory(root
))
728 bool SandboxMountPointProvider::IsAllowedScheme(const GURL
& url
) const {
729 // Basically we only accept http or https. We allow file:// URLs
730 // only if --allow-file-access-from-files flag is given.
731 if (url
.SchemeIs("http") || url
.SchemeIs("https"))
733 if (url
.SchemeIsFileSystem())
734 return url
.inner_url() && IsAllowedScheme(*url
.inner_url());
737 i
< file_system_options_
.additional_allowed_schemes().size();
740 file_system_options_
.additional_allowed_schemes()[i
].c_str()))
746 } // namespace fileapi