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