Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / webkit / browser / fileapi / sandbox_file_system_backend_delegate.cc
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.
4
5 #include "webkit/browser/fileapi/sandbox_file_system_backend_delegate.h"
6
7 #include <vector>
8
9 #include "base/command_line.h"
10 #include "base/file_util.h"
11 #include "base/metrics/histogram.h"
12 #include "base/stl_util.h"
13 #include "base/task_runner_util.h"
14 #include "net/base/net_util.h"
15 #include "webkit/browser/blob/file_stream_reader.h"
16 #include "webkit/browser/fileapi/async_file_util_adapter.h"
17 #include "webkit/browser/fileapi/file_system_context.h"
18 #include "webkit/browser/fileapi/file_system_operation_context.h"
19 #include "webkit/browser/fileapi/file_system_url.h"
20 #include "webkit/browser/fileapi/file_system_usage_cache.h"
21 #include "webkit/browser/fileapi/obfuscated_file_util.h"
22 #include "webkit/browser/fileapi/quota/quota_backend_impl.h"
23 #include "webkit/browser/fileapi/quota/quota_reservation.h"
24 #include "webkit/browser/fileapi/quota/quota_reservation_manager.h"
25 #include "webkit/browser/fileapi/sandbox_file_stream_writer.h"
26 #include "webkit/browser/fileapi/sandbox_file_system_backend.h"
27 #include "webkit/browser/fileapi/sandbox_quota_observer.h"
28 #include "webkit/browser/quota/quota_manager_proxy.h"
29 #include "webkit/common/fileapi/file_system_util.h"
30
31 namespace fileapi {
32
33 namespace {
34
35 const char kTemporaryOriginsCountLabel[] = "FileSystem.TemporaryOriginsCount";
36 const char kPersistentOriginsCountLabel[] = "FileSystem.PersistentOriginsCount";
37
38 const char kOpenFileSystemLabel[] = "FileSystem.OpenFileSystem";
39 const char kOpenFileSystemDetailLabel[] = "FileSystem.OpenFileSystemDetail";
40 const char kOpenFileSystemDetailNonThrottledLabel[] =
41     "FileSystem.OpenFileSystemDetailNonthrottled";
42 int64 kMinimumStatsCollectionIntervalHours = 1;
43
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";
50
51 const char* kPrepopulateTypes[] = {
52   kPersistentDirectoryName,
53   kTemporaryDirectoryName
54 };
55
56 enum FileSystemError {
57   kOK = 0,
58   kIncognito,
59   kInvalidSchemeError,
60   kCreateDirectoryError,
61   kNotFound,
62   kUnknownError,
63   kFileSystemErrorMax,
64 };
65
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(".."),
70 };
71
72 // Restricted chars.
73 const base::FilePath::CharType kRestrictedChars[] = {
74   FILE_PATH_LITERAL('/'), FILE_PATH_LITERAL('\\'),
75 };
76
77 std::string GetTypeStringForURL(const FileSystemURL& url) {
78   return SandboxFileSystemBackendDelegate::GetTypeString(url.type());
79 }
80
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;
87 }
88
89 class ObfuscatedOriginEnumerator
90     : public SandboxFileSystemBackendDelegate::OriginEnumerator {
91  public:
92   explicit ObfuscatedOriginEnumerator(ObfuscatedFileUtil* file_util) {
93     enum_.reset(file_util->CreateOriginEnumerator());
94   }
95   virtual ~ObfuscatedOriginEnumerator() {}
96
97   virtual GURL Next() OVERRIDE {
98     return enum_->Next();
99   }
100
101   virtual bool HasFileSystemType(FileSystemType type) const OVERRIDE {
102     return enum_->HasTypeDirectory(
103         SandboxFileSystemBackendDelegate::GetTypeString(type));
104   }
105
106  private:
107   scoped_ptr<ObfuscatedFileUtil::AbstractOriginEnumerator> enum_;
108 };
109
110 void OpenFileSystemOnFileTaskRunner(
111     ObfuscatedFileUtil* file_util,
112     const GURL& origin_url,
113     FileSystemType type,
114     OpenFileSystemMode mode,
115     base::File::Error* error_ptr) {
116   DCHECK(error_ptr);
117   const bool create = (mode == OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT);
118   file_util->GetDirectoryForOriginAndType(
119       origin_url, SandboxFileSystemBackendDelegate::GetTypeString(type),
120       create, error_ptr);
121   if (*error_ptr != base::File::FILE_OK) {
122     UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemLabel,
123                               kCreateDirectoryError,
124                               kFileSystemErrorMax);
125   } else {
126     UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemLabel, kOK, kFileSystemErrorMax);
127   }
128   // The reference of file_util will be derefed on the FILE thread
129   // when the storage of this callback gets deleted regardless of whether
130   // this method is called or not.
131 }
132
133 void DidOpenFileSystem(
134     base::WeakPtr<SandboxFileSystemBackendDelegate> delegate,
135     const base::Callback<void(base::File::Error error)>& callback,
136     base::File::Error* error) {
137   if (delegate.get())
138     delegate.get()->CollectOpenFileSystemMetrics(*error);
139   callback.Run(*error);
140 }
141
142 template <typename T>
143 void DeleteSoon(base::SequencedTaskRunner* runner, T* ptr) {
144   if (!runner->DeleteSoon(FROM_HERE, ptr))
145     delete ptr;
146 }
147
148 }  // namespace
149
150 const base::FilePath::CharType
151 SandboxFileSystemBackendDelegate::kFileSystemDirectory[] =
152     FILE_PATH_LITERAL("File System");
153
154 // static
155 std::string SandboxFileSystemBackendDelegate::GetTypeString(
156     FileSystemType type) {
157   switch (type) {
158     case kFileSystemTypeTemporary:
159       return kTemporaryDirectoryName;
160     case kFileSystemTypePersistent:
161       return kPersistentDirectoryName;
162     case kFileSystemTypeSyncable:
163     case kFileSystemTypeSyncableForInternalSync:
164       return kSyncableDirectoryName;
165     case kFileSystemTypeUnknown:
166     default:
167       NOTREACHED() << "Unknown filesystem type requested:" << type;
168       return std::string();
169   }
170 }
171
172 SandboxFileSystemBackendDelegate::SandboxFileSystemBackendDelegate(
173     quota::QuotaManagerProxy* quota_manager_proxy,
174     base::SequencedTaskRunner* file_task_runner,
175     const base::FilePath& profile_path,
176     quota::SpecialStoragePolicy* special_storage_policy,
177     const FileSystemOptions& file_system_options)
178     : file_task_runner_(file_task_runner),
179       sandbox_file_util_(new AsyncFileUtilAdapter(
180           new ObfuscatedFileUtil(
181               special_storage_policy,
182               profile_path.Append(kFileSystemDirectory),
183               file_system_options.env_override(),
184               file_task_runner,
185               base::Bind(&GetTypeStringForURL),
186               GetKnownTypeStrings(),
187               this))),
188       file_system_usage_cache_(new FileSystemUsageCache(file_task_runner)),
189       quota_observer_(new SandboxQuotaObserver(
190           quota_manager_proxy,
191           file_task_runner,
192           obfuscated_file_util(),
193           usage_cache())),
194       quota_reservation_manager_(new QuotaReservationManager(
195           scoped_ptr<QuotaReservationManager::QuotaBackend>(
196               new QuotaBackendImpl(file_task_runner_,
197                                    obfuscated_file_util(),
198                                    usage_cache(),
199                                    quota_manager_proxy)))),
200       special_storage_policy_(special_storage_policy),
201       file_system_options_(file_system_options),
202       is_filesystem_opened_(false),
203       weak_factory_(this) {
204   // Prepopulate database only if it can run asynchronously (i.e. the current
205   // thread is not file_task_runner). Usually this is the case but may not
206   // in test code.
207   if (!file_task_runner_->RunsTasksOnCurrentThread()) {
208     std::vector<std::string> types_to_prepopulate(
209         &kPrepopulateTypes[0],
210         &kPrepopulateTypes[arraysize(kPrepopulateTypes)]);
211     file_task_runner_->PostTask(
212         FROM_HERE,
213         base::Bind(&ObfuscatedFileUtil::MaybePrepopulateDatabase,
214                   base::Unretained(obfuscated_file_util()),
215                   types_to_prepopulate));
216   }
217 }
218
219 SandboxFileSystemBackendDelegate::~SandboxFileSystemBackendDelegate() {
220   io_thread_checker_.DetachFromThread();
221
222   if (!file_task_runner_->RunsTasksOnCurrentThread()) {
223     DeleteSoon(file_task_runner_.get(), quota_reservation_manager_.release());
224     DeleteSoon(file_task_runner_.get(), sandbox_file_util_.release());
225     DeleteSoon(file_task_runner_.get(), quota_observer_.release());
226     DeleteSoon(file_task_runner_.get(), file_system_usage_cache_.release());
227   }
228 }
229
230 SandboxFileSystemBackendDelegate::OriginEnumerator*
231 SandboxFileSystemBackendDelegate::CreateOriginEnumerator() {
232   return new ObfuscatedOriginEnumerator(obfuscated_file_util());
233 }
234
235 base::FilePath
236 SandboxFileSystemBackendDelegate::GetBaseDirectoryForOriginAndType(
237     const GURL& origin_url,
238     FileSystemType type,
239     bool create) {
240   base::File::Error error = base::File::FILE_OK;
241   base::FilePath path = obfuscated_file_util()->GetDirectoryForOriginAndType(
242       origin_url, GetTypeString(type), create, &error);
243   if (error != base::File::FILE_OK)
244     return base::FilePath();
245   return path;
246 }
247
248 void SandboxFileSystemBackendDelegate::OpenFileSystem(
249     const GURL& origin_url,
250     FileSystemType type,
251     OpenFileSystemMode mode,
252     const OpenFileSystemCallback& callback,
253     const GURL& root_url) {
254   if (!IsAllowedScheme(origin_url)) {
255     callback.Run(GURL(), std::string(), base::File::FILE_ERROR_SECURITY);
256     return;
257   }
258
259   std::string name = GetFileSystemName(origin_url, type);
260
261   base::File::Error* error_ptr = new base::File::Error;
262   file_task_runner_->PostTaskAndReply(
263       FROM_HERE,
264       base::Bind(&OpenFileSystemOnFileTaskRunner,
265                  obfuscated_file_util(), origin_url, type, mode,
266                  base::Unretained(error_ptr)),
267       base::Bind(&DidOpenFileSystem,
268                  weak_factory_.GetWeakPtr(),
269                  base::Bind(callback, root_url, name),
270                  base::Owned(error_ptr)));
271
272   io_thread_checker_.DetachFromThread();
273   is_filesystem_opened_ = true;
274 }
275
276 scoped_ptr<FileSystemOperationContext>
277 SandboxFileSystemBackendDelegate::CreateFileSystemOperationContext(
278     const FileSystemURL& url,
279     FileSystemContext* context,
280     base::File::Error* error_code) const {
281   if (!IsAccessValid(url)) {
282     *error_code = base::File::FILE_ERROR_SECURITY;
283     return scoped_ptr<FileSystemOperationContext>();
284   }
285
286   const UpdateObserverList* update_observers = GetUpdateObservers(url.type());
287   const ChangeObserverList* change_observers = GetChangeObservers(url.type());
288   DCHECK(update_observers);
289
290   scoped_ptr<FileSystemOperationContext> operation_context(
291       new FileSystemOperationContext(context));
292   operation_context->set_update_observers(*update_observers);
293   operation_context->set_change_observers(
294       change_observers ? *change_observers : ChangeObserverList());
295
296   return operation_context.Pass();
297 }
298
299 scoped_ptr<webkit_blob::FileStreamReader>
300 SandboxFileSystemBackendDelegate::CreateFileStreamReader(
301     const FileSystemURL& url,
302     int64 offset,
303     const base::Time& expected_modification_time,
304     FileSystemContext* context) const {
305   if (!IsAccessValid(url))
306     return scoped_ptr<webkit_blob::FileStreamReader>();
307   return scoped_ptr<webkit_blob::FileStreamReader>(
308       webkit_blob::FileStreamReader::CreateForFileSystemFile(
309           context, url, offset, expected_modification_time));
310 }
311
312 scoped_ptr<FileStreamWriter>
313 SandboxFileSystemBackendDelegate::CreateFileStreamWriter(
314     const FileSystemURL& url,
315     int64 offset,
316     FileSystemContext* context,
317     FileSystemType type) const {
318   if (!IsAccessValid(url))
319     return scoped_ptr<FileStreamWriter>();
320   const UpdateObserverList* observers = GetUpdateObservers(type);
321   DCHECK(observers);
322   return scoped_ptr<FileStreamWriter>(
323       new SandboxFileStreamWriter(context, url, offset, *observers));
324 }
325
326 base::File::Error
327 SandboxFileSystemBackendDelegate::DeleteOriginDataOnFileTaskRunner(
328     FileSystemContext* file_system_context,
329     quota::QuotaManagerProxy* proxy,
330     const GURL& origin_url,
331     FileSystemType type) {
332   DCHECK(file_task_runner_->RunsTasksOnCurrentThread());
333   int64 usage = GetOriginUsageOnFileTaskRunner(
334       file_system_context, origin_url, type);
335   usage_cache()->CloseCacheFiles();
336   bool result = obfuscated_file_util()->DeleteDirectoryForOriginAndType(
337       origin_url, GetTypeString(type));
338   if (result && proxy) {
339     proxy->NotifyStorageModified(
340         quota::QuotaClient::kFileSystem,
341         origin_url,
342         FileSystemTypeToQuotaStorageType(type),
343         -usage);
344   }
345
346   if (result)
347     return base::File::FILE_OK;
348   return base::File::FILE_ERROR_FAILED;
349 }
350
351 void SandboxFileSystemBackendDelegate::GetOriginsForTypeOnFileTaskRunner(
352     FileSystemType type, std::set<GURL>* origins) {
353   DCHECK(file_task_runner_->RunsTasksOnCurrentThread());
354   DCHECK(origins);
355   scoped_ptr<OriginEnumerator> enumerator(CreateOriginEnumerator());
356   GURL origin;
357   while (!(origin = enumerator->Next()).is_empty()) {
358     if (enumerator->HasFileSystemType(type))
359       origins->insert(origin);
360   }
361   switch (type) {
362     case kFileSystemTypeTemporary:
363       UMA_HISTOGRAM_COUNTS(kTemporaryOriginsCountLabel, origins->size());
364       break;
365     case kFileSystemTypePersistent:
366       UMA_HISTOGRAM_COUNTS(kPersistentOriginsCountLabel, origins->size());
367       break;
368     default:
369       break;
370   }
371 }
372
373 void SandboxFileSystemBackendDelegate::GetOriginsForHostOnFileTaskRunner(
374     FileSystemType type, const std::string& host,
375     std::set<GURL>* origins) {
376   DCHECK(file_task_runner_->RunsTasksOnCurrentThread());
377   DCHECK(origins);
378   scoped_ptr<OriginEnumerator> enumerator(CreateOriginEnumerator());
379   GURL origin;
380   while (!(origin = enumerator->Next()).is_empty()) {
381     if (host == net::GetHostOrSpecFromURL(origin) &&
382         enumerator->HasFileSystemType(type))
383       origins->insert(origin);
384   }
385 }
386
387 int64 SandboxFileSystemBackendDelegate::GetOriginUsageOnFileTaskRunner(
388     FileSystemContext* file_system_context,
389     const GURL& origin_url,
390     FileSystemType type) {
391   DCHECK(file_task_runner_->RunsTasksOnCurrentThread());
392
393   // Don't use usage cache and return recalculated usage for sticky invalidated
394   // origins.
395   if (ContainsKey(sticky_dirty_origins_, std::make_pair(origin_url, type)))
396     return RecalculateUsage(file_system_context, origin_url, type);
397
398   base::FilePath base_path =
399       GetBaseDirectoryForOriginAndType(origin_url, type, false);
400   if (base_path.empty() || !base::DirectoryExists(base_path))
401     return 0;
402   base::FilePath usage_file_path =
403       base_path.Append(FileSystemUsageCache::kUsageFileName);
404
405   bool is_valid = usage_cache()->IsValid(usage_file_path);
406   uint32 dirty_status = 0;
407   bool dirty_status_available =
408       usage_cache()->GetDirty(usage_file_path, &dirty_status);
409   bool visited = !visited_origins_.insert(origin_url).second;
410   if (is_valid && (dirty_status == 0 || (dirty_status_available && visited))) {
411     // The usage cache is clean (dirty == 0) or the origin is already
412     // initialized and running.  Read the cache file to get the usage.
413     int64 usage = 0;
414     return usage_cache()->GetUsage(usage_file_path, &usage) ? usage : -1;
415   }
416   // The usage cache has not been initialized or the cache is dirty.
417   // Get the directory size now and update the cache.
418   usage_cache()->Delete(usage_file_path);
419
420   int64 usage = RecalculateUsage(file_system_context, origin_url, type);
421
422   // This clears the dirty flag too.
423   usage_cache()->UpdateUsage(usage_file_path, usage);
424   return usage;
425 }
426
427 scoped_refptr<QuotaReservation>
428 SandboxFileSystemBackendDelegate::CreateQuotaReservationOnFileTaskRunner(
429     const GURL& origin,
430     FileSystemType type) {
431   DCHECK(file_task_runner_->RunsTasksOnCurrentThread());
432   DCHECK(quota_reservation_manager_);
433   return quota_reservation_manager_->CreateReservation(origin, type);
434 }
435
436 void SandboxFileSystemBackendDelegate::AddFileUpdateObserver(
437     FileSystemType type,
438     FileUpdateObserver* observer,
439     base::SequencedTaskRunner* task_runner) {
440   DCHECK(!is_filesystem_opened_ || io_thread_checker_.CalledOnValidThread());
441   update_observers_[type] =
442       update_observers_[type].AddObserver(observer, task_runner);
443 }
444
445 void SandboxFileSystemBackendDelegate::AddFileChangeObserver(
446     FileSystemType type,
447     FileChangeObserver* observer,
448     base::SequencedTaskRunner* task_runner) {
449   DCHECK(!is_filesystem_opened_ || io_thread_checker_.CalledOnValidThread());
450   change_observers_[type] =
451       change_observers_[type].AddObserver(observer, task_runner);
452 }
453
454 void SandboxFileSystemBackendDelegate::AddFileAccessObserver(
455     FileSystemType type,
456     FileAccessObserver* observer,
457     base::SequencedTaskRunner* task_runner) {
458   DCHECK(!is_filesystem_opened_ || io_thread_checker_.CalledOnValidThread());
459   access_observers_[type] =
460       access_observers_[type].AddObserver(observer, task_runner);
461 }
462
463 const UpdateObserverList* SandboxFileSystemBackendDelegate::GetUpdateObservers(
464     FileSystemType type) const {
465   std::map<FileSystemType, UpdateObserverList>::const_iterator iter =
466       update_observers_.find(type);
467   if (iter == update_observers_.end())
468     return NULL;
469   return &iter->second;
470 }
471
472 const ChangeObserverList* SandboxFileSystemBackendDelegate::GetChangeObservers(
473     FileSystemType type) const {
474   std::map<FileSystemType, ChangeObserverList>::const_iterator iter =
475       change_observers_.find(type);
476   if (iter == change_observers_.end())
477     return NULL;
478   return &iter->second;
479 }
480
481 const AccessObserverList* SandboxFileSystemBackendDelegate::GetAccessObservers(
482     FileSystemType type) const {
483   std::map<FileSystemType, AccessObserverList>::const_iterator iter =
484       access_observers_.find(type);
485   if (iter == access_observers_.end())
486     return NULL;
487   return &iter->second;
488 }
489
490 void SandboxFileSystemBackendDelegate::RegisterQuotaUpdateObserver(
491     FileSystemType type) {
492   AddFileUpdateObserver(type, quota_observer_.get(), file_task_runner_.get());
493 }
494
495 void SandboxFileSystemBackendDelegate::InvalidateUsageCache(
496     const GURL& origin,
497     FileSystemType type) {
498   base::File::Error error = base::File::FILE_OK;
499   base::FilePath usage_file_path = GetUsageCachePathForOriginAndType(
500       obfuscated_file_util(), origin, type, &error);
501   if (error != base::File::FILE_OK)
502     return;
503   usage_cache()->IncrementDirty(usage_file_path);
504 }
505
506 void SandboxFileSystemBackendDelegate::StickyInvalidateUsageCache(
507     const GURL& origin,
508     FileSystemType type) {
509   sticky_dirty_origins_.insert(std::make_pair(origin, type));
510   quota_observer()->SetUsageCacheEnabled(origin, type, false);
511   InvalidateUsageCache(origin, type);
512 }
513
514 FileSystemFileUtil* SandboxFileSystemBackendDelegate::sync_file_util() {
515   return static_cast<AsyncFileUtilAdapter*>(file_util())->sync_file_util();
516 }
517
518 bool SandboxFileSystemBackendDelegate::IsAccessValid(
519     const FileSystemURL& url) const {
520   if (!IsAllowedScheme(url.origin()))
521     return false;
522
523   if (url.path().ReferencesParent())
524     return false;
525
526   // Return earlier if the path is '/', because VirtualPath::BaseName()
527   // returns '/' for '/' and we fail the "basename != '/'" check below.
528   // (We exclude '.' because it's disallowed by spec.)
529   if (VirtualPath::IsRootPath(url.path()) &&
530       url.path() != base::FilePath(base::FilePath::kCurrentDirectory))
531     return true;
532
533   // Restricted names specified in
534   // http://dev.w3.org/2009/dap/file-system/file-dir-sys.html#naming-restrictions
535   base::FilePath filename = VirtualPath::BaseName(url.path());
536   // See if the name is allowed to create.
537   for (size_t i = 0; i < arraysize(kRestrictedNames); ++i) {
538     if (filename.value() == kRestrictedNames[i])
539       return false;
540   }
541   for (size_t i = 0; i < arraysize(kRestrictedChars); ++i) {
542     if (filename.value().find(kRestrictedChars[i]) !=
543         base::FilePath::StringType::npos)
544       return false;
545   }
546
547   return true;
548 }
549
550 bool SandboxFileSystemBackendDelegate::IsAllowedScheme(const GURL& url) const {
551   // Basically we only accept http or https. We allow file:// URLs
552   // only if --allow-file-access-from-files flag is given.
553   if (url.SchemeIsHTTPOrHTTPS())
554     return true;
555   if (url.SchemeIsFileSystem())
556     return url.inner_url() && IsAllowedScheme(*url.inner_url());
557
558   for (size_t i = 0;
559        i < file_system_options_.additional_allowed_schemes().size();
560        ++i) {
561     if (url.SchemeIs(
562             file_system_options_.additional_allowed_schemes()[i].c_str()))
563       return true;
564   }
565   return false;
566 }
567
568 base::FilePath
569 SandboxFileSystemBackendDelegate::GetUsageCachePathForOriginAndType(
570     const GURL& origin_url,
571     FileSystemType type) {
572   base::File::Error error;
573   base::FilePath path = GetUsageCachePathForOriginAndType(
574       obfuscated_file_util(), origin_url, type, &error);
575   if (error != base::File::FILE_OK)
576     return base::FilePath();
577   return path;
578 }
579
580 // static
581 base::FilePath
582 SandboxFileSystemBackendDelegate::GetUsageCachePathForOriginAndType(
583     ObfuscatedFileUtil* sandbox_file_util,
584     const GURL& origin_url,
585     FileSystemType type,
586     base::File::Error* error_out) {
587   DCHECK(error_out);
588   *error_out = base::File::FILE_OK;
589   base::FilePath base_path = sandbox_file_util->GetDirectoryForOriginAndType(
590       origin_url, GetTypeString(type), false /* create */, error_out);
591   if (*error_out != base::File::FILE_OK)
592     return base::FilePath();
593   return base_path.Append(FileSystemUsageCache::kUsageFileName);
594 }
595
596 int64 SandboxFileSystemBackendDelegate::RecalculateUsage(
597     FileSystemContext* context,
598     const GURL& origin,
599     FileSystemType type) {
600   FileSystemOperationContext operation_context(context);
601   FileSystemURL url = context->CreateCrackedFileSystemURL(
602       origin, type, base::FilePath());
603   scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator> enumerator(
604       obfuscated_file_util()->CreateFileEnumerator(
605           &operation_context, url, true));
606
607   base::FilePath file_path_each;
608   int64 usage = 0;
609
610   while (!(file_path_each = enumerator->Next()).empty()) {
611     usage += enumerator->Size();
612     usage += ObfuscatedFileUtil::ComputeFilePathCost(file_path_each);
613   }
614
615   return usage;
616 }
617
618 void SandboxFileSystemBackendDelegate::CollectOpenFileSystemMetrics(
619     base::File::Error error_code) {
620   base::Time now = base::Time::Now();
621   bool throttled = now < next_release_time_for_open_filesystem_stat_;
622   if (!throttled) {
623     next_release_time_for_open_filesystem_stat_ =
624         now + base::TimeDelta::FromHours(kMinimumStatsCollectionIntervalHours);
625   }
626
627 #define REPORT(report_value)                                            \
628   UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemDetailLabel,                 \
629                             (report_value),                             \
630                             kFileSystemErrorMax);                       \
631   if (!throttled) {                                                     \
632     UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemDetailNonThrottledLabel,   \
633                               (report_value),                           \
634                               kFileSystemErrorMax);                     \
635   }
636
637   switch (error_code) {
638     case base::File::FILE_OK:
639       REPORT(kOK);
640       break;
641     case base::File::FILE_ERROR_INVALID_URL:
642       REPORT(kInvalidSchemeError);
643       break;
644     case base::File::FILE_ERROR_NOT_FOUND:
645       REPORT(kNotFound);
646       break;
647     case base::File::FILE_ERROR_FAILED:
648     default:
649       REPORT(kUnknownError);
650       break;
651   }
652 #undef REPORT
653 }
654
655 ObfuscatedFileUtil* SandboxFileSystemBackendDelegate::obfuscated_file_util() {
656   return static_cast<ObfuscatedFileUtil*>(sync_file_util());
657 }
658
659 // Declared in obfuscated_file_util.h.
660 // static
661 ObfuscatedFileUtil* ObfuscatedFileUtil::CreateForTesting(
662     quota::SpecialStoragePolicy* special_storage_policy,
663     const base::FilePath& file_system_directory,
664     leveldb::Env* env_override,
665     base::SequencedTaskRunner* file_task_runner) {
666   return new ObfuscatedFileUtil(special_storage_policy,
667                                 file_system_directory,
668                                 env_override,
669                                 file_task_runner,
670                                 base::Bind(&GetTypeStringForURL),
671                                 GetKnownTypeStrings(),
672                                 NULL);
673 }
674
675 }  // namespace fileapi