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 "storage/browser/fileapi/file_system_context.h"
6
7 #include "base/bind.h"
8 #include "base/single_thread_task_runner.h"
9 #include "base/stl_util.h"
10 #include "base/task_runner_util.h"
11 #include "net/url_request/url_request.h"
12 #include "storage/browser/blob/file_stream_reader.h"
13 #include "storage/browser/fileapi/copy_or_move_file_validator.h"
14 #include "storage/browser/fileapi/external_mount_points.h"
15 #include "storage/browser/fileapi/file_permission_policy.h"
16 #include "storage/browser/fileapi/file_stream_writer.h"
17 #include "storage/browser/fileapi/file_system_file_util.h"
18 #include "storage/browser/fileapi/file_system_operation.h"
19 #include "storage/browser/fileapi/file_system_operation_runner.h"
20 #include "storage/browser/fileapi/file_system_options.h"
21 #include "storage/browser/fileapi/file_system_quota_client.h"
22 #include "storage/browser/fileapi/file_system_url.h"
23 #include "storage/browser/fileapi/isolated_context.h"
24 #include "storage/browser/fileapi/isolated_file_system_backend.h"
25 #include "storage/browser/fileapi/mount_points.h"
26 #include "storage/browser/fileapi/quota/quota_reservation.h"
27 #include "storage/browser/fileapi/sandbox_file_system_backend.h"
28 #include "storage/browser/quota/quota_manager_proxy.h"
29 #include "storage/browser/quota/special_storage_policy.h"
30 #include "storage/common/fileapi/file_system_info.h"
31 #include "storage/common/fileapi/file_system_util.h"
32 #include "url/gurl.h"
33
34 using storage::QuotaClient;
35
36 namespace storage {
37
38 namespace {
39
CreateQuotaClient(FileSystemContext * context,bool is_incognito)40 QuotaClient* CreateQuotaClient(
41 FileSystemContext* context,
42 bool is_incognito) {
43 return new FileSystemQuotaClient(context, is_incognito);
44 }
45
46
DidGetMetadataForResolveURL(const base::FilePath & path,const FileSystemContext::ResolveURLCallback & callback,const FileSystemInfo & info,base::File::Error error,const base::File::Info & file_info)47 void DidGetMetadataForResolveURL(
48 const base::FilePath& path,
49 const FileSystemContext::ResolveURLCallback& callback,
50 const FileSystemInfo& info,
51 base::File::Error error,
52 const base::File::Info& file_info) {
53 if (error != base::File::FILE_OK) {
54 if (error == base::File::FILE_ERROR_NOT_FOUND) {
55 callback.Run(base::File::FILE_OK, info, path,
56 FileSystemContext::RESOLVED_ENTRY_NOT_FOUND);
57 } else {
58 callback.Run(error, FileSystemInfo(), base::FilePath(),
59 FileSystemContext::RESOLVED_ENTRY_NOT_FOUND);
60 }
61 return;
62 }
63 callback.Run(error, info, path, file_info.is_directory ?
64 FileSystemContext::RESOLVED_ENTRY_DIRECTORY :
65 FileSystemContext::RESOLVED_ENTRY_FILE);
66 }
67
RelayResolveURLCallback(scoped_refptr<base::MessageLoopProxy> message_loop,const FileSystemContext::ResolveURLCallback & callback,base::File::Error result,const FileSystemInfo & info,const base::FilePath & file_path,FileSystemContext::ResolvedEntryType type)68 void RelayResolveURLCallback(
69 scoped_refptr<base::MessageLoopProxy> message_loop,
70 const FileSystemContext::ResolveURLCallback& callback,
71 base::File::Error result,
72 const FileSystemInfo& info,
73 const base::FilePath& file_path,
74 FileSystemContext::ResolvedEntryType type) {
75 message_loop->PostTask(
76 FROM_HERE, base::Bind(callback, result, info, file_path, type));
77 }
78
79 } // namespace
80
81 // static
GetPermissionPolicy(FileSystemType type)82 int FileSystemContext::GetPermissionPolicy(FileSystemType type) {
83 switch (type) {
84 case kFileSystemTypeTemporary:
85 case kFileSystemTypePersistent:
86 case kFileSystemTypeSyncable:
87 return FILE_PERMISSION_SANDBOX;
88
89 case kFileSystemTypeDrive:
90 case kFileSystemTypeNativeForPlatformApp:
91 case kFileSystemTypeNativeLocal:
92 case kFileSystemTypeCloudDevice:
93 case kFileSystemTypeProvided:
94 case kFileSystemTypeDeviceMediaAsFileStorage:
95 return FILE_PERMISSION_USE_FILE_PERMISSION;
96
97 case kFileSystemTypeRestrictedNativeLocal:
98 return FILE_PERMISSION_READ_ONLY |
99 FILE_PERMISSION_USE_FILE_PERMISSION;
100
101 case kFileSystemTypeDeviceMedia:
102 case kFileSystemTypeIphoto:
103 case kFileSystemTypeItunes:
104 case kFileSystemTypeNativeMedia:
105 case kFileSystemTypePicasa:
106 return FILE_PERMISSION_USE_FILE_PERMISSION;
107
108 // Following types are only accessed via IsolatedFileSystem, and
109 // don't have their own permission policies.
110 case kFileSystemTypeDragged:
111 case kFileSystemTypeForTransientFile:
112 case kFileSystemTypePluginPrivate:
113 return FILE_PERMISSION_ALWAYS_DENY;
114
115 // Following types only appear as mount_type, and will not be
116 // queried for their permission policies.
117 case kFileSystemTypeIsolated:
118 case kFileSystemTypeExternal:
119 return FILE_PERMISSION_ALWAYS_DENY;
120
121 // Following types should not be used to access files by FileAPI clients.
122 case kFileSystemTypeTest:
123 case kFileSystemTypeSyncableForInternalSync:
124 case kFileSystemInternalTypeEnumEnd:
125 case kFileSystemInternalTypeEnumStart:
126 case kFileSystemTypeUnknown:
127 return FILE_PERMISSION_ALWAYS_DENY;
128 }
129 NOTREACHED();
130 return FILE_PERMISSION_ALWAYS_DENY;
131 }
132
FileSystemContext(base::SingleThreadTaskRunner * io_task_runner,base::SequencedTaskRunner * file_task_runner,ExternalMountPoints * external_mount_points,storage::SpecialStoragePolicy * special_storage_policy,storage::QuotaManagerProxy * quota_manager_proxy,ScopedVector<FileSystemBackend> additional_backends,const std::vector<URLRequestAutoMountHandler> & auto_mount_handlers,const base::FilePath & partition_path,const FileSystemOptions & options)133 FileSystemContext::FileSystemContext(
134 base::SingleThreadTaskRunner* io_task_runner,
135 base::SequencedTaskRunner* file_task_runner,
136 ExternalMountPoints* external_mount_points,
137 storage::SpecialStoragePolicy* special_storage_policy,
138 storage::QuotaManagerProxy* quota_manager_proxy,
139 ScopedVector<FileSystemBackend> additional_backends,
140 const std::vector<URLRequestAutoMountHandler>& auto_mount_handlers,
141 const base::FilePath& partition_path,
142 const FileSystemOptions& options)
143 : io_task_runner_(io_task_runner),
144 default_file_task_runner_(file_task_runner),
145 quota_manager_proxy_(quota_manager_proxy),
146 sandbox_delegate_(
147 new SandboxFileSystemBackendDelegate(quota_manager_proxy,
148 file_task_runner,
149 partition_path,
150 special_storage_policy,
151 options)),
152 sandbox_backend_(new SandboxFileSystemBackend(sandbox_delegate_.get())),
153 isolated_backend_(new IsolatedFileSystemBackend()),
154 plugin_private_backend_(
155 new PluginPrivateFileSystemBackend(file_task_runner,
156 partition_path,
157 special_storage_policy,
158 options)),
159 additional_backends_(additional_backends.Pass()),
160 auto_mount_handlers_(auto_mount_handlers),
161 external_mount_points_(external_mount_points),
162 partition_path_(partition_path),
163 is_incognito_(options.is_incognito()),
164 operation_runner_(new FileSystemOperationRunner(this)) {
165 RegisterBackend(sandbox_backend_.get());
166 RegisterBackend(isolated_backend_.get());
167 RegisterBackend(plugin_private_backend_.get());
168
169 for (ScopedVector<FileSystemBackend>::const_iterator iter =
170 additional_backends_.begin();
171 iter != additional_backends_.end(); ++iter) {
172 RegisterBackend(*iter);
173 }
174
175 if (quota_manager_proxy) {
176 // Quota client assumes all backends have registered.
177 quota_manager_proxy->RegisterClient(CreateQuotaClient(
178 this, options.is_incognito()));
179 }
180
181 sandbox_backend_->Initialize(this);
182 isolated_backend_->Initialize(this);
183 plugin_private_backend_->Initialize(this);
184 for (ScopedVector<FileSystemBackend>::const_iterator iter =
185 additional_backends_.begin();
186 iter != additional_backends_.end(); ++iter) {
187 (*iter)->Initialize(this);
188 }
189
190 // Additional mount points must be added before regular system-wide
191 // mount points.
192 if (external_mount_points)
193 url_crackers_.push_back(external_mount_points);
194 url_crackers_.push_back(ExternalMountPoints::GetSystemInstance());
195 url_crackers_.push_back(IsolatedContext::GetInstance());
196 }
197
DeleteDataForOriginOnFileTaskRunner(const GURL & origin_url)198 bool FileSystemContext::DeleteDataForOriginOnFileTaskRunner(
199 const GURL& origin_url) {
200 DCHECK(default_file_task_runner()->RunsTasksOnCurrentThread());
201 DCHECK(origin_url == origin_url.GetOrigin());
202
203 bool success = true;
204 for (FileSystemBackendMap::iterator iter = backend_map_.begin();
205 iter != backend_map_.end();
206 ++iter) {
207 FileSystemBackend* backend = iter->second;
208 if (!backend->GetQuotaUtil())
209 continue;
210 if (backend->GetQuotaUtil()->DeleteOriginDataOnFileTaskRunner(
211 this, quota_manager_proxy(), origin_url, iter->first)
212 != base::File::FILE_OK) {
213 // Continue the loop, but record the failure.
214 success = false;
215 }
216 }
217
218 return success;
219 }
220
221 scoped_refptr<QuotaReservation>
CreateQuotaReservationOnFileTaskRunner(const GURL & origin_url,FileSystemType type)222 FileSystemContext::CreateQuotaReservationOnFileTaskRunner(
223 const GURL& origin_url,
224 FileSystemType type) {
225 DCHECK(default_file_task_runner()->RunsTasksOnCurrentThread());
226 FileSystemBackend* backend = GetFileSystemBackend(type);
227 if (!backend || !backend->GetQuotaUtil())
228 return scoped_refptr<QuotaReservation>();
229 return backend->GetQuotaUtil()->CreateQuotaReservationOnFileTaskRunner(
230 origin_url, type);
231 }
232
Shutdown()233 void FileSystemContext::Shutdown() {
234 if (!io_task_runner_->RunsTasksOnCurrentThread()) {
235 io_task_runner_->PostTask(
236 FROM_HERE, base::Bind(&FileSystemContext::Shutdown,
237 make_scoped_refptr(this)));
238 return;
239 }
240 operation_runner_->Shutdown();
241 }
242
243 FileSystemQuotaUtil*
GetQuotaUtil(FileSystemType type) const244 FileSystemContext::GetQuotaUtil(FileSystemType type) const {
245 FileSystemBackend* backend = GetFileSystemBackend(type);
246 if (!backend)
247 return NULL;
248 return backend->GetQuotaUtil();
249 }
250
GetAsyncFileUtil(FileSystemType type) const251 AsyncFileUtil* FileSystemContext::GetAsyncFileUtil(
252 FileSystemType type) const {
253 FileSystemBackend* backend = GetFileSystemBackend(type);
254 if (!backend)
255 return NULL;
256 return backend->GetAsyncFileUtil(type);
257 }
258
259 CopyOrMoveFileValidatorFactory*
GetCopyOrMoveFileValidatorFactory(FileSystemType type,base::File::Error * error_code) const260 FileSystemContext::GetCopyOrMoveFileValidatorFactory(
261 FileSystemType type, base::File::Error* error_code) const {
262 DCHECK(error_code);
263 *error_code = base::File::FILE_OK;
264 FileSystemBackend* backend = GetFileSystemBackend(type);
265 if (!backend)
266 return NULL;
267 return backend->GetCopyOrMoveFileValidatorFactory(
268 type, error_code);
269 }
270
GetFileSystemBackend(FileSystemType type) const271 FileSystemBackend* FileSystemContext::GetFileSystemBackend(
272 FileSystemType type) const {
273 FileSystemBackendMap::const_iterator found = backend_map_.find(type);
274 if (found != backend_map_.end())
275 return found->second;
276 NOTREACHED() << "Unknown filesystem type: " << type;
277 return NULL;
278 }
279
GetWatcherManager(FileSystemType type) const280 WatcherManager* FileSystemContext::GetWatcherManager(
281 FileSystemType type) const {
282 FileSystemBackend* backend = GetFileSystemBackend(type);
283 if (!backend)
284 return NULL;
285 return backend->GetWatcherManager(type);
286 }
287
IsSandboxFileSystem(FileSystemType type) const288 bool FileSystemContext::IsSandboxFileSystem(FileSystemType type) const {
289 FileSystemBackendMap::const_iterator found = backend_map_.find(type);
290 return found != backend_map_.end() && found->second->GetQuotaUtil();
291 }
292
GetUpdateObservers(FileSystemType type) const293 const UpdateObserverList* FileSystemContext::GetUpdateObservers(
294 FileSystemType type) const {
295 FileSystemBackend* backend = GetFileSystemBackend(type);
296 return backend->GetUpdateObservers(type);
297 }
298
GetChangeObservers(FileSystemType type) const299 const ChangeObserverList* FileSystemContext::GetChangeObservers(
300 FileSystemType type) const {
301 FileSystemBackend* backend = GetFileSystemBackend(type);
302 return backend->GetChangeObservers(type);
303 }
304
GetAccessObservers(FileSystemType type) const305 const AccessObserverList* FileSystemContext::GetAccessObservers(
306 FileSystemType type) const {
307 FileSystemBackend* backend = GetFileSystemBackend(type);
308 return backend->GetAccessObservers(type);
309 }
310
GetFileSystemTypes(std::vector<FileSystemType> * types) const311 void FileSystemContext::GetFileSystemTypes(
312 std::vector<FileSystemType>* types) const {
313 types->clear();
314 for (FileSystemBackendMap::const_iterator iter = backend_map_.begin();
315 iter != backend_map_.end(); ++iter)
316 types->push_back(iter->first);
317 }
318
319 ExternalFileSystemBackend*
external_backend() const320 FileSystemContext::external_backend() const {
321 return static_cast<ExternalFileSystemBackend*>(
322 GetFileSystemBackend(kFileSystemTypeExternal));
323 }
324
OpenFileSystem(const GURL & origin_url,FileSystemType type,OpenFileSystemMode mode,const OpenFileSystemCallback & callback)325 void FileSystemContext::OpenFileSystem(
326 const GURL& origin_url,
327 FileSystemType type,
328 OpenFileSystemMode mode,
329 const OpenFileSystemCallback& callback) {
330 DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
331 DCHECK(!callback.is_null());
332
333 if (!FileSystemContext::IsSandboxFileSystem(type)) {
334 // Disallow opening a non-sandboxed filesystem.
335 callback.Run(GURL(), std::string(), base::File::FILE_ERROR_SECURITY);
336 return;
337 }
338
339 FileSystemBackend* backend = GetFileSystemBackend(type);
340 if (!backend) {
341 callback.Run(GURL(), std::string(), base::File::FILE_ERROR_SECURITY);
342 return;
343 }
344
345 backend->ResolveURL(
346 CreateCrackedFileSystemURL(origin_url, type, base::FilePath()),
347 mode,
348 callback);
349 }
350
ResolveURL(const FileSystemURL & url,const ResolveURLCallback & callback)351 void FileSystemContext::ResolveURL(
352 const FileSystemURL& url,
353 const ResolveURLCallback& callback) {
354 DCHECK(!callback.is_null());
355
356 // If not on IO thread, forward before passing the task to the backend.
357 if (!io_task_runner_->RunsTasksOnCurrentThread()) {
358 ResolveURLCallback relay_callback =
359 base::Bind(&RelayResolveURLCallback,
360 base::MessageLoopProxy::current(), callback);
361 io_task_runner_->PostTask(
362 FROM_HERE,
363 base::Bind(&FileSystemContext::ResolveURL, this, url, relay_callback));
364 return;
365 }
366
367 FileSystemBackend* backend = GetFileSystemBackend(url.type());
368 if (!backend) {
369 callback.Run(base::File::FILE_ERROR_SECURITY,
370 FileSystemInfo(), base::FilePath(),
371 FileSystemContext::RESOLVED_ENTRY_NOT_FOUND);
372 return;
373 }
374
375 backend->ResolveURL(
376 url,
377 OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT,
378 base::Bind(&FileSystemContext::DidOpenFileSystemForResolveURL,
379 this,
380 url,
381 callback));
382 }
383
AttemptAutoMountForURLRequest(const net::URLRequest * url_request,const std::string & storage_domain,const StatusCallback & callback)384 void FileSystemContext::AttemptAutoMountForURLRequest(
385 const net::URLRequest* url_request,
386 const std::string& storage_domain,
387 const StatusCallback& callback) {
388 FileSystemURL filesystem_url(url_request->url());
389 if (filesystem_url.type() == kFileSystemTypeExternal) {
390 for (size_t i = 0; i < auto_mount_handlers_.size(); i++) {
391 if (auto_mount_handlers_[i].Run(url_request, filesystem_url,
392 storage_domain, callback)) {
393 return;
394 }
395 }
396 }
397 callback.Run(base::File::FILE_ERROR_NOT_FOUND);
398 }
399
DeleteFileSystem(const GURL & origin_url,FileSystemType type,const StatusCallback & callback)400 void FileSystemContext::DeleteFileSystem(
401 const GURL& origin_url,
402 FileSystemType type,
403 const StatusCallback& callback) {
404 DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
405 DCHECK(origin_url == origin_url.GetOrigin());
406 DCHECK(!callback.is_null());
407
408 FileSystemBackend* backend = GetFileSystemBackend(type);
409 if (!backend) {
410 callback.Run(base::File::FILE_ERROR_SECURITY);
411 return;
412 }
413 if (!backend->GetQuotaUtil()) {
414 callback.Run(base::File::FILE_ERROR_INVALID_OPERATION);
415 return;
416 }
417
418 base::PostTaskAndReplyWithResult(
419 default_file_task_runner(),
420 FROM_HERE,
421 // It is safe to pass Unretained(quota_util) since context owns it.
422 base::Bind(&FileSystemQuotaUtil::DeleteOriginDataOnFileTaskRunner,
423 base::Unretained(backend->GetQuotaUtil()),
424 make_scoped_refptr(this),
425 base::Unretained(quota_manager_proxy()),
426 origin_url,
427 type),
428 callback);
429 }
430
CreateFileStreamReader(const FileSystemURL & url,int64 offset,int64 max_bytes_to_read,const base::Time & expected_modification_time)431 scoped_ptr<storage::FileStreamReader> FileSystemContext::CreateFileStreamReader(
432 const FileSystemURL& url,
433 int64 offset,
434 int64 max_bytes_to_read,
435 const base::Time& expected_modification_time) {
436 if (!url.is_valid())
437 return scoped_ptr<storage::FileStreamReader>();
438 FileSystemBackend* backend = GetFileSystemBackend(url.type());
439 if (!backend)
440 return scoped_ptr<storage::FileStreamReader>();
441 return backend->CreateFileStreamReader(
442 url, offset, max_bytes_to_read, expected_modification_time, this);
443 }
444
CreateFileStreamWriter(const FileSystemURL & url,int64 offset)445 scoped_ptr<FileStreamWriter> FileSystemContext::CreateFileStreamWriter(
446 const FileSystemURL& url,
447 int64 offset) {
448 if (!url.is_valid())
449 return scoped_ptr<FileStreamWriter>();
450 FileSystemBackend* backend = GetFileSystemBackend(url.type());
451 if (!backend)
452 return scoped_ptr<FileStreamWriter>();
453 return backend->CreateFileStreamWriter(url, offset, this);
454 }
455
456 scoped_ptr<FileSystemOperationRunner>
CreateFileSystemOperationRunner()457 FileSystemContext::CreateFileSystemOperationRunner() {
458 return make_scoped_ptr(new FileSystemOperationRunner(this));
459 }
460
CrackURL(const GURL & url) const461 FileSystemURL FileSystemContext::CrackURL(const GURL& url) const {
462 return CrackFileSystemURL(FileSystemURL(url));
463 }
464
CreateCrackedFileSystemURL(const GURL & origin,FileSystemType type,const base::FilePath & path) const465 FileSystemURL FileSystemContext::CreateCrackedFileSystemURL(
466 const GURL& origin,
467 FileSystemType type,
468 const base::FilePath& path) const {
469 return CrackFileSystemURL(FileSystemURL(origin, type, path));
470 }
471
472 #if defined(OS_CHROMEOS)
EnableTemporaryFileSystemInIncognito()473 void FileSystemContext::EnableTemporaryFileSystemInIncognito() {
474 sandbox_backend_->set_enable_temporary_file_system_in_incognito(true);
475 }
476 #endif
477
CanServeURLRequest(const FileSystemURL & url) const478 bool FileSystemContext::CanServeURLRequest(const FileSystemURL& url) const {
479 // We never support accessing files in isolated filesystems via an URL.
480 if (url.mount_type() == kFileSystemTypeIsolated)
481 return false;
482 #if defined(OS_CHROMEOS)
483 if (url.type() == kFileSystemTypeTemporary &&
484 sandbox_backend_->enable_temporary_file_system_in_incognito()) {
485 return true;
486 }
487 #endif
488 return !is_incognito_ || !FileSystemContext::IsSandboxFileSystem(url.type());
489 }
490
ShouldFlushOnWriteCompletion(FileSystemType type) const491 bool FileSystemContext::ShouldFlushOnWriteCompletion(
492 FileSystemType type) const {
493 if (IsSandboxFileSystem(type)) {
494 // Disable Flush() for each write operation on SandboxFileSystems since it
495 // hurts the performance, assuming the FileSystems are stored in a local
496 // disk, we don't need to keep calling fsync() for it.
497 // On the other hand, other FileSystems that may stored on a removable media
498 // should be Flush()ed as soon as a write operation is completed, so that
499 // written data is saved over sudden media removal.
500 return false;
501 }
502 return true;
503 }
504
OpenPluginPrivateFileSystem(const GURL & origin_url,FileSystemType type,const std::string & filesystem_id,const std::string & plugin_id,OpenFileSystemMode mode,const StatusCallback & callback)505 void FileSystemContext::OpenPluginPrivateFileSystem(
506 const GURL& origin_url,
507 FileSystemType type,
508 const std::string& filesystem_id,
509 const std::string& plugin_id,
510 OpenFileSystemMode mode,
511 const StatusCallback& callback) {
512 DCHECK(plugin_private_backend_);
513 plugin_private_backend_->OpenPrivateFileSystem(
514 origin_url, type, filesystem_id, plugin_id, mode, callback);
515 }
516
~FileSystemContext()517 FileSystemContext::~FileSystemContext() {
518 }
519
DeleteOnCorrectThread() const520 void FileSystemContext::DeleteOnCorrectThread() const {
521 if (!io_task_runner_->RunsTasksOnCurrentThread() &&
522 io_task_runner_->DeleteSoon(FROM_HERE, this)) {
523 return;
524 }
525 delete this;
526 }
527
CreateFileSystemOperation(const FileSystemURL & url,base::File::Error * error_code)528 FileSystemOperation* FileSystemContext::CreateFileSystemOperation(
529 const FileSystemURL& url, base::File::Error* error_code) {
530 if (!url.is_valid()) {
531 if (error_code)
532 *error_code = base::File::FILE_ERROR_INVALID_URL;
533 return NULL;
534 }
535
536 FileSystemBackend* backend = GetFileSystemBackend(url.type());
537 if (!backend) {
538 if (error_code)
539 *error_code = base::File::FILE_ERROR_FAILED;
540 return NULL;
541 }
542
543 base::File::Error fs_error = base::File::FILE_OK;
544 FileSystemOperation* operation =
545 backend->CreateFileSystemOperation(url, this, &fs_error);
546
547 if (error_code)
548 *error_code = fs_error;
549 return operation;
550 }
551
CrackFileSystemURL(const FileSystemURL & url) const552 FileSystemURL FileSystemContext::CrackFileSystemURL(
553 const FileSystemURL& url) const {
554 if (!url.is_valid())
555 return FileSystemURL();
556
557 // The returned value in case there is no crackers which can crack the url.
558 // This is valid situation for non isolated/external file systems.
559 FileSystemURL current = url;
560
561 // File system may be mounted multiple times (e.g., an isolated filesystem on
562 // top of an external filesystem). Hence cracking needs to be iterated.
563 for (;;) {
564 FileSystemURL cracked = current;
565 for (size_t i = 0; i < url_crackers_.size(); ++i) {
566 if (!url_crackers_[i]->HandlesFileSystemMountType(current.type()))
567 continue;
568 cracked = url_crackers_[i]->CrackFileSystemURL(current);
569 if (cracked.is_valid())
570 break;
571 }
572 if (cracked == current)
573 break;
574 current = cracked;
575 }
576 return current;
577 }
578
RegisterBackend(FileSystemBackend * backend)579 void FileSystemContext::RegisterBackend(FileSystemBackend* backend) {
580 const FileSystemType mount_types[] = {
581 kFileSystemTypeTemporary,
582 kFileSystemTypePersistent,
583 kFileSystemTypeIsolated,
584 kFileSystemTypeExternal,
585 };
586 // Register file system backends for public mount types.
587 for (size_t j = 0; j < ARRAYSIZE_UNSAFE(mount_types); ++j) {
588 if (backend->CanHandleType(mount_types[j])) {
589 const bool inserted = backend_map_.insert(
590 std::make_pair(mount_types[j], backend)).second;
591 DCHECK(inserted);
592 }
593 }
594 // Register file system backends for internal types.
595 for (int t = kFileSystemInternalTypeEnumStart + 1;
596 t < kFileSystemInternalTypeEnumEnd; ++t) {
597 FileSystemType type = static_cast<FileSystemType>(t);
598 if (backend->CanHandleType(type)) {
599 const bool inserted = backend_map_.insert(
600 std::make_pair(type, backend)).second;
601 DCHECK(inserted);
602 }
603 }
604 }
605
DidOpenFileSystemForResolveURL(const FileSystemURL & url,const FileSystemContext::ResolveURLCallback & callback,const GURL & filesystem_root,const std::string & filesystem_name,base::File::Error error)606 void FileSystemContext::DidOpenFileSystemForResolveURL(
607 const FileSystemURL& url,
608 const FileSystemContext::ResolveURLCallback& callback,
609 const GURL& filesystem_root,
610 const std::string& filesystem_name,
611 base::File::Error error) {
612 DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
613
614 if (error != base::File::FILE_OK) {
615 callback.Run(error, FileSystemInfo(), base::FilePath(),
616 FileSystemContext::RESOLVED_ENTRY_NOT_FOUND);
617 return;
618 }
619
620 storage::FileSystemInfo info(
621 filesystem_name, filesystem_root, url.mount_type());
622
623 // Extract the virtual path not containing a filesystem type part from |url|.
624 base::FilePath parent = CrackURL(filesystem_root).virtual_path();
625 base::FilePath child = url.virtual_path();
626 base::FilePath path;
627
628 if (parent.empty()) {
629 path = child;
630 } else if (parent != child) {
631 bool result = parent.AppendRelativePath(child, &path);
632 DCHECK(result);
633 }
634
635 operation_runner()->GetMetadata(
636 url, base::Bind(&DidGetMetadataForResolveURL, path, callback, info));
637 }
638
639 } // namespace storage
640