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