| Index: webkit/fileapi/external_mount_points.cc
|
| diff --git a/webkit/fileapi/external_mount_points.cc b/webkit/fileapi/external_mount_points.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..9abba4218cfe17fb4bcf2609a2ea7e4ca6690cba
|
| --- /dev/null
|
| +++ b/webkit/fileapi/external_mount_points.cc
|
| @@ -0,0 +1,331 @@
|
| +// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "webkit/fileapi/external_mount_points.h"
|
| +
|
| +#include "base/file_path.h"
|
| +#include "base/lazy_instance.h"
|
| +#include "base/path_service.h"
|
| +#include "base/stl_util.h"
|
| +#include "webkit/fileapi/remote_file_system_proxy.h"
|
| +
|
| +namespace {
|
| +
|
| +// Normalizes file path so it has normalized separators and ends with exactly
|
| +// one separator. Paths have to be normalized this way for use in
|
| +// GetVirtualPath method. Separators cannot be completely stripped, or
|
| +// GetVirtualPath could not working in some edge cases.
|
| +// For example, /a/b/c(1)/d would be erroneously resolved as c/d if the
|
| +// following mount points were registered: "/a/b/c", "/a/b/c(1)". (Note:
|
| +// "/a/b/c" < "/a/b/c(1)" < "/a/b/c/").
|
| +FilePath NormalizeFilePath(const FilePath& path) {
|
| + if (path.empty())
|
| + return path;
|
| +
|
| + FilePath::StringType path_str = path.StripTrailingSeparators().value();
|
| + if (!FilePath::IsSeparator(path_str[path_str.length() - 1]))
|
| + path_str.append(FILE_PATH_LITERAL("/"));
|
| +
|
| + return FilePath(path_str).NormalizePathSeparators();
|
| +}
|
| +
|
| +// Wrapper around ref-counted ExternalMountPoints that will be used to lazily
|
| +// create and initialize LazyInstance system ExternalMountPoints.
|
| +class SystemMountPointsLazyWrapper {
|
| + public:
|
| + SystemMountPointsLazyWrapper()
|
| + : system_mount_points_(fileapi::ExternalMountPoints::CreateRefCounted()) {
|
| + RegisterDefaultMountPoints();
|
| + }
|
| +
|
| + ~SystemMountPointsLazyWrapper() {}
|
| +
|
| + fileapi::ExternalMountPoints* get() {
|
| + return system_mount_points_.get();
|
| + }
|
| +
|
| + private:
|
| + void RegisterDefaultMountPoints() {
|
| +#if defined(OS_CHROMEOS)
|
| + // Add default system mount points.
|
| + system_mount_points_->RegisterFileSystem(
|
| + "archive",
|
| + fileapi::kFileSystemTypeNativeLocal,
|
| + FilePath(FILE_PATH_LITERAL("/media/archive")));
|
| + system_mount_points_->RegisterFileSystem(
|
| + "removable",
|
| + fileapi::kFileSystemTypeNativeLocal,
|
| + FilePath(FILE_PATH_LITERAL("/media/removable")));
|
| + system_mount_points_->RegisterFileSystem(
|
| + "oem",
|
| + fileapi::kFileSystemTypeRestrictedNativeLocal,
|
| + FilePath(FILE_PATH_LITERAL("/usr/share/oem")));
|
| +
|
| + // TODO(tbarzic): Move this out of here.
|
| + FilePath home_path;
|
| + if (PathService::Get(base::DIR_HOME, &home_path)) {
|
| + system_mount_points_->RegisterFileSystem(
|
| + "Downloads",
|
| + fileapi::kFileSystemTypeNativeLocal,
|
| + home_path.AppendASCII("Downloads"));
|
| + }
|
| +#endif // defined(OS_CHROMEOS)
|
| + }
|
| +
|
| + scoped_refptr<fileapi::ExternalMountPoints> system_mount_points_;
|
| +};
|
| +
|
| +base::LazyInstance<SystemMountPointsLazyWrapper>::Leaky
|
| + g_external_mount_points = LAZY_INSTANCE_INITIALIZER;
|
| +
|
| +} // namespace
|
| +
|
| +namespace fileapi {
|
| +
|
| +class ExternalMountPoints::Instance {
|
| + public:
|
| + Instance(FileSystemType type,
|
| + const FilePath& path,
|
| + RemoteFileSystemProxyInterface* remote_proxy);
|
| +
|
| + ~Instance();
|
| +
|
| + FileSystemType type() const { return type_; }
|
| + const FilePath& path() const { return path_; }
|
| + RemoteFileSystemProxyInterface* remote_proxy() const {
|
| + return remote_proxy_.get();
|
| + }
|
| +
|
| + private:
|
| + const FileSystemType type_;
|
| + const FilePath path_;
|
| +
|
| + // For file systems that have a remote file system proxy.
|
| + scoped_refptr<RemoteFileSystemProxyInterface> remote_proxy_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(Instance);
|
| +};
|
| +
|
| +ExternalMountPoints::Instance::Instance(FileSystemType type,
|
| + const FilePath& path,
|
| + RemoteFileSystemProxyInterface* proxy)
|
| + : type_(type),
|
| + path_(path.StripTrailingSeparators()),
|
| + remote_proxy_(proxy) {
|
| + DCHECK(!proxy || (kFileSystemTypeDrive == type_));
|
| +}
|
| +
|
| +ExternalMountPoints::Instance::~Instance() {}
|
| +
|
| +//--------------------------------------------------------------------------
|
| +
|
| +// static
|
| +ExternalMountPoints* ExternalMountPoints::GetSystemInstance() {
|
| + return g_external_mount_points.Pointer()->get();
|
| +}
|
| +
|
| +// static
|
| +scoped_refptr<ExternalMountPoints> ExternalMountPoints::CreateRefCounted() {
|
| + return new ExternalMountPoints();
|
| +}
|
| +
|
| +bool ExternalMountPoints::RegisterFileSystem(
|
| + const std::string& mount_name,
|
| + FileSystemType type,
|
| + const FilePath& path) {
|
| + return RegisterRemoteFileSystem(mount_name, type, NULL, path);
|
| +}
|
| +
|
| +bool ExternalMountPoints::RegisterRemoteFileSystem(
|
| + const std::string& mount_name,
|
| + FileSystemType type,
|
| + RemoteFileSystemProxyInterface* remote_proxy,
|
| + const FilePath& path_in) {
|
| + base::AutoLock locker(lock_);
|
| +
|
| + FilePath path = NormalizeFilePath(path_in);
|
| + if (!ValidateNewMountPoint(mount_name, path))
|
| + return false;
|
| +
|
| + instance_map_[mount_name] = new Instance(type, path, remote_proxy);
|
| + if (!path.empty())
|
| + path_to_name_map_.insert(std::make_pair(path, mount_name));
|
| + return true;
|
| +}
|
| +
|
| +bool ExternalMountPoints::RevokeFileSystem(const std::string& mount_name) {
|
| + base::AutoLock locker(lock_);
|
| + NameToInstance::iterator found = instance_map_.find(mount_name);
|
| + if (found == instance_map_.end())
|
| + return false;
|
| + Instance* instance = found->second;
|
| + path_to_name_map_.erase(NormalizeFilePath(instance->path()));
|
| + delete found->second;
|
| + instance_map_.erase(found);
|
| + return true;
|
| +}
|
| +
|
| +bool ExternalMountPoints::GetRegisteredPath(
|
| + const std::string& filesystem_id, FilePath* path) const {
|
| + DCHECK(path);
|
| + base::AutoLock locker(lock_);
|
| + NameToInstance::const_iterator found = instance_map_.find(filesystem_id);
|
| + if (found == instance_map_.end())
|
| + return false;
|
| + *path = found->second->path();
|
| + return true;
|
| +}
|
| +
|
| +bool ExternalMountPoints::CrackVirtualPath(const FilePath& virtual_path,
|
| + std::string* mount_name,
|
| + FileSystemType* type,
|
| + FilePath* path) const {
|
| + DCHECK(mount_name);
|
| + DCHECK(path);
|
| +
|
| + // The path should not contain any '..' references.
|
| + if (virtual_path.ReferencesParent())
|
| + return false;
|
| +
|
| + // The virtual_path should comprise of <mount_name> and <relative_path> parts.
|
| + std::vector<FilePath::StringType> components;
|
| + virtual_path.GetComponents(&components);
|
| + if (components.size() < 1)
|
| + return false;
|
| +
|
| + std::vector<FilePath::StringType>::iterator component_iter =
|
| + components.begin();
|
| + std::string maybe_mount_name = FilePath(*component_iter++).MaybeAsASCII();
|
| + if (maybe_mount_name.empty())
|
| + return false;
|
| +
|
| + FilePath cracked_path;
|
| + {
|
| + base::AutoLock locker(lock_);
|
| + NameToInstance::const_iterator found_instance =
|
| + instance_map_.find(maybe_mount_name);
|
| + if (found_instance == instance_map_.end())
|
| + return false;
|
| +
|
| + *mount_name = maybe_mount_name;
|
| + const Instance* instance = found_instance->second;
|
| + if (type)
|
| + *type = instance->type();
|
| + cracked_path = instance->path();
|
| + }
|
| +
|
| + for (; component_iter != components.end(); ++component_iter)
|
| + cracked_path = cracked_path.Append(*component_iter);
|
| + *path = cracked_path;
|
| + return true;
|
| +}
|
| +
|
| +RemoteFileSystemProxyInterface* ExternalMountPoints::GetRemoteFileSystemProxy(
|
| + const std::string& mount_name) const {
|
| + base::AutoLock locker(lock_);
|
| + NameToInstance::const_iterator found = instance_map_.find(mount_name);
|
| + if (found == instance_map_.end())
|
| + return NULL;
|
| + return found->second->remote_proxy();
|
| +}
|
| +
|
| +void ExternalMountPoints::AddMountPointInfosTo(
|
| + std::vector<MountPointInfo>* mount_points) const {
|
| + base::AutoLock locker(lock_);
|
| + DCHECK(mount_points);
|
| + for (NameToInstance::const_iterator iter = instance_map_.begin();
|
| + iter != instance_map_.end(); ++iter) {
|
| + mount_points->push_back(MountPointInfo(iter->first, iter->second->path()));
|
| + }
|
| +}
|
| +
|
| +bool ExternalMountPoints::GetVirtualPath(const FilePath& path_in,
|
| + FilePath* virtual_path) {
|
| + DCHECK(virtual_path);
|
| +
|
| + base::AutoLock locker(lock_);
|
| +
|
| + FilePath path = NormalizeFilePath(path_in);
|
| + std::map<FilePath, std::string>::reverse_iterator iter(
|
| + path_to_name_map_.upper_bound(path));
|
| + if (iter == path_to_name_map_.rend())
|
| + return false;
|
| +
|
| + *virtual_path = CreateVirtualRootPath(iter->second);
|
| + if (iter->first == path)
|
| + return true;
|
| + return iter->first.AppendRelativePath(path, virtual_path);
|
| +}
|
| +
|
| +FilePath ExternalMountPoints::CreateVirtualRootPath(
|
| + const std::string& mount_name) const {
|
| + return FilePath().AppendASCII(mount_name);
|
| +}
|
| +
|
| +ExternalMountPoints::ExternalMountPoints() {}
|
| +
|
| +ExternalMountPoints::~ExternalMountPoints() {
|
| + STLDeleteContainerPairSecondPointers(instance_map_.begin(),
|
| + instance_map_.end());
|
| +}
|
| +
|
| +bool ExternalMountPoints::ValidateNewMountPoint(const std::string& mount_name,
|
| + const FilePath& path) {
|
| + lock_.AssertAcquired();
|
| +
|
| + // Mount name must not be empty.
|
| + if (mount_name.empty())
|
| + return false;
|
| +
|
| + // Verify there is no registered mount point with the same name.
|
| + NameToInstance::iterator found = instance_map_.find(mount_name);
|
| + if (found != instance_map_.end())
|
| + return false;
|
| +
|
| + // Allow empty paths.
|
| + if (path.empty())
|
| + return true;
|
| +
|
| + // Verify path is legal.
|
| + if (path.ReferencesParent() || !path.IsAbsolute())
|
| + return false;
|
| +
|
| + // Check there the new path does not overlap with one of the existing ones.
|
| + std::map<FilePath, std::string>::reverse_iterator potential_parent(
|
| + path_to_name_map_.upper_bound(path));
|
| + if (potential_parent != path_to_name_map_.rend()) {
|
| + if (potential_parent->first == path ||
|
| + potential_parent->first.IsParent(path)) {
|
| + return false;
|
| + }
|
| + }
|
| +
|
| + std::map<FilePath, std::string>::iterator potential_child =
|
| + path_to_name_map_.upper_bound(path);
|
| + if (potential_child == path_to_name_map_.end())
|
| + return true;
|
| + return !(potential_child->first == path) &&
|
| + !path.IsParent(potential_child->first);
|
| +}
|
| +
|
| +ScopedExternalFileSystem::ScopedExternalFileSystem(
|
| + const std::string& mount_name,
|
| + FileSystemType type,
|
| + const FilePath& path)
|
| + : mount_name_(mount_name) {
|
| + ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
|
| + mount_name, type, path);
|
| +}
|
| +
|
| +FilePath ScopedExternalFileSystem::GetVirtualRootPath() const {
|
| + return ExternalMountPoints::GetSystemInstance()->
|
| + CreateVirtualRootPath(mount_name_);
|
| +}
|
| +
|
| +ScopedExternalFileSystem::~ScopedExternalFileSystem() {
|
| + ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(mount_name_);
|
| +}
|
| +
|
| +} // namespace fileapi
|
| +
|
|
|