diff options
Diffstat (limited to 'chromium/webkit/browser/fileapi/external_mount_points.cc')
-rw-r--r-- | chromium/webkit/browser/fileapi/external_mount_points.cc | 335 |
1 files changed, 335 insertions, 0 deletions
diff --git a/chromium/webkit/browser/fileapi/external_mount_points.cc b/chromium/webkit/browser/fileapi/external_mount_points.cc new file mode 100644 index 00000000000..a3ecd4b6678 --- /dev/null +++ b/chromium/webkit/browser/fileapi/external_mount_points.cc @@ -0,0 +1,335 @@ +// 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/browser/fileapi/external_mount_points.h" + +#include "base/files/file_path.h" +#include "base/lazy_instance.h" +#include "base/path_service.h" +#include "base/stl_util.h" +#include "webkit/browser/fileapi/file_system_url.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/"). +base::FilePath NormalizeFilePath(const base::FilePath& path) { + if (path.empty()) + return path; + + base::FilePath::StringType path_str = path.StripTrailingSeparators().value(); + if (!base::FilePath::IsSeparator(path_str[path_str.length() - 1])) + path_str.append(FILE_PATH_LITERAL("/")); + + return base::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()) { + } + + ~SystemMountPointsLazyWrapper() {} + + fileapi::ExternalMountPoints* get() { + return system_mount_points_.get(); + } + + private: + 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 base::FilePath& path) + : type_(type), path_(path.StripTrailingSeparators()) {} + ~Instance() {} + + FileSystemType type() const { return type_; } + const base::FilePath& path() const { return path_; } + + private: + const FileSystemType type_; + const base::FilePath path_; + + DISALLOW_COPY_AND_ASSIGN(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 base::FilePath& path_in) { + base::AutoLock locker(lock_); + + base::FilePath path = NormalizeFilePath(path_in); + if (!ValidateNewMountPoint(mount_name, path)) + return false; + + instance_map_[mount_name] = new Instance(type, path); + if (!path.empty()) + path_to_name_map_.insert(std::make_pair(path, mount_name)); + return true; +} + +bool ExternalMountPoints::HandlesFileSystemMountType( + FileSystemType type) const { + return type == kFileSystemTypeExternal || + type == kFileSystemTypeNativeForPlatformApp; +} + +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, base::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 base::FilePath& virtual_path, + std::string* mount_name, + FileSystemType* type, + base::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<base::FilePath::StringType> components; + virtual_path.GetComponents(&components); + if (components.size() < 1) + return false; + + std::vector<base::FilePath::StringType>::iterator component_iter = + components.begin(); + std::string maybe_mount_name = + base::FilePath(*component_iter++).MaybeAsASCII(); + if (maybe_mount_name.empty()) + return false; + + base::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; +} + +FileSystemURL ExternalMountPoints::CrackURL(const GURL& url) const { + FileSystemURL filesystem_url = FileSystemURL(url); + if (!filesystem_url.is_valid()) + return FileSystemURL(); + return CrackFileSystemURL(filesystem_url); +} + +FileSystemURL ExternalMountPoints::CreateCrackedFileSystemURL( + const GURL& origin, + FileSystemType type, + const base::FilePath& path) const { + return CrackFileSystemURL(FileSystemURL(origin, type, path)); +} + +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 base::FilePath& path_in, + base::FilePath* virtual_path) const { + DCHECK(virtual_path); + + base::AutoLock locker(lock_); + + base::FilePath path = NormalizeFilePath(path_in); + std::map<base::FilePath, std::string>::const_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); +} + +base::FilePath ExternalMountPoints::CreateVirtualRootPath( + const std::string& mount_name) const { + return base::FilePath().AppendASCII(mount_name); +} + +FileSystemURL ExternalMountPoints::CreateExternalFileSystemURL( + const GURL& origin, + const std::string& mount_name, + const base::FilePath& path) const { + return CreateCrackedFileSystemURL( + origin, + fileapi::kFileSystemTypeExternal, + // Avoid using FilePath::Append as path may be an absolute path. + base::FilePath( + CreateVirtualRootPath(mount_name).value() + + base::FilePath::kSeparators[0] + path.value())); +} + +ExternalMountPoints::ExternalMountPoints() {} + +ExternalMountPoints::~ExternalMountPoints() { + STLDeleteContainerPairSecondPointers(instance_map_.begin(), + instance_map_.end()); +} + +FileSystemURL ExternalMountPoints::CrackFileSystemURL( + const FileSystemURL& url) const { + if (!HandlesFileSystemMountType(url.type())) + return FileSystemURL(); + + base::FilePath virtual_path = url.path(); + if (url.type() == kFileSystemTypeNativeForPlatformApp) { +#if defined(OS_CHROMEOS) + // On Chrome OS, find a mount point and virtual path for the external fs. + if (!GetVirtualPath(url.path(), &virtual_path)) + return FileSystemURL(); +#else + // On other OS, it is simply a native local path. + return FileSystemURL( + url.origin(), url.mount_type(), url.virtual_path(), + url.mount_filesystem_id(), kFileSystemTypeNativeLocal, + url.path(), url.filesystem_id()); +#endif + } + + std::string mount_name; + FileSystemType cracked_type; + base::FilePath cracked_path; + + if (!CrackVirtualPath(virtual_path, &mount_name, &cracked_type, + &cracked_path)) { + return FileSystemURL(); + } + + return FileSystemURL( + url.origin(), url.mount_type(), url.virtual_path(), + !url.filesystem_id().empty() ? url.filesystem_id() : mount_name, + cracked_type, cracked_path, mount_name); +} + +bool ExternalMountPoints::ValidateNewMountPoint(const std::string& mount_name, + const base::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<base::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<base::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 base::FilePath& path) + : mount_name_(mount_name) { + ExternalMountPoints::GetSystemInstance()->RegisterFileSystem( + mount_name, type, path); +} + +base::FilePath ScopedExternalFileSystem::GetVirtualRootPath() const { + return ExternalMountPoints::GetSystemInstance()-> + CreateVirtualRootPath(mount_name_); +} + +ScopedExternalFileSystem::~ScopedExternalFileSystem() { + ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(mount_name_); +} + +} // namespace fileapi |