Experimental push messaging api reference docs.
[chromium-blink-merge.git] / webkit / fileapi / sandbox_mount_point_provider.cc
blobb6a9918e3ac2096e9b973a93c9a716763da46891
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"
7 #include "base/bind.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;
36 namespace fileapi {
38 namespace {
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 {
56 kOK = 0,
57 kIncognito,
58 kInvalidSchemeError,
59 kCreateDirectoryError,
60 kNotFound,
61 kUnknownError,
62 kFileSystemErrorMax,
65 const char kTemporaryOriginsCountLabel[] = "FileSystem.TemporaryOriginsCount";
66 const char kPersistentOriginsCountLabel[] = "FileSystem.PersistentOriginsCount";
68 // Restricted names.
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(".."),
74 // Restricted chars.
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)];
86 return unique;
89 base::PlatformFileError OldReadOriginDirectory(const FilePath& base_path,
90 FilePath* unique) {
91 file_util::FileEnumerator file_enum(
92 base_path, false /* recursive */,
93 file_util::FileEnumerator::DIRECTORIES,
94 FilePath::StringType(kOldFileSystemUniqueNamePrefix) +
95 FILE_PATH_LITERAL("*"));
96 FilePath current;
97 bool found = false;
98 while (!(current = file_enum.Next()).empty()) {
99 if (current.BaseName().value().length() !=
100 kOldFileSystemUniqueDirectoryNameLength)
101 continue;
102 if (found) {
103 LOG(WARNING) << "Unexpectedly found more than one FileSystem "
104 << "directory";
105 return base::PLATFORM_FILE_ERROR_FAILED;
107 found = true;
108 *unique = current;
110 if (unique->empty())
111 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
112 return base::PLATFORM_FILE_OK;
115 class ObfuscatedOriginEnumerator
116 : public SandboxMountPointProvider::OriginEnumerator {
117 public:
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);
131 private:
132 scoped_ptr<ObfuscatedFileUtil::AbstractOriginEnumerator> enum_;
135 class OldSandboxOriginEnumerator
136 : public SandboxMountPointProvider::OriginEnumerator {
137 public:
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())
146 return GURL();
147 return GetOriginURLFromIdentifier(current_.BaseName().MaybeAsASCII());
150 virtual bool HasFileSystemType(fileapi::FileSystemType type) const OVERRIDE {
151 if (current_.empty())
152 return false;
153 std::string directory = GetFileSystemTypeString(type);
154 DCHECK(!directory.empty());
155 return file_util::DirectoryExists(current_.AppendASCII(directory));
158 private:
159 file_util::FileEnumerator enumerator_;
160 FilePath current_;
163 FilePath OldGetBaseDirectoryForOrigin(
164 const FilePath& old_base_path,
165 const GURL& origin_url) {
166 std::string id = GetOriginIdentifierFromURL(origin_url);
167 if (!id.empty())
168 return old_base_path.AppendASCII(id);
169 return FilePath();
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()) {
177 NOTREACHED();
178 return FilePath();
180 FilePath base_path = OldGetBaseDirectoryForOrigin(
181 old_base_path, origin_url);
182 if (base_path.empty()) {
183 NOTREACHED();
184 return FilePath();
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())
196 return false;
198 FilePath root;
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
206 // delete it.
207 if (base::PLATFORM_FILE_OK != result)
208 return false;
210 if (!file_util->MigrateFromOldSandbox(origin, type, root)) {
211 LOG(WARNING) << "Failed to migrate filesystem for origin " << origin <<
212 " and type " << type;
213 return false;
215 return true;
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));
223 GURL origin;
224 int failures = 0;
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;
246 if (!failures)
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
253 // necessary.
254 FilePath new_path =
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,
286 FileSystemType type,
287 const FilePath& old_base_path,
288 bool create,
289 base::PlatformFileError* error_ptr) {
290 DCHECK(error_ptr);
291 MigrateIfNeeded(file_util, old_base_path);
293 FilePath root_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);
300 } else {
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");
320 // static
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(
338 quota_manager_proxy,
339 file_task_runner,
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,
371 kIncognito,
372 kFileSystemErrorMax);
373 return;
376 if (!IsAllowedScheme(origin_url)) {
377 callback.Run(base::PLATFORM_FILE_ERROR_SECURITY);
378 UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemLabel,
379 kInvalidSchemeError,
380 kFileSystemErrorMax);
381 return;
384 base::PlatformFileError* error_ptr = new base::PlatformFileError;
385 file_task_runner_->PostTaskAndReply(
386 FROM_HERE,
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)));
396 FilePath
397 SandboxMountPointProvider::GetFileSystemRootPathOnFileThread(
398 const GURL& origin_url, FileSystemType type, const FilePath& unused,
399 bool create) {
400 if (file_system_options_.is_incognito())
401 // TODO(kinuko): return an isolated temporary directory.
402 return FilePath();
404 if (!IsAllowedScheme(origin_url))
405 return FilePath();
407 return GetBaseDirectoryForOriginAndType(origin_url, type, create);
410 bool SandboxMountPointProvider::IsAccessAllowed(const FileSystemURL& url) {
411 FileSystemType type = url.type();
412 if (!CanHandleType(type))
413 return false;
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)
420 const {
421 if (filename.value().empty())
422 return false;
424 for (size_t i = 0; i < arraysize(kRestrictedNames); ++i) {
425 // Exact match.
426 if (filename.value() == kRestrictedNames[i])
427 return true;
430 for (size_t i = 0; i < arraysize(kRestrictedChars); ++i) {
431 if (filename.value().find(kRestrictedChars[i]) !=
432 FilePath::StringType::npos)
433 return true;
436 return false;
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,
468 int64 offset,
469 FileSystemContext* context) const {
470 return new FileSystemFileStreamReader(context, url, offset);
473 fileapi::FileStreamWriter* SandboxMountPointProvider::CreateFileStreamWriter(
474 const FileSystemURL& url,
475 int64 offset,
476 FileSystemContext* context) const {
477 return new SandboxFileStreamWriter(
478 context, url, offset, update_observers_);
481 FileSystemQuotaUtil* SandboxMountPointProvider::GetQuotaUtil() {
482 return this;
485 void SandboxMountPointProvider::DeleteFileSystem(
486 const GURL& origin_url,
487 FileSystemType type,
488 FileSystemContext* context,
489 const DeleteFileSystemCallback& callback) {
490 base::PostTaskAndReplyWithResult(
491 context->task_runners()->file_task_runner(),
492 FROM_HERE,
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()),
498 origin_url,
499 type),
500 callback);
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)
530 return FilePath();
531 return path;
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,
543 origin_url, type);
545 bool result =
546 sandbox_file_util_->DeleteDirectoryForOriginAndType(origin_url, type);
547 if (result && proxy) {
548 proxy->NotifyStorageModified(
549 quota::QuotaClient::kFileSystem,
550 origin_url,
551 FileSystemTypeToQuotaStorageType(type),
552 -usage);
555 if (result)
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));
563 DCHECK(origins);
564 scoped_ptr<OriginEnumerator> enumerator(CreateOriginEnumerator());
565 GURL origin;
566 while (!(origin = enumerator->Next()).is_empty()) {
567 if (enumerator->HasFileSystemType(type))
568 origins->insert(origin);
570 switch (type) {
571 case kFileSystemTypeTemporary:
572 UMA_HISTOGRAM_COUNTS(kTemporaryOriginsCountLabel, origins->size());
573 break;
574 case kFileSystemTypePersistent:
575 UMA_HISTOGRAM_COUNTS(kPersistentOriginsCountLabel, origins->size());
576 break;
577 default:
578 break;
582 void SandboxMountPointProvider::GetOriginsForHostOnFileThread(
583 fileapi::FileSystemType type, const std::string& host,
584 std::set<GURL>* origins) {
585 DCHECK(CanHandleType(type));
586 DCHECK(origins);
587 scoped_ptr<OriginEnumerator> enumerator(CreateOriginEnumerator());
588 GURL origin;
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));
601 FilePath base_path =
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;
626 int64 usage = 0;
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);
636 return usage;
639 void SandboxMountPointProvider::InvalidateUsageCache(
640 const GURL& origin_url, fileapi::FileSystemType type) {
641 DCHECK(CanHandleType(type));
642 FilePath usage_file_path = GetUsageCachePathForOriginAndType(
643 origin_url, type);
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_;
651 if (!throttled) {
652 next_release_time_for_open_filesystem_stat_ =
653 now + base::TimeDelta::FromHours(kMinimumStatsCollectionIntervalHours);
656 #define REPORT(report_value) \
657 UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemDetailLabel, \
658 (report_value), \
659 kFileSystemErrorMax); \
660 if (!throttled) { \
661 UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemDetailNonThrottledLabel, \
662 (report_value), \
663 kFileSystemErrorMax); \
666 switch (error_code) {
667 case base::PLATFORM_FILE_OK:
668 REPORT(kOK);
669 break;
670 case base::PLATFORM_FILE_ERROR_INVALID_URL:
671 REPORT(kInvalidSchemeError);
672 break;
673 case base::PLATFORM_FILE_ERROR_NOT_FOUND:
674 REPORT(kNotFound);
675 break;
676 case base::PLATFORM_FILE_ERROR_FAILED:
677 default:
678 REPORT(kUnknownError);
679 break;
681 #undef REPORT
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 {
696 FilePath base_path =
697 GetBaseDirectoryForOriginAndType(origin_url, type, false);
698 if (base_path.empty())
699 return FilePath();
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());
709 FilePath root;
710 base::PlatformFileError result =
711 OldReadOriginDirectory(origin_base_path, &root);
712 if (base::PLATFORM_FILE_OK == result)
713 return root;
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)
718 return FilePath();
720 // Creates the root directory.
721 root = origin_base_path.Append(OldCreateUniqueDirectoryName(origin_url));
722 if (!file_util::CreateDirectory(root))
723 return FilePath();
725 return 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"))
732 return true;
733 if (url.SchemeIsFileSystem())
734 return url.inner_url() && IsAllowedScheme(*url.inner_url());
736 for (size_t i = 0;
737 i < file_system_options_.additional_allowed_schemes().size();
738 ++i) {
739 if (url.SchemeIs(
740 file_system_options_.additional_allowed_schemes()[i].c_str()))
741 return true;
743 return false;
746 } // namespace fileapi