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