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.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
GetTypeStringForURL(const FileSystemURL & url)77 std::string GetTypeStringForURL(const FileSystemURL& url) {
78 return SandboxFileSystemBackendDelegate::GetTypeString(url.type());
79 }
80
GetKnownTypeStrings()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:
ObfuscatedOriginEnumerator(ObfuscatedFileUtil * file_util)92 explicit ObfuscatedOriginEnumerator(ObfuscatedFileUtil* file_util) {
93 enum_.reset(file_util->CreateOriginEnumerator());
94 }
~ObfuscatedOriginEnumerator()95 virtual ~ObfuscatedOriginEnumerator() {}
96
Next()97 virtual GURL Next() OVERRIDE {
98 return enum_->Next();
99 }
100
HasFileSystemType(FileSystemType type) const101 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
OpenFileSystemOnFileThread(ObfuscatedFileUtil * file_util,const GURL & origin_url,FileSystemType type,OpenFileSystemMode mode,base::PlatformFileError * error_ptr)110 void OpenFileSystemOnFileThread(
111 ObfuscatedFileUtil* file_util,
112 const GURL& origin_url,
113 FileSystemType type,
114 OpenFileSystemMode mode,
115 base::PlatformFileError* 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::PLATFORM_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
DidOpenFileSystem(base::WeakPtr<SandboxFileSystemBackendDelegate> delegate,const base::Callback<void (base::PlatformFileError error)> & callback,base::PlatformFileError * error)133 void DidOpenFileSystem(
134 base::WeakPtr<SandboxFileSystemBackendDelegate> delegate,
135 const base::Callback<void(base::PlatformFileError error)>& callback,
136 base::PlatformFileError* error) {
137 if (delegate.get())
138 delegate.get()->CollectOpenFileSystemMetrics(*error);
139 callback.Run(*error);
140 }
141
142 template <typename T>
DeleteSoon(base::SequencedTaskRunner * runner,T * ptr)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
GetTypeString(FileSystemType type)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
SandboxFileSystemBackendDelegate(quota::QuotaManagerProxy * quota_manager_proxy,base::SequencedTaskRunner * file_task_runner,const base::FilePath & profile_path,quota::SpecialStoragePolicy * special_storage_policy,const FileSystemOptions & file_system_options)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_task_runner,
184 base::Bind(&GetTypeStringForURL),
185 GetKnownTypeStrings(),
186 this))),
187 file_system_usage_cache_(new FileSystemUsageCache(file_task_runner)),
188 quota_observer_(new SandboxQuotaObserver(
189 quota_manager_proxy,
190 file_task_runner,
191 obfuscated_file_util(),
192 usage_cache())),
193 quota_reservation_manager_(new QuotaReservationManager(
194 scoped_ptr<QuotaReservationManager::QuotaBackend>(
195 new QuotaBackendImpl(file_task_runner_,
196 obfuscated_file_util(),
197 usage_cache(),
198 quota_manager_proxy)))),
199 special_storage_policy_(special_storage_policy),
200 file_system_options_(file_system_options),
201 is_filesystem_opened_(false),
202 weak_factory_(this) {
203 // Prepopulate database only if it can run asynchronously (i.e. the current
204 // thread is not file_task_runner). Usually this is the case but may not
205 // in test code.
206 if (!file_task_runner_->RunsTasksOnCurrentThread()) {
207 std::vector<std::string> types_to_prepopulate(
208 &kPrepopulateTypes[0],
209 &kPrepopulateTypes[arraysize(kPrepopulateTypes)]);
210 file_task_runner_->PostTask(
211 FROM_HERE,
212 base::Bind(&ObfuscatedFileUtil::MaybePrepopulateDatabase,
213 base::Unretained(obfuscated_file_util()),
214 types_to_prepopulate));
215 }
216 }
217
~SandboxFileSystemBackendDelegate()218 SandboxFileSystemBackendDelegate::~SandboxFileSystemBackendDelegate() {
219 io_thread_checker_.DetachFromThread();
220
221 if (!file_task_runner_->RunsTasksOnCurrentThread()) {
222 DeleteSoon(file_task_runner_.get(), quota_reservation_manager_.release());
223 DeleteSoon(file_task_runner_.get(), sandbox_file_util_.release());
224 DeleteSoon(file_task_runner_.get(), quota_observer_.release());
225 DeleteSoon(file_task_runner_.get(), file_system_usage_cache_.release());
226 }
227 }
228
229 SandboxFileSystemBackendDelegate::OriginEnumerator*
CreateOriginEnumerator()230 SandboxFileSystemBackendDelegate::CreateOriginEnumerator() {
231 return new ObfuscatedOriginEnumerator(obfuscated_file_util());
232 }
233
234 base::FilePath
GetBaseDirectoryForOriginAndType(const GURL & origin_url,FileSystemType type,bool create)235 SandboxFileSystemBackendDelegate::GetBaseDirectoryForOriginAndType(
236 const GURL& origin_url,
237 FileSystemType type,
238 bool create) {
239 base::PlatformFileError error = base::PLATFORM_FILE_OK;
240 base::FilePath path = obfuscated_file_util()->GetDirectoryForOriginAndType(
241 origin_url, GetTypeString(type), create, &error);
242 if (error != base::PLATFORM_FILE_OK)
243 return base::FilePath();
244 return path;
245 }
246
OpenFileSystem(const GURL & origin_url,FileSystemType type,OpenFileSystemMode mode,const OpenFileSystemCallback & callback,const GURL & root_url)247 void SandboxFileSystemBackendDelegate::OpenFileSystem(
248 const GURL& origin_url,
249 FileSystemType type,
250 OpenFileSystemMode mode,
251 const OpenFileSystemCallback& callback,
252 const GURL& root_url) {
253 if (!IsAllowedScheme(origin_url)) {
254 callback.Run(GURL(), std::string(), base::PLATFORM_FILE_ERROR_SECURITY);
255 return;
256 }
257
258 std::string name = GetFileSystemName(origin_url, type);
259
260 base::PlatformFileError* error_ptr = new base::PlatformFileError;
261 file_task_runner_->PostTaskAndReply(
262 FROM_HERE,
263 base::Bind(&OpenFileSystemOnFileThread,
264 obfuscated_file_util(), origin_url, type, mode,
265 base::Unretained(error_ptr)),
266 base::Bind(&DidOpenFileSystem,
267 weak_factory_.GetWeakPtr(),
268 base::Bind(callback, root_url, name),
269 base::Owned(error_ptr)));
270
271 io_thread_checker_.DetachFromThread();
272 is_filesystem_opened_ = true;
273 }
274
275 scoped_ptr<FileSystemOperationContext>
CreateFileSystemOperationContext(const FileSystemURL & url,FileSystemContext * context,base::PlatformFileError * error_code) const276 SandboxFileSystemBackendDelegate::CreateFileSystemOperationContext(
277 const FileSystemURL& url,
278 FileSystemContext* context,
279 base::PlatformFileError* error_code) const {
280 if (!IsAccessValid(url)) {
281 *error_code = base::PLATFORM_FILE_ERROR_SECURITY;
282 return scoped_ptr<FileSystemOperationContext>();
283 }
284
285 const UpdateObserverList* update_observers = GetUpdateObservers(url.type());
286 const ChangeObserverList* change_observers = GetChangeObservers(url.type());
287 DCHECK(update_observers);
288
289 scoped_ptr<FileSystemOperationContext> operation_context(
290 new FileSystemOperationContext(context));
291 operation_context->set_update_observers(*update_observers);
292 operation_context->set_change_observers(
293 change_observers ? *change_observers : ChangeObserverList());
294
295 return operation_context.Pass();
296 }
297
298 scoped_ptr<webkit_blob::FileStreamReader>
CreateFileStreamReader(const FileSystemURL & url,int64 offset,const base::Time & expected_modification_time,FileSystemContext * context) const299 SandboxFileSystemBackendDelegate::CreateFileStreamReader(
300 const FileSystemURL& url,
301 int64 offset,
302 const base::Time& expected_modification_time,
303 FileSystemContext* context) const {
304 if (!IsAccessValid(url))
305 return scoped_ptr<webkit_blob::FileStreamReader>();
306 return scoped_ptr<webkit_blob::FileStreamReader>(
307 webkit_blob::FileStreamReader::CreateForFileSystemFile(
308 context, url, offset, expected_modification_time));
309 }
310
311 scoped_ptr<FileStreamWriter>
CreateFileStreamWriter(const FileSystemURL & url,int64 offset,FileSystemContext * context,FileSystemType type) const312 SandboxFileSystemBackendDelegate::CreateFileStreamWriter(
313 const FileSystemURL& url,
314 int64 offset,
315 FileSystemContext* context,
316 FileSystemType type) const {
317 if (!IsAccessValid(url))
318 return scoped_ptr<FileStreamWriter>();
319 const UpdateObserverList* observers = GetUpdateObservers(type);
320 DCHECK(observers);
321 return scoped_ptr<FileStreamWriter>(
322 new SandboxFileStreamWriter(context, url, offset, *observers));
323 }
324
325 base::PlatformFileError
DeleteOriginDataOnFileThread(FileSystemContext * file_system_context,quota::QuotaManagerProxy * proxy,const GURL & origin_url,FileSystemType type)326 SandboxFileSystemBackendDelegate::DeleteOriginDataOnFileThread(
327 FileSystemContext* file_system_context,
328 quota::QuotaManagerProxy* proxy,
329 const GURL& origin_url,
330 FileSystemType type) {
331 int64 usage = GetOriginUsageOnFileThread(
332 file_system_context, origin_url, type);
333 usage_cache()->CloseCacheFiles();
334 bool result = obfuscated_file_util()->DeleteDirectoryForOriginAndType(
335 origin_url, GetTypeString(type));
336 if (result && proxy) {
337 proxy->NotifyStorageModified(
338 quota::QuotaClient::kFileSystem,
339 origin_url,
340 FileSystemTypeToQuotaStorageType(type),
341 -usage);
342 }
343
344 if (result)
345 return base::PLATFORM_FILE_OK;
346 return base::PLATFORM_FILE_ERROR_FAILED;
347 }
348
GetOriginsForTypeOnFileThread(FileSystemType type,std::set<GURL> * origins)349 void SandboxFileSystemBackendDelegate::GetOriginsForTypeOnFileThread(
350 FileSystemType type, std::set<GURL>* origins) {
351 DCHECK(origins);
352 scoped_ptr<OriginEnumerator> enumerator(CreateOriginEnumerator());
353 GURL origin;
354 while (!(origin = enumerator->Next()).is_empty()) {
355 if (enumerator->HasFileSystemType(type))
356 origins->insert(origin);
357 }
358 switch (type) {
359 case kFileSystemTypeTemporary:
360 UMA_HISTOGRAM_COUNTS(kTemporaryOriginsCountLabel, origins->size());
361 break;
362 case kFileSystemTypePersistent:
363 UMA_HISTOGRAM_COUNTS(kPersistentOriginsCountLabel, origins->size());
364 break;
365 default:
366 break;
367 }
368 }
369
GetOriginsForHostOnFileThread(FileSystemType type,const std::string & host,std::set<GURL> * origins)370 void SandboxFileSystemBackendDelegate::GetOriginsForHostOnFileThread(
371 FileSystemType type, const std::string& host,
372 std::set<GURL>* origins) {
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);
380 }
381 }
382
GetOriginUsageOnFileThread(FileSystemContext * file_system_context,const GURL & origin_url,FileSystemType type)383 int64 SandboxFileSystemBackendDelegate::GetOriginUsageOnFileThread(
384 FileSystemContext* file_system_context,
385 const GURL& origin_url,
386 FileSystemType type) {
387 // Don't use usage cache and return recalculated usage for sticky invalidated
388 // origins.
389 if (ContainsKey(sticky_dirty_origins_, std::make_pair(origin_url, type)))
390 return RecalculateUsage(file_system_context, origin_url, type);
391
392 base::FilePath base_path =
393 GetBaseDirectoryForOriginAndType(origin_url, type, false);
394 if (base_path.empty() || !base::DirectoryExists(base_path))
395 return 0;
396 base::FilePath usage_file_path =
397 base_path.Append(FileSystemUsageCache::kUsageFileName);
398
399 bool is_valid = usage_cache()->IsValid(usage_file_path);
400 uint32 dirty_status = 0;
401 bool dirty_status_available =
402 usage_cache()->GetDirty(usage_file_path, &dirty_status);
403 bool visited = !visited_origins_.insert(origin_url).second;
404 if (is_valid && (dirty_status == 0 || (dirty_status_available && visited))) {
405 // The usage cache is clean (dirty == 0) or the origin is already
406 // initialized and running. Read the cache file to get the usage.
407 int64 usage = 0;
408 return usage_cache()->GetUsage(usage_file_path, &usage) ? usage : -1;
409 }
410 // The usage cache has not been initialized or the cache is dirty.
411 // Get the directory size now and update the cache.
412 usage_cache()->Delete(usage_file_path);
413
414 int64 usage = RecalculateUsage(file_system_context, origin_url, type);
415
416 // This clears the dirty flag too.
417 usage_cache()->UpdateUsage(usage_file_path, usage);
418 return usage;
419 }
420
421 scoped_refptr<QuotaReservation>
CreateQuotaReservationOnFileTaskRunner(const GURL & origin,FileSystemType type)422 SandboxFileSystemBackendDelegate::CreateQuotaReservationOnFileTaskRunner(
423 const GURL& origin,
424 FileSystemType type) {
425 DCHECK(file_task_runner_->RunsTasksOnCurrentThread());
426 DCHECK(quota_reservation_manager_);
427 return quota_reservation_manager_->CreateReservation(origin, type);
428 }
429
AddFileUpdateObserver(FileSystemType type,FileUpdateObserver * observer,base::SequencedTaskRunner * task_runner)430 void SandboxFileSystemBackendDelegate::AddFileUpdateObserver(
431 FileSystemType type,
432 FileUpdateObserver* observer,
433 base::SequencedTaskRunner* task_runner) {
434 DCHECK(!is_filesystem_opened_ || io_thread_checker_.CalledOnValidThread());
435 update_observers_[type] =
436 update_observers_[type].AddObserver(observer, task_runner);
437 }
438
AddFileChangeObserver(FileSystemType type,FileChangeObserver * observer,base::SequencedTaskRunner * task_runner)439 void SandboxFileSystemBackendDelegate::AddFileChangeObserver(
440 FileSystemType type,
441 FileChangeObserver* observer,
442 base::SequencedTaskRunner* task_runner) {
443 DCHECK(!is_filesystem_opened_ || io_thread_checker_.CalledOnValidThread());
444 change_observers_[type] =
445 change_observers_[type].AddObserver(observer, task_runner);
446 }
447
AddFileAccessObserver(FileSystemType type,FileAccessObserver * observer,base::SequencedTaskRunner * task_runner)448 void SandboxFileSystemBackendDelegate::AddFileAccessObserver(
449 FileSystemType type,
450 FileAccessObserver* observer,
451 base::SequencedTaskRunner* task_runner) {
452 DCHECK(!is_filesystem_opened_ || io_thread_checker_.CalledOnValidThread());
453 access_observers_[type] =
454 access_observers_[type].AddObserver(observer, task_runner);
455 }
456
GetUpdateObservers(FileSystemType type) const457 const UpdateObserverList* SandboxFileSystemBackendDelegate::GetUpdateObservers(
458 FileSystemType type) const {
459 std::map<FileSystemType, UpdateObserverList>::const_iterator iter =
460 update_observers_.find(type);
461 if (iter == update_observers_.end())
462 return NULL;
463 return &iter->second;
464 }
465
GetChangeObservers(FileSystemType type) const466 const ChangeObserverList* SandboxFileSystemBackendDelegate::GetChangeObservers(
467 FileSystemType type) const {
468 std::map<FileSystemType, ChangeObserverList>::const_iterator iter =
469 change_observers_.find(type);
470 if (iter == change_observers_.end())
471 return NULL;
472 return &iter->second;
473 }
474
GetAccessObservers(FileSystemType type) const475 const AccessObserverList* SandboxFileSystemBackendDelegate::GetAccessObservers(
476 FileSystemType type) const {
477 std::map<FileSystemType, AccessObserverList>::const_iterator iter =
478 access_observers_.find(type);
479 if (iter == access_observers_.end())
480 return NULL;
481 return &iter->second;
482 }
483
RegisterQuotaUpdateObserver(FileSystemType type)484 void SandboxFileSystemBackendDelegate::RegisterQuotaUpdateObserver(
485 FileSystemType type) {
486 AddFileUpdateObserver(type, quota_observer_.get(), file_task_runner_.get());
487 }
488
InvalidateUsageCache(const GURL & origin,FileSystemType type)489 void SandboxFileSystemBackendDelegate::InvalidateUsageCache(
490 const GURL& origin,
491 FileSystemType type) {
492 base::PlatformFileError error = base::PLATFORM_FILE_OK;
493 base::FilePath usage_file_path = GetUsageCachePathForOriginAndType(
494 obfuscated_file_util(), origin, type, &error);
495 if (error != base::PLATFORM_FILE_OK)
496 return;
497 usage_cache()->IncrementDirty(usage_file_path);
498 }
499
StickyInvalidateUsageCache(const GURL & origin,FileSystemType type)500 void SandboxFileSystemBackendDelegate::StickyInvalidateUsageCache(
501 const GURL& origin,
502 FileSystemType type) {
503 sticky_dirty_origins_.insert(std::make_pair(origin, type));
504 quota_observer()->SetUsageCacheEnabled(origin, type, false);
505 InvalidateUsageCache(origin, type);
506 }
507
sync_file_util()508 FileSystemFileUtil* SandboxFileSystemBackendDelegate::sync_file_util() {
509 return static_cast<AsyncFileUtilAdapter*>(file_util())->sync_file_util();
510 }
511
IsAccessValid(const FileSystemURL & url) const512 bool SandboxFileSystemBackendDelegate::IsAccessValid(
513 const FileSystemURL& url) const {
514 if (!IsAllowedScheme(url.origin()))
515 return false;
516
517 if (url.path().ReferencesParent())
518 return false;
519
520 // Return earlier if the path is '/', because VirtualPath::BaseName()
521 // returns '/' for '/' and we fail the "basename != '/'" check below.
522 // (We exclude '.' because it's disallowed by spec.)
523 if (VirtualPath::IsRootPath(url.path()) &&
524 url.path() != base::FilePath(base::FilePath::kCurrentDirectory))
525 return true;
526
527 // Restricted names specified in
528 // http://dev.w3.org/2009/dap/file-system/file-dir-sys.html#naming-restrictions
529 base::FilePath filename = VirtualPath::BaseName(url.path());
530 // See if the name is allowed to create.
531 for (size_t i = 0; i < arraysize(kRestrictedNames); ++i) {
532 if (filename.value() == kRestrictedNames[i])
533 return false;
534 }
535 for (size_t i = 0; i < arraysize(kRestrictedChars); ++i) {
536 if (filename.value().find(kRestrictedChars[i]) !=
537 base::FilePath::StringType::npos)
538 return false;
539 }
540
541 return true;
542 }
543
IsAllowedScheme(const GURL & url) const544 bool SandboxFileSystemBackendDelegate::IsAllowedScheme(const GURL& url) const {
545 // Basically we only accept http or https. We allow file:// URLs
546 // only if --allow-file-access-from-files flag is given.
547 if (url.SchemeIsHTTPOrHTTPS())
548 return true;
549 if (url.SchemeIsFileSystem())
550 return url.inner_url() && IsAllowedScheme(*url.inner_url());
551
552 for (size_t i = 0;
553 i < file_system_options_.additional_allowed_schemes().size();
554 ++i) {
555 if (url.SchemeIs(
556 file_system_options_.additional_allowed_schemes()[i].c_str()))
557 return true;
558 }
559 return false;
560 }
561
562 base::FilePath
GetUsageCachePathForOriginAndType(const GURL & origin_url,FileSystemType type)563 SandboxFileSystemBackendDelegate::GetUsageCachePathForOriginAndType(
564 const GURL& origin_url,
565 FileSystemType type) {
566 base::PlatformFileError error;
567 base::FilePath path = GetUsageCachePathForOriginAndType(
568 obfuscated_file_util(), origin_url, type, &error);
569 if (error != base::PLATFORM_FILE_OK)
570 return base::FilePath();
571 return path;
572 }
573
574 // static
575 base::FilePath
GetUsageCachePathForOriginAndType(ObfuscatedFileUtil * sandbox_file_util,const GURL & origin_url,FileSystemType type,base::PlatformFileError * error_out)576 SandboxFileSystemBackendDelegate::GetUsageCachePathForOriginAndType(
577 ObfuscatedFileUtil* sandbox_file_util,
578 const GURL& origin_url,
579 FileSystemType type,
580 base::PlatformFileError* error_out) {
581 DCHECK(error_out);
582 *error_out = base::PLATFORM_FILE_OK;
583 base::FilePath base_path = sandbox_file_util->GetDirectoryForOriginAndType(
584 origin_url, GetTypeString(type), false /* create */, error_out);
585 if (*error_out != base::PLATFORM_FILE_OK)
586 return base::FilePath();
587 return base_path.Append(FileSystemUsageCache::kUsageFileName);
588 }
589
RecalculateUsage(FileSystemContext * context,const GURL & origin,FileSystemType type)590 int64 SandboxFileSystemBackendDelegate::RecalculateUsage(
591 FileSystemContext* context,
592 const GURL& origin,
593 FileSystemType type) {
594 FileSystemOperationContext operation_context(context);
595 FileSystemURL url = context->CreateCrackedFileSystemURL(
596 origin, type, base::FilePath());
597 scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator> enumerator(
598 obfuscated_file_util()->CreateFileEnumerator(
599 &operation_context, url, true));
600
601 base::FilePath file_path_each;
602 int64 usage = 0;
603
604 while (!(file_path_each = enumerator->Next()).empty()) {
605 usage += enumerator->Size();
606 usage += ObfuscatedFileUtil::ComputeFilePathCost(file_path_each);
607 }
608
609 return usage;
610 }
611
CollectOpenFileSystemMetrics(base::PlatformFileError error_code)612 void SandboxFileSystemBackendDelegate::CollectOpenFileSystemMetrics(
613 base::PlatformFileError error_code) {
614 base::Time now = base::Time::Now();
615 bool throttled = now < next_release_time_for_open_filesystem_stat_;
616 if (!throttled) {
617 next_release_time_for_open_filesystem_stat_ =
618 now + base::TimeDelta::FromHours(kMinimumStatsCollectionIntervalHours);
619 }
620
621 #define REPORT(report_value) \
622 UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemDetailLabel, \
623 (report_value), \
624 kFileSystemErrorMax); \
625 if (!throttled) { \
626 UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemDetailNonThrottledLabel, \
627 (report_value), \
628 kFileSystemErrorMax); \
629 }
630
631 switch (error_code) {
632 case base::PLATFORM_FILE_OK:
633 REPORT(kOK);
634 break;
635 case base::PLATFORM_FILE_ERROR_INVALID_URL:
636 REPORT(kInvalidSchemeError);
637 break;
638 case base::PLATFORM_FILE_ERROR_NOT_FOUND:
639 REPORT(kNotFound);
640 break;
641 case base::PLATFORM_FILE_ERROR_FAILED:
642 default:
643 REPORT(kUnknownError);
644 break;
645 }
646 #undef REPORT
647 }
648
obfuscated_file_util()649 ObfuscatedFileUtil* SandboxFileSystemBackendDelegate::obfuscated_file_util() {
650 return static_cast<ObfuscatedFileUtil*>(sync_file_util());
651 }
652
653 // Declared in obfuscated_file_util.h.
654 // static
CreateForTesting(quota::SpecialStoragePolicy * special_storage_policy,const base::FilePath & file_system_directory,base::SequencedTaskRunner * file_task_runner)655 ObfuscatedFileUtil* ObfuscatedFileUtil::CreateForTesting(
656 quota::SpecialStoragePolicy* special_storage_policy,
657 const base::FilePath& file_system_directory,
658 base::SequencedTaskRunner* file_task_runner) {
659 return new ObfuscatedFileUtil(special_storage_policy,
660 file_system_directory,
661 file_task_runner,
662 base::Bind(&GetTypeStringForURL),
663 GetKnownTypeStrings(),
664 NULL);
665 }
666
667 } // namespace fileapi
668