diff options
author | tbarzic@chromium.org <tbarzic@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-01-18 03:12:54 +0000 |
---|---|---|
committer | tbarzic@chromium.org <tbarzic@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-01-18 03:12:54 +0000 |
commit | 9d5d6986dfaed15ef3719250fbf7fb8347bebd80 (patch) | |
tree | a472d1593efc197e15d9474d26e93530b939ec7f /webkit/fileapi | |
parent | d22af016d12e789ac7c5976c300c819ebe4340b3 (diff) | |
download | chromium_src-9d5d6986dfaed15ef3719250fbf7fb8347bebd80.zip chromium_src-9d5d6986dfaed15ef3719250fbf7fb8347bebd80.tar.gz chromium_src-9d5d6986dfaed15ef3719250fbf7fb8347bebd80.tar.bz2 |
Extract external file systems handling from isolated context.
Move mount point info bookeeping from CrosMountPointProvider to ExternalMountPoints.
Add some tests for CrosMountPointProvider.
BUG=158837
TEST=content_unittests:CrosMountPointProvider*
TBR=benwells@chromium.org
Review URL: https://chromiumcodereview.appspot.com/11648027
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@177578 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/fileapi')
-rw-r--r-- | webkit/fileapi/external_mount_points.cc | 331 | ||||
-rw-r--r-- | webkit/fileapi/external_mount_points.h | 155 | ||||
-rw-r--r-- | webkit/fileapi/external_mount_points_unittest.cc | 227 | ||||
-rw-r--r-- | webkit/fileapi/file_system_context.cc | 8 | ||||
-rw-r--r-- | webkit/fileapi/file_system_mount_point_provider.h | 8 | ||||
-rw-r--r-- | webkit/fileapi/file_system_url.cc | 7 | ||||
-rw-r--r-- | webkit/fileapi/file_system_url_unittest.cc | 13 | ||||
-rw-r--r-- | webkit/fileapi/isolated_context.cc | 235 | ||||
-rw-r--r-- | webkit/fileapi/isolated_context.h | 137 | ||||
-rw-r--r-- | webkit/fileapi/isolated_context_unittest.cc | 12 | ||||
-rw-r--r-- | webkit/fileapi/isolated_file_util.cc | 2 | ||||
-rw-r--r-- | webkit/fileapi/mount_points.cc | 15 | ||||
-rw-r--r-- | webkit/fileapi/mount_points.h | 77 | ||||
-rw-r--r-- | webkit/fileapi/remote_file_system_proxy.h | 122 | ||||
-rw-r--r-- | webkit/fileapi/syncable/canned_syncable_file_system.cc | 1 | ||||
-rw-r--r-- | webkit/fileapi/syncable/syncable_file_system_util.cc | 7 | ||||
-rw-r--r-- | webkit/fileapi/syncable/syncable_file_system_util_unittest.cc | 2 | ||||
-rw-r--r-- | webkit/fileapi/webkit_fileapi.gypi | 6 |
18 files changed, 1078 insertions, 287 deletions
diff --git a/webkit/fileapi/external_mount_points.cc b/webkit/fileapi/external_mount_points.cc new file mode 100644 index 0000000..9abba42 --- /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 + diff --git a/webkit/fileapi/external_mount_points.h b/webkit/fileapi/external_mount_points.h new file mode 100644 index 0000000..fe8d4d0 --- /dev/null +++ b/webkit/fileapi/external_mount_points.h @@ -0,0 +1,155 @@ +// 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. + +#ifndef WEBKIT_FILEAPI_EXTERNAL_MOUNT_POINTS_H_ +#define WEBKIT_FILEAPI_EXTERNAL_MOUNT_POINTS_H_ + +#include <map> +#include <string> +#include <vector> + +#include "base/memory/ref_counted.h" +#include "base/synchronization/lock.h" +#include "webkit/fileapi/file_system_types.h" +#include "webkit/fileapi/mount_points.h" +#include "webkit/storage/webkit_storage_export.h" + +class FilePath; + +namespace fileapi { +class RemoteFileSystemProxyInterface; +} + +namespace fileapi { + +// Manages external filesystem namespaces that are identified by 'mount name' +// and are persisted until RevokeFileSystem is called. +// Files in an external filesystem are identified by a filesystem URL like: +// +// filesystem:<origin>/external/<mount_name>/relative/path +// +class WEBKIT_STORAGE_EXPORT ExternalMountPoints + : public base::RefCountedThreadSafe<ExternalMountPoints>, + public MountPoints { + public: + static ExternalMountPoints* GetSystemInstance(); + static scoped_refptr<ExternalMountPoints> CreateRefCounted(); + + // Registers a new named external filesystem. + // The |path| is registered as the root path of the mount point which + // is identified by a URL "filesystem:.../external/mount_name". + // + // For example, if the path "/media/removable" is registered with + // the mount_name "removable", a filesystem URL like + // "filesystem:.../external/removable/a/b" will be resolved as + // "/media/removable/a/b". + // + // The |mount_name| should NOT contain a path separator '/'. + // Returns false if the given name is already registered. + // + // Overlapping mount points in a single MountPoints instance are not allowed. + // Adding mount point whose path overlaps with an existing mount point will + // fail. + // + // If not empty, |path| must be absolute. It is allowed for the path to be + // empty, but |GetVirtualPath| will not work for those mount points. + // + // An external file system registered by this method can be revoked + // by calling RevokeFileSystem with |mount_name|. + bool RegisterFileSystem(const std::string& mount_name, + FileSystemType type, + const FilePath& path); + + // Same as |RegisterExternalFileSystem|, but also registers a remote file + // system proxy for the file system. + bool RegisterRemoteFileSystem(const std::string& mount_name, + FileSystemType type, + RemoteFileSystemProxyInterface* remote_proxy, + const FilePath& path); + + // MountPoints overrides. + virtual bool RevokeFileSystem(const std::string& mount_name) OVERRIDE; + virtual bool GetRegisteredPath(const std::string& mount_name, + FilePath* path) const OVERRIDE; + virtual bool CrackVirtualPath(const FilePath& virtual_path, + std::string* mount_name, + FileSystemType* type, + FilePath* path) const OVERRIDE; + + // Retrieves the remote file system proxy for the registered file system. + // Returns NULL if there is no file system with the given name, or if the file + // system does not have a remote file system proxy. + RemoteFileSystemProxyInterface* GetRemoteFileSystemProxy( + const std::string& mount_name) const; + + // Returns a list of registered MountPointInfos (of <mount_name, path>). + void AddMountPointInfosTo(std::vector<MountPointInfo>* mount_points) const; + + // Converts a path on a registered file system to virtual path relative to the + // file system root. E.g. if 'Downloads' file system is mapped to + // '/usr/local/home/Downloads', and |absolute| path is set to + // '/usr/local/home/Downloads/foo', the method will set |virtual_path| to + // 'Downloads/foo'. + // Returns false if the path cannot be resolved (e.g. if the path is not + // part of any registered filesystem). + // + // Returned virtual_path will have normalized path separators. + bool GetVirtualPath(const FilePath& absolute_path, FilePath* virtual_path); + + // Returns the virtual root path that looks like /<mount_name>. + FilePath CreateVirtualRootPath(const std::string& mount_name) const; + + private: + friend class base::RefCountedThreadSafe<ExternalMountPoints>; + + // Represents each file system instance (defined in the .cc). + class Instance; + + typedef std::map<std::string, Instance*> NameToInstance; + + // Reverse map from registered path to its corresponding mount name. + typedef std::map<FilePath, std::string> PathToName; + + // Use |GetSystemInstance| of |CreateRefCounted| to get an instance. + ExternalMountPoints(); + virtual ~ExternalMountPoints(); + + // Performs sanity checks on the new mount point. + // Checks the following: + // - there is no registered mount point with mount_name + // - path does not contain a reference to a parent + // - path is absolute + // - path does not overlap with an existing mount point path. + // + // |lock_| should be taken before calling this method. + bool ValidateNewMountPoint(const std::string& mount_name, + const FilePath& path); + + // This lock needs to be obtained when accessing the instance_map_. + mutable base::Lock lock_; + + NameToInstance instance_map_; + PathToName path_to_name_map_; + + DISALLOW_COPY_AND_ASSIGN(ExternalMountPoints); +}; + +// Registers a scoped external filesystem which gets revoked when it scopes out. +class WEBKIT_STORAGE_EXPORT ScopedExternalFileSystem { + public: + ScopedExternalFileSystem(const std::string& mount_name, + FileSystemType type, + const FilePath& path); + ~ScopedExternalFileSystem(); + + FilePath GetVirtualRootPath() const; + + private: + const std::string mount_name_; +}; + +} // namespace fileapi + +#endif // WEBKIT_FILEAPI_EXTERNAL_MOUNT_POINTS_H_ + diff --git a/webkit/fileapi/external_mount_points_unittest.cc b/webkit/fileapi/external_mount_points_unittest.cc new file mode 100644 index 0000000..379d146 --- /dev/null +++ b/webkit/fileapi/external_mount_points_unittest.cc @@ -0,0 +1,227 @@ +// 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 <string> + +#include "base/file_path.h" +#include "testing/gtest/include/gtest/gtest.h" + +#define FPL FILE_PATH_LITERAL + +#if defined(FILE_PATH_USES_DRIVE_LETTERS) +#define DRIVE FPL("C:") +#else +#define DRIVE +#endif + +namespace { + +TEST(ExternalMountPointsTest, AddMountPoint) { + scoped_refptr<fileapi::ExternalMountPoints> mount_points( + fileapi::ExternalMountPoints::CreateRefCounted()); + + struct TestCase { + // The mount point's name. + const char* const name; + // The mount point's path. + const FilePath::CharType* const path; + // Whether the mount point registration should succeed. + bool success; + // Path returned by GetRegisteredPath. NULL if the method is expected to + // fail. + const FilePath::CharType* const registered_path; + }; + + const TestCase kTestCases[] = { + // Valid mount point. + { "test", DRIVE FPL("/foo/test"), true, DRIVE FPL("/foo/test") }, + // Valid mount point with only one path component. + { "bbb", DRIVE FPL("/bbb"), true, DRIVE FPL("/bbb") }, + // Existing mount point path is substring of the mount points path. + { "test11", DRIVE FPL("/foo/test11"), true, DRIVE FPL("/foo/test11") }, + // Path substring of an existing path. + { "test1", DRIVE FPL("/foo/test1"), true, DRIVE FPL("/foo/test1") }, + // Empty mount point name and path. + { "", DRIVE FPL(""), false, NULL }, + // Empty mount point name. + { "", DRIVE FPL("/ddd"), false, NULL }, + // Empty mount point path. + { "empty_path", FPL(""), true, FPL("") }, + // Name different from path's base name. + { "not_base_name", DRIVE FPL("/x/y/z"), true, DRIVE FPL("/x/y/z") }, + // References parent. + { "invalid", DRIVE FPL("../foo/invalid"), false, NULL }, + // Relative path. + { "relative", DRIVE FPL("foo/relative"), false, NULL }, + // Existing mount point path. + { "path_exists", DRIVE FPL("/foo/test"), false, NULL }, + // Mount point with the same name exists. + { "test", DRIVE FPL("/foo/a/test_name_exists"), false, + DRIVE FPL("/foo/test") }, + // Child of an existing mount point. + { "a1", DRIVE FPL("/foo/test/a"), false, NULL }, + // Parent of an existing mount point. + { "foo1", DRIVE FPL("/foo"), false, NULL }, + // Bit bigger depth. + { "g", DRIVE FPL("/foo/a/b/c/d/e/f/g"), true, + DRIVE FPL("/foo/a/b/c/d/e/f/g") }, + // Sibling mount point (with similar name) exists. + { "ff", DRIVE FPL("/foo/a/b/c/d/e/ff"), true, + DRIVE FPL("/foo/a/b/c/d/e/ff") }, + // Lexicographically last among existing mount points. + { "yyy", DRIVE FPL("/zzz/yyy"), true, DRIVE FPL("/zzz/yyy") }, + // Parent of the lexicographically last mount point. + { "zzz1", DRIVE FPL("/zzz"), false, NULL }, + // Child of the lexicographically last mount point. + { "xxx1", DRIVE FPL("/zzz/yyy/xxx"), false, NULL }, + // Lexicographically first among existing mount points. + { "b", DRIVE FPL("/a/b"), true, DRIVE FPL("/a/b") }, + // Parent of lexicographically first mount point. + { "a2", DRIVE FPL("/a"), false, NULL }, + // Child of lexicographically last mount point. + { "c1", DRIVE FPL("/a/b/c"), false, NULL }, + // Parent to all of the mount points. + { "root", DRIVE FPL("/"), false, NULL }, + // Path contains .. component. + { "funky", DRIVE FPL("/tt/fun/../funky"), false, NULL }, + // Windows separators. +#if defined(FILE_PATH_USES_WIN_SEPARATORS) + { "win", DRIVE FPL("\\try\\separators\\win"), true, + DRIVE FPL("\\try\\separators\\win") }, + { "win1", DRIVE FPL("\\try/separators\\win1"), true, + DRIVE FPL("\\try/separators\\win1") }, + { "win2", DRIVE FPL("\\try/separators\\win"), false, NULL }, +#else + { "win", DRIVE FPL("\\separators\\win"), false, NULL }, + { "win1", DRIVE FPL("\\try/separators\\win1"), false, NULL }, +#endif + // Win separators, but relative path. + { "win2", DRIVE FPL("try\\separators\\win2"), false, NULL }, + }; + + // Test adding mount points. + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) { + EXPECT_EQ(kTestCases[i].success, + mount_points->RegisterFileSystem( + kTestCases[i].name, + fileapi::kFileSystemTypeNativeLocal, + FilePath(kTestCases[i].path))) + << "Adding mount point: " << kTestCases[i].name << " with path " + << kTestCases[i].path; + } + + // Test that final mount point presence state is as expected. + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) { + FilePath found_path; + EXPECT_EQ(kTestCases[i].registered_path != NULL, + mount_points->GetRegisteredPath(kTestCases[i].name, &found_path)) + << "Test case: " << i; + + if (kTestCases[i].registered_path) { + FilePath expected_path(kTestCases[i].registered_path); + EXPECT_EQ(expected_path.NormalizePathSeparators(), found_path); + } + } +} + +TEST(ExternalMountPointsTest, GetVirtualPath) { + scoped_refptr<fileapi::ExternalMountPoints> mount_points( + fileapi::ExternalMountPoints::CreateRefCounted()); + + mount_points->RegisterFileSystem("c", + fileapi::kFileSystemTypeNativeLocal, + FilePath(DRIVE FPL("/a/b/c"))); + // Note that "/a/b/c" < "/a/b/c(1)" < "/a/b/c/". + mount_points->RegisterFileSystem("c(1)", + fileapi::kFileSystemTypeNativeLocal, + FilePath(DRIVE FPL("/a/b/c(1)"))); + mount_points->RegisterFileSystem("x", + fileapi::kFileSystemTypeNativeLocal, + FilePath(DRIVE FPL("/z/y/x"))); + mount_points->RegisterFileSystem("o", + fileapi::kFileSystemTypeNativeLocal, + FilePath(DRIVE FPL("/m/n/o"))); + // A mount point whose name does not match its path base name. + mount_points->RegisterFileSystem("mount", + fileapi::kFileSystemTypeNativeLocal, + FilePath(DRIVE FPL("/root/foo"))); + // A mount point with an empty path. + mount_points->RegisterFileSystem("empty_path", + fileapi::kFileSystemTypeNativeLocal, + FilePath(FPL(""))); + + struct TestCase { + const FilePath::CharType* const local_path; + bool success; + const FilePath::CharType* const virtual_path; + }; + + const TestCase kTestCases[] = { + // Empty path. + { FPL(""), false, FPL("") }, + // No registered mount point (but is parent to a mount point). + { DRIVE FPL("/a/b"), false, FPL("") }, + // No registered mount point (but is parent to a mount point). + { DRIVE FPL("/z/y"), false, FPL("") }, + // No registered mount point (but is parent to a mount point). + { DRIVE FPL("/m/n"), false, FPL("") }, + // No registered mount point. + { DRIVE FPL("/foo/mount"), false, FPL("") }, + // An existing mount point path is substring. + { DRIVE FPL("/a/b/c1"), false, FPL("") }, + // No leading /. + { DRIVE FPL("a/b/c"), false, FPL("") }, + // Sibling to a root path. + { DRIVE FPL("/a/b/d/e"), false, FPL("") }, + // Sibling to a root path. + { DRIVE FPL("/z/y/v/u"), false, FPL("") }, + // Sibling to a root path. + { DRIVE FPL("/m/n/p/q"), false, FPL("") }, + // Mount point root path. + { DRIVE FPL("/a/b/c"), true, FPL("c") }, + // Mount point root path. + { DRIVE FPL("/z/y/x"), true, FPL("x") }, + // Mount point root path. + { DRIVE FPL("/m/n/o"), true, FPL("o") }, + // Mount point child path. + { DRIVE FPL("/a/b/c/d/e"), true, FPL("c/d/e") }, + // Mount point child path. + { DRIVE FPL("/z/y/x/v/u"), true, FPL("x/v/u") }, + // Mount point child path. + { DRIVE FPL("/m/n/o/p/q"), true, FPL("o/p/q") }, + // Name doesn't match mount point path base name. + { DRIVE FPL("/root/foo/a/b/c"), true, FPL("mount/a/b/c") }, + { DRIVE FPL("/root/foo"), true, FPL("mount") }, + // Mount point contains character whose ASCII code is smaller than file path + // separator's. + { DRIVE FPL("/a/b/c(1)/d/e"), true, FPL("c(1)/d/e") }, +#if defined(FILE_PATH_USES_WIN_SEPARATORS) + // Path with win separators mixed in. + { DRIVE FPL("/a\\b\\c/d"), true, FPL("c/d") }, +#endif + }; + + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) { + // Initialize virtual path with a value. + FilePath virtual_path(DRIVE FPL("/mount")); + FilePath local_path(kTestCases[i].local_path); + EXPECT_EQ(kTestCases[i].success, + mount_points->GetVirtualPath(local_path, &virtual_path)) + << "Resolving " << kTestCases[i].local_path; + + // There are no guarantees for |virtual_path| value if |GetVirtualPath| + // fails. + if (!kTestCases[i].success) + continue; + + FilePath expected_virtual_path(kTestCases[i].virtual_path); + EXPECT_EQ(expected_virtual_path.NormalizePathSeparators(), virtual_path) + << "Resolving " << kTestCases[i].local_path; + } +} + +} // namespace + diff --git a/webkit/fileapi/file_system_context.cc b/webkit/fileapi/file_system_context.cc index 93a0aa7..bf285ea 100644 --- a/webkit/fileapi/file_system_context.cc +++ b/webkit/fileapi/file_system_context.cc @@ -8,6 +8,7 @@ #include "base/stl_util.h" #include "base/single_thread_task_runner.h" #include "googleurl/src/gurl.h" +#include "webkit/fileapi/external_mount_points.h" #include "webkit/fileapi/file_system_file_util.h" #include "webkit/fileapi/file_system_operation.h" #include "webkit/fileapi/file_system_options.h" @@ -75,7 +76,11 @@ FileSystemContext::FileSystemContext( } #if defined(OS_CHROMEOS) external_provider_.reset( - new chromeos::CrosMountPointProvider(special_storage_policy)); + new chromeos::CrosMountPointProvider( + special_storage_policy, + // TODO(tbarzic): Switch this to |external_mount_points_|. + fileapi::ExternalMountPoints::GetSystemInstance(), + fileapi::ExternalMountPoints::GetSystemInstance())); #endif } @@ -243,6 +248,7 @@ FileSystemOperation* FileSystemContext::CreateFileSystemOperation( *error_code = base::PLATFORM_FILE_ERROR_INVALID_URL; return NULL; } + FileSystemMountPointProvider* mount_point_provider = GetMountPointProvider(url.type()); if (!mount_point_provider) { diff --git a/webkit/fileapi/file_system_mount_point_provider.h b/webkit/fileapi/file_system_mount_point_provider.h index 4f0950e..24c00fe 100644 --- a/webkit/fileapi/file_system_mount_point_provider.h +++ b/webkit/fileapi/file_system_mount_point_provider.h @@ -141,14 +141,14 @@ class ExternalFileSystemMountPointProvider virtual void RevokeAccessForExtension( const std::string& extension_id) = 0; // Checks if a given |mount_point| already exists. - virtual bool HasMountPoint(const FilePath& mount_point) = 0; + virtual bool HasMountPoint(const FilePath& mount_point) const = 0; // Adds a new local mount point. - virtual void AddLocalMountPoint(const FilePath& mount_point) = 0; + virtual bool AddLocalMountPoint(const FilePath& mount_point) = 0; // Adds a new local mount point that will be accessible only by extensions // that have been granted full acess for all external file systems. - virtual void AddRestrictedLocalMountPoint(const FilePath& mount_point) = 0; + virtual bool AddRestrictedLocalMountPoint(const FilePath& mount_point) = 0; // Adds a new remote mount point. - virtual void AddRemoteMountPoint( + virtual bool AddRemoteMountPoint( const FilePath& mount_point, RemoteFileSystemProxyInterface* remote_proxy) = 0; // Removes a mount point. diff --git a/webkit/fileapi/file_system_url.cc b/webkit/fileapi/file_system_url.cc index 9e2fdf5..b69eda1 100644 --- a/webkit/fileapi/file_system_url.cc +++ b/webkit/fileapi/file_system_url.cc @@ -9,6 +9,7 @@ #include "base/logging.h" #include "base/string_util.h" #include "net/base/escape.h" +#include "webkit/fileapi/external_mount_points.h" #include "webkit/fileapi/file_system_types.h" #include "webkit/fileapi/file_system_util.h" #include "webkit/fileapi/isolated_context.h" @@ -158,7 +159,11 @@ void FileSystemURL::MayCrackIsolatedPath() { if (is_valid_ && IsolatedContext::IsIsolatedType(type_)) { // If the type is isolated, crack the path further to get the 'real' // filesystem type and path. - is_valid_ = IsolatedContext::GetInstance()->CrackIsolatedPath( + is_valid_ = ExternalMountPoints::GetSystemInstance()->CrackVirtualPath( + virtual_path_, &filesystem_id_, &type_, &path_); + if (is_valid_) + return; + is_valid_ = IsolatedContext::GetInstance()->CrackVirtualPath( virtual_path_, &filesystem_id_, &type_, &path_); } } diff --git a/webkit/fileapi/file_system_url_unittest.cc b/webkit/fileapi/file_system_url_unittest.cc index c6608cc..c1c01a3 100644 --- a/webkit/fileapi/file_system_url_unittest.cc +++ b/webkit/fileapi/file_system_url_unittest.cc @@ -7,6 +7,7 @@ #include "base/file_path.h" #include "googleurl/src/gurl.h" #include "testing/gtest/include/gtest/gtest.h" +#include "webkit/fileapi/external_mount_points.h" #include "webkit/fileapi/file_system_types.h" #include "webkit/fileapi/file_system_util.h" #include "webkit/fileapi/isolated_context.h" @@ -14,6 +15,12 @@ #define FPL FILE_PATH_LITERAL +#if defined(FILE_PATH_USES_DRIVE_LETTERS) +#define DRIVE FPL("C:") +#else +#define DRIVE FPL("/a/") +#endif + namespace fileapi { namespace { @@ -214,8 +221,10 @@ TEST(FileSystemURLTest, DebugString) { NormalizedUTF8Path(kPath), kURL1.DebugString()); - const FilePath kRoot(FPL("root")); - ScopedExternalFileSystem scoped_fs("foo", kFileSystemTypeNativeLocal, kRoot); + const FilePath kRoot(DRIVE FPL("/root")); + ScopedExternalFileSystem scoped_fs("foo", + kFileSystemTypeNativeLocal, + kRoot.NormalizePathSeparators()); const FileSystemURL kURL2(kOrigin, kFileSystemTypeExternal, scoped_fs.GetVirtualRootPath().Append(kPath)); EXPECT_EQ("filesystem:http://example.com/external/" + diff --git a/webkit/fileapi/isolated_context.cc b/webkit/fileapi/isolated_context.cc index 057d508..1433e72 100644 --- a/webkit/fileapi/isolated_context.cc +++ b/webkit/fileapi/isolated_context.cc @@ -42,7 +42,7 @@ FilePath::StringType GetRegisterNameForPath(const FilePath& path) { bool IsSinglePathIsolatedFileSystem(FileSystemType type) { switch (type) { // As of writing dragged file system is the only filesystem - // which could have multiple toplevel paths. + // which could have multiple top-level paths. case kFileSystemTypeDragged: return false; @@ -57,15 +57,10 @@ bool IsSinglePathIsolatedFileSystem(FileSystemType type) { return true; } -} // namespace - static base::LazyInstance<IsolatedContext>::Leaky g_isolated_context = LAZY_INSTANCE_INITIALIZER; -IsolatedContext::FileInfo::FileInfo() {} -IsolatedContext::FileInfo::FileInfo( - const std::string& name, const FilePath& path) - : name(name), path(path) {} +} // namespace IsolatedContext::FileInfoSet::FileInfoSet() {} IsolatedContext::FileInfoSet::~FileInfoSet() {} @@ -78,7 +73,8 @@ bool IsolatedContext::FileInfoSet::AddPath( FilePath::StringType name = GetRegisterNameForPath(path); std::string utf8name = FilePath(name).AsUTF8Unsafe(); FilePath normalized_path = path.NormalizePathSeparators(); - bool inserted = fileset_.insert(FileInfo(utf8name, normalized_path)).second; + bool inserted = + fileset_.insert(MountPointInfo(utf8name, normalized_path)).second; if (!inserted) { int suffix = 1; std::string basepart = FilePath(name).RemoveExtension().AsUTF8Unsafe(); @@ -87,7 +83,8 @@ bool IsolatedContext::FileInfoSet::AddPath( utf8name = base::StringPrintf("%s (%d)", basepart.c_str(), suffix++); if (!ext.empty()) utf8name.append(ext); - inserted = fileset_.insert(FileInfo(utf8name, normalized_path)).second; + inserted = + fileset_.insert(MountPointInfo(utf8name, normalized_path)).second; } } if (registered_name) @@ -100,34 +97,29 @@ bool IsolatedContext::FileInfoSet::AddPathWithName( // The given path should not contain any '..' and should be absolute. if (path.ReferencesParent() || !path.IsAbsolute()) return false; - return fileset_.insert(FileInfo(name, path.NormalizePathSeparators())).second; + return fileset_.insert( + MountPointInfo(name, path.NormalizePathSeparators())).second; } //-------------------------------------------------------------------------- class IsolatedContext::Instance { public: - typedef FileSystemType MountType; - // For a single-path isolated file system, which could be registered by // IsolatedContext::RegisterFileSystemForPath(). // Most of isolated file system contexts should be of this type. - Instance(FileSystemType type, const FileInfo& file_info); + Instance(FileSystemType type, const MountPointInfo& file_info); // For a multi-paths isolated file system. As of writing only file system // type which could have multi-paths is Dragged file system, and // could be registered by IsolatedContext::RegisterDraggedFileSystem(). - Instance(FileSystemType type, const std::set<FileInfo>& files); - - // For a single-path external file system. - Instance(FileSystemType type, const FilePath& path); + Instance(FileSystemType type, const std::set<MountPointInfo>& files); ~Instance(); - MountType mount_type() const { return mount_type_; } FileSystemType type() const { return type_; } - const FileInfo& file_info() const { return file_info_; } - const std::set<FileInfo>& files() const { return files_; } + const MountPointInfo& file_info() const { return file_info_; } + const std::set<MountPointInfo>& files() const { return files_; } int ref_counts() const { return ref_counts_; } void AddRef() { ++ref_counts_; } @@ -139,14 +131,13 @@ class IsolatedContext::Instance { bool IsSinglePathInstance() const; private: - const MountType mount_type_; const FileSystemType type_; // For single-path instance. - const FileInfo file_info_; + const MountPointInfo file_info_; // For multiple-path instance (e.g. dragged file system). - const std::set<FileInfo> files_; + const std::set<MountPointInfo> files_; // Reference counts. Note that an isolated filesystem is created with ref==0 // and will get deleted when the ref count reaches <=0. @@ -156,32 +147,21 @@ class IsolatedContext::Instance { }; IsolatedContext::Instance::Instance(FileSystemType type, - const FileInfo& file_info) - : mount_type_(kFileSystemTypeIsolated), - type_(type), + const MountPointInfo& file_info) + : type_(type), file_info_(file_info), ref_counts_(0) { DCHECK(IsSinglePathIsolatedFileSystem(type_)); } IsolatedContext::Instance::Instance(FileSystemType type, - const std::set<FileInfo>& files) - : mount_type_(kFileSystemTypeIsolated), - type_(type), + const std::set<MountPointInfo>& files) + : type_(type), files_(files), ref_counts_(0) { DCHECK(!IsSinglePathIsolatedFileSystem(type_)); } -IsolatedContext::Instance::Instance(FileSystemType type, - const FilePath& path) - : mount_type_(kFileSystemTypeExternal), - type_(type), - file_info_(FileInfo("", path)), - ref_counts_(0) { - DCHECK(IsSinglePathIsolatedFileSystem(type_)); -} - IsolatedContext::Instance::~Instance() {} bool IsolatedContext::Instance::ResolvePathForName(const std::string& name, @@ -190,8 +170,8 @@ bool IsolatedContext::Instance::ResolvePathForName(const std::string& name, *path = file_info_.path; return file_info_.name == name; } - std::set<FileInfo>::const_iterator found = files_.find( - FileInfo(name, FilePath())); + std::set<MountPointInfo>::const_iterator found = files_.find( + MountPointInfo(name, FilePath())); if (found == files_.end()) return false; *path = found->path; @@ -240,83 +220,28 @@ std::string IsolatedContext::RegisterFileSystemForPath( base::AutoLock locker(lock_); std::string filesystem_id = GetNewFileSystemId(); - instance_map_[filesystem_id] = new Instance(type, FileInfo(name, path)); + instance_map_[filesystem_id] = new Instance(type, MountPointInfo(name, path)); path_to_id_map_[path].insert(filesystem_id); return filesystem_id; } -bool IsolatedContext::RegisterExternalFileSystem(const std::string& mount_name, - FileSystemType type, - const FilePath& path) { - base::AutoLock locker(lock_); - IDToInstance::iterator found = instance_map_.find(mount_name); - if (found != instance_map_.end()) - return false; - instance_map_[mount_name] = new Instance(type, path); - path_to_id_map_[path].insert(mount_name); - return true; -} - -std::vector<IsolatedContext::FileInfo> -IsolatedContext::GetExternalMountPoints() const { - base::AutoLock locker(lock_); - std::vector<FileInfo> files; - for (IDToInstance::const_iterator iter = instance_map_.begin(); - iter != instance_map_.end(); - ++iter) { - if (iter->second->mount_type() == kFileSystemTypeExternal) - files.push_back(FileInfo(iter->first, iter->second->file_info().path)); - } - return files; -} - bool IsolatedContext::RevokeFileSystem(const std::string& filesystem_id) { base::AutoLock locker(lock_); return UnregisterFileSystem(filesystem_id); } -void IsolatedContext::RevokeFileSystemByPath(const FilePath& path_in) { - base::AutoLock locker(lock_); - FilePath path(path_in.NormalizePathSeparators()); - PathToID::iterator ids_iter = path_to_id_map_.find(path); - if (ids_iter == path_to_id_map_.end()) - return; - std::set<std::string>& ids = ids_iter->second; - for (std::set<std::string>::iterator iter = ids.begin(); - iter != ids.end(); ++iter) { - IDToInstance::iterator found = instance_map_.find(*iter); - if (found != instance_map_.end()) { - delete found->second; - instance_map_.erase(found); - } - } - path_to_id_map_.erase(ids_iter); -} - -void IsolatedContext::AddReference(const std::string& filesystem_id) { - base::AutoLock locker(lock_); - DCHECK(instance_map_.find(filesystem_id) != instance_map_.end()); - instance_map_[filesystem_id]->AddRef(); -} - -void IsolatedContext::RemoveReference(const std::string& filesystem_id) { +bool IsolatedContext::GetRegisteredPath( + const std::string& filesystem_id, FilePath* path) const { + DCHECK(path); base::AutoLock locker(lock_); - // This could get called for non-existent filesystem if it has been - // already deleted by RevokeFileSystemByPath. - IDToInstance::iterator found = instance_map_.find(filesystem_id); - if (found == instance_map_.end()) - return; - Instance* instance = found->second; - DCHECK_GT(instance->ref_counts(), 0); - instance->RemoveRef(); - if (instance->ref_counts() == 0 && - instance->mount_type() != kFileSystemTypeExternal) { - bool deleted = UnregisterFileSystem(filesystem_id); - DCHECK(deleted); - } + IDToInstance::const_iterator found = instance_map_.find(filesystem_id); + if (found == instance_map_.end() || !found->second->IsSinglePathInstance()) + return false; + *path = found->second->file_info().path; + return true; } -bool IsolatedContext::CrackIsolatedPath(const FilePath& virtual_path, +bool IsolatedContext::CrackVirtualPath(const FilePath& virtual_path, std::string* id_or_name, FileSystemType* type, FilePath* path) const { @@ -348,26 +273,17 @@ bool IsolatedContext::CrackIsolatedPath(const FilePath& virtual_path, const Instance* instance = found_instance->second; if (type) *type = instance->type(); - switch (instance->mount_type()) { - case kFileSystemTypeIsolated: { - if (component_iter == components.end()) { - // The virtual root case. - path->clear(); - return true; - } - // *component_iter should be a name of the registered path. - std::string name = FilePath(*component_iter++).AsUTF8Unsafe(); - if (!instance->ResolvePathForName(name, &cracked_path)) - return false; - break; - } - case kFileSystemTypeExternal: - cracked_path = instance->file_info().path; - break; - default: - NOTREACHED(); - break; + + if (component_iter == components.end()) { + // The virtual root case. + path->clear(); + return true; } + + // *component_iter should be a name of the registered path. + std::string name = FilePath(*component_iter++).AsUTF8Unsafe(); + if (!instance->ResolvePathForName(name, &cracked_path)) + return false; } for (; component_iter != components.end(); ++component_iter) @@ -376,8 +292,49 @@ bool IsolatedContext::CrackIsolatedPath(const FilePath& virtual_path, return true; } +void IsolatedContext::RevokeFileSystemByPath(const FilePath& path_in) { + base::AutoLock locker(lock_); + FilePath path(path_in.NormalizePathSeparators()); + PathToID::iterator ids_iter = path_to_id_map_.find(path); + if (ids_iter == path_to_id_map_.end()) + return; + std::set<std::string>& ids = ids_iter->second; + for (std::set<std::string>::iterator iter = ids.begin(); + iter != ids.end(); ++iter) { + IDToInstance::iterator found = instance_map_.find(*iter); + if (found != instance_map_.end()) { + delete found->second; + instance_map_.erase(found); + } + } + path_to_id_map_.erase(ids_iter); +} + +void IsolatedContext::AddReference(const std::string& filesystem_id) { + base::AutoLock locker(lock_); + DCHECK(instance_map_.find(filesystem_id) != instance_map_.end()); + instance_map_[filesystem_id]->AddRef(); +} + +void IsolatedContext::RemoveReference(const std::string& filesystem_id) { + base::AutoLock locker(lock_); + // This could get called for non-existent filesystem if it has been + // already deleted by RevokeFileSystemByPath. + IDToInstance::iterator found = instance_map_.find(filesystem_id); + if (found == instance_map_.end()) + return; + Instance* instance = found->second; + DCHECK_GT(instance->ref_counts(), 0); + instance->RemoveRef(); + if (instance->ref_counts() == 0) { + bool deleted = UnregisterFileSystem(filesystem_id); + DCHECK(deleted); + } +} + bool IsolatedContext::GetDraggedFileInfo( - const std::string& filesystem_id, std::vector<FileInfo>* files) const { + const std::string& filesystem_id, + std::vector<MountPointInfo>* files) const { DCHECK(files); base::AutoLock locker(lock_); IDToInstance::const_iterator found = instance_map_.find(filesystem_id); @@ -389,17 +346,6 @@ bool IsolatedContext::GetDraggedFileInfo( return true; } -bool IsolatedContext::GetRegisteredPath( - const std::string& filesystem_id, FilePath* path) const { - DCHECK(path); - base::AutoLock locker(lock_); - IDToInstance::const_iterator found = instance_map_.find(filesystem_id); - if (found == instance_map_.end() || !found->second->IsSinglePathInstance()) - return false; - *path = found->second->file_info().path; - return true; -} - FilePath IsolatedContext::CreateVirtualRootPath( const std::string& filesystem_id) const { return FilePath().AppendASCII(filesystem_id); @@ -444,21 +390,4 @@ std::string IsolatedContext::GetNewFileSystemId() const { return id; } -ScopedExternalFileSystem::ScopedExternalFileSystem( - const std::string& mount_name, - FileSystemType type, - const FilePath& path) - : mount_name_(mount_name) { - IsolatedContext::GetInstance()->RegisterExternalFileSystem( - mount_name, type, path); -} - -FilePath ScopedExternalFileSystem::GetVirtualRootPath() const { - return IsolatedContext::GetInstance()->CreateVirtualRootPath(mount_name_); -} - -ScopedExternalFileSystem::~ScopedExternalFileSystem() { - IsolatedContext::GetInstance()->RevokeFileSystem(mount_name_); -} - } // namespace fileapi diff --git a/webkit/fileapi/isolated_context.h b/webkit/fileapi/isolated_context.h index e0cea7c..63cab56 100644 --- a/webkit/fileapi/isolated_context.h +++ b/webkit/fileapi/isolated_context.h @@ -16,60 +16,25 @@ #include "base/memory/singleton.h" #include "base/synchronization/lock.h" #include "webkit/fileapi/file_system_types.h" +#include "webkit/fileapi/mount_points.h" #include "webkit/storage/webkit_storage_export.h" namespace fileapi { -// Manages isolated filesystem namespaces. -// This context class is a singleton and access to the context is -// thread-safe (protected with a lock). -// -// There are two types of filesystems managed by this context: -// isolated and external. -// The former is transient while the latter is persistent. -// -// * Transient isolated file systems have no name and are identified by -// string 'filesystem ID', which usually just looks like random value. -// This type of filesystem can be created on the fly and may go away -// when it has no references from renderers. -// Files in an isolated filesystem are registered with corresponding names -// and identified by a filesystem URL like: +// Manages isolated filesystem mount points which have no well-known names +// and are identified by a string 'filesystem ID', which usually just looks +// like random value. +// This type of filesystem can be created on the fly and may go away when it has +// no references from renderers. +// Files in an isolated filesystem are registered with corresponding names and +// identified by a filesystem URL like: // // filesystem:<origin>/isolated/<filesystem_id>/<name>/relative/path // -// * Persistent external file systems are identified by 'mount name' -// and are persisted until RevokeFileSystem is called. -// Files in an external filesystem are identified by a filesystem URL like: -// -// filesystem:<origin>/external/<mount_name>/relative/path -// -// A filesystem instance is represented by IsolatedContext::Instance, and -// managed as a map instance_map_ which maps from filesystem ID (or name) -// to the instance. -// // Some methods of this class are virtual just for mocking. // -// TODO(kinuko): This should have a better name since this handles both -// isolated and external file systems. -// -class WEBKIT_STORAGE_EXPORT IsolatedContext { +class WEBKIT_STORAGE_EXPORT IsolatedContext : public MountPoints { public: - struct WEBKIT_STORAGE_EXPORT FileInfo { - FileInfo(); - FileInfo(const std::string& name, const FilePath& path); - - // The name to be used to register the file. The registered file can - // be referred by a virtual path /<filesystem_id>/<name>. - // The name should NOT contain a path separator '/'. - std::string name; - - // The path of the file. - FilePath path; - - // For STL operation. - bool operator<(const FileInfo& that) const { return name < that.name; } - }; - class WEBKIT_STORAGE_EXPORT FileInfoSet { public: FileInfoSet(); @@ -86,10 +51,10 @@ class WEBKIT_STORAGE_EXPORT IsolatedContext { // is not valid and could not be added. bool AddPathWithName(const FilePath& path, const std::string& name); - const std::set<FileInfo>& fileset() const { return fileset_; } + const std::set<MountPointInfo>& fileset() const { return fileset_; } private: - std::set<FileInfo> fileset_; + std::set<MountPointInfo> fileset_; }; // The instance is lazily created per browser process. @@ -133,30 +98,14 @@ class WEBKIT_STORAGE_EXPORT IsolatedContext { const FilePath& path, std::string* register_name); - // Registers a new named external filesystem. - // The |path| is registered as the root path of the mount point which - // is identified by a URL "filesystem:.../external/mount_name". - // - // For example, if the path "/media/removable" is registered with - // the mount_name "removable", a filesystem URL like - // "filesystem:.../external/removable/a/b" will be resolved as - // "/media/removable/a/b". - // - // The |mount_name| should NOT contain a path separator '/'. - // Returns false if the given name is already registered. - // - // An external file system registered by this method can be revoked - // by calling RevokeFileSystem with |mount_name|. - bool RegisterExternalFileSystem(const std::string& mount_name, - FileSystemType type, - const FilePath& path); - - // Returns a set of FilePath (of <mount_name, path>) registered as external. - std::vector<FileInfo> GetExternalMountPoints() const; - - // Revokes the filesystem |filesystem_id|. - // Returns false if the |filesystem_id| is not (no longer) registered. - bool RevokeFileSystem(const std::string& filesystem_id); + // MountPoints override. + virtual bool RevokeFileSystem(const std::string& filesystem_id) OVERRIDE; + virtual bool GetRegisteredPath(const std::string& filesystem_id, + FilePath* path) const OVERRIDE; + virtual bool CrackVirtualPath(const FilePath& virtual_path, + std::string* filesystem_id, + FileSystemType* type, + FilePath* path) const OVERRIDE; // Revokes all filesystem(s) registered for the given path. // This is assumed to be called when the registered path becomes @@ -173,41 +122,17 @@ class WEBKIT_STORAGE_EXPORT IsolatedContext { // Removes a reference to a filesystem specified by the given filesystem_id. // If the reference count reaches 0 the isolated context gets destroyed. - // It is ok to call this on the filesystem that has been already deleted + // It is OK to call this on the filesystem that has been already deleted // (e.g. by RevokeFileSystemByPath). void RemoveReference(const std::string& filesystem_id); - // Cracks the given |virtual_path| (which is the path part of a filesystem URL - // without '/isolated' or '/external' prefix) and populates the - // |id_or_name|, |type|, and |path| if the <id_or_name> part embedded in - // the |virtual_path| (i.e. the first component of the |virtual_path|) is a - // valid registered filesystem ID or mount name for an isolated or external - // filesystem. - // - // Returns false if the given virtual_path or the cracked id_or_name - // is not valid. - // - // Note that |path| is set to empty paths if the filesystem type is isolated - // and |virtual_path| has no <relative_path> part (i.e. pointing to the - // virtual root). - bool CrackIsolatedPath(const FilePath& virtual_path, - std::string* id_or_name, - FileSystemType* type, - FilePath* path) const; - - // Returns a set of dragged FileInfo's registered for the |filesystem_id|. + // Returns a set of dragged MountPointInfos registered for the + // |filesystem_id|. // The filesystem_id must be pointing to a dragged file system // (i.e. must be the one registered by RegisterDraggedFileSystem). // Returns false if the |filesystem_id| is not valid. bool GetDraggedFileInfo(const std::string& filesystem_id, - std::vector<FileInfo>* files) const; - - // Returns the file path registered for the |filesystem_id|. - // The filesystem_id must NOT be pointing to a dragged file system - // (i.e. must be the one registered by RegisterFileSystemForPath). - // Returns false if the |filesystem_id| is not valid. - bool GetRegisteredPath(const std::string& filesystem_id, - FilePath* path) const; + std::vector<MountPointInfo>* files) const; // Returns the virtual root path that looks like /<filesystem_id>. FilePath CreateVirtualRootPath(const std::string& filesystem_id) const; @@ -225,7 +150,7 @@ class WEBKIT_STORAGE_EXPORT IsolatedContext { // Obtain an instance of this class via GetInstance(). IsolatedContext(); - ~IsolatedContext(); + virtual ~IsolatedContext(); // Unregisters a file system of given |filesystem_id|. Must be called with // lock_ held. Returns true if the file system is unregistered. @@ -243,20 +168,6 @@ class WEBKIT_STORAGE_EXPORT IsolatedContext { DISALLOW_COPY_AND_ASSIGN(IsolatedContext); }; -// Registers a scoped external filesystem which gets revoked when it scopes out. -class WEBKIT_STORAGE_EXPORT ScopedExternalFileSystem { - public: - ScopedExternalFileSystem(const std::string& mount_name, - FileSystemType type, - const FilePath& path); - ~ScopedExternalFileSystem(); - - FilePath GetVirtualRootPath() const; - - private: - const std::string mount_name_; -}; - } // namespace fileapi #endif // WEBKIT_FILEAPI_ISOLATED_CONTEXT_H_ diff --git a/webkit/fileapi/isolated_context_unittest.cc b/webkit/fileapi/isolated_context_unittest.cc index 78efd16..bf36df9 100644 --- a/webkit/fileapi/isolated_context_unittest.cc +++ b/webkit/fileapi/isolated_context_unittest.cc @@ -19,7 +19,7 @@ namespace fileapi { -typedef IsolatedContext::FileInfo FileInfo; +typedef IsolatedContext::MountPointInfo FileInfo; namespace { @@ -95,7 +95,7 @@ TEST_F(IsolatedContextTest, RegisterAndRevokeTest) { std::string cracked_id; FilePath cracked_path; FileSystemType cracked_type; - ASSERT_TRUE(isolated_context()->CrackIsolatedPath( + ASSERT_TRUE(isolated_context()->CrackVirtualPath( virtual_path, &cracked_id, &cracked_type, &cracked_path)); ASSERT_EQ(kTestPaths[i].NormalizePathSeparators().value(), cracked_path.value()); @@ -191,11 +191,11 @@ TEST_F(IsolatedContextTest, CrackWithRelativePaths) { FilePath cracked_path; FileSystemType cracked_type; if (!relatives[j].valid) { - ASSERT_FALSE(isolated_context()->CrackIsolatedPath( + ASSERT_FALSE(isolated_context()->CrackVirtualPath( virtual_path, &cracked_id, &cracked_type, &cracked_path)); continue; } - ASSERT_TRUE(isolated_context()->CrackIsolatedPath( + ASSERT_TRUE(isolated_context()->CrackVirtualPath( virtual_path, &cracked_id, &cracked_type, &cracked_path)); ASSERT_EQ(kTestPaths[i].Append(relatives[j].path) .NormalizePathSeparators().value(), @@ -214,7 +214,7 @@ TEST_F(IsolatedContextTest, TestWithVirtualRoot) { // as "/" of the isolated filesystem is a pure virtual directory // that has no corresponding platform directory. FilePath virtual_path = isolated_context()->CreateVirtualRootPath(id_); - ASSERT_TRUE(isolated_context()->CrackIsolatedPath( + ASSERT_TRUE(isolated_context()->CrackVirtualPath( virtual_path, &cracked_id, NULL, &cracked_path)); ASSERT_EQ(FPL(""), cracked_path.value()); ASSERT_EQ(id_, cracked_id); @@ -223,7 +223,7 @@ TEST_F(IsolatedContextTest, TestWithVirtualRoot) { // included in the kTestPaths). virtual_path = isolated_context()->CreateVirtualRootPath( id_).AppendASCII("foo"); - ASSERT_FALSE(isolated_context()->CrackIsolatedPath( + ASSERT_FALSE(isolated_context()->CrackVirtualPath( virtual_path, &cracked_id, NULL, &cracked_path)); } diff --git a/webkit/fileapi/isolated_file_util.cc b/webkit/fileapi/isolated_file_util.cc index cf3f0ce..d50549e 100644 --- a/webkit/fileapi/isolated_file_util.cc +++ b/webkit/fileapi/isolated_file_util.cc @@ -19,7 +19,7 @@ using base::PlatformFileInfo; namespace fileapi { -typedef IsolatedContext::FileInfo FileInfo; +typedef IsolatedContext::MountPointInfo FileInfo; namespace { diff --git a/webkit/fileapi/mount_points.cc b/webkit/fileapi/mount_points.cc new file mode 100644 index 0000000..d754b25 --- /dev/null +++ b/webkit/fileapi/mount_points.cc @@ -0,0 +1,15 @@ +// 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/mount_points.h" + +namespace fileapi { + +MountPoints::MountPointInfo::MountPointInfo() {} +MountPoints::MountPointInfo::MountPointInfo( + const std::string& name, const FilePath& path) + : name(name), path(path) {} + +} // namespace fileapi + diff --git a/webkit/fileapi/mount_points.h b/webkit/fileapi/mount_points.h new file mode 100644 index 0000000..0cfb57b --- /dev/null +++ b/webkit/fileapi/mount_points.h @@ -0,0 +1,77 @@ +// 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. + +#ifndef WEBKIT_FILEAPI_MOUNT_POINTS_H_ +#define WEBKIT_FILEAPI_MOUNT_POINTS_H_ + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/file_path.h" +#include "webkit/fileapi/file_system_util.h" +#include "webkit/storage/webkit_storage_export.h" + +class GURL; + +namespace fileapi { + +// Represents a set of mount points for File API. +class WEBKIT_STORAGE_EXPORT MountPoints { + public: + struct WEBKIT_STORAGE_EXPORT MountPointInfo { + MountPointInfo(); + MountPointInfo(const std::string& name, const FilePath& path); + + // The name to be used to register the path. The registered file can + // be referred by a virtual path /<filesystem_id>/<name>. + // The name should NOT contain a path separator '/'. + std::string name; + + // The path of the file. + FilePath path; + + // For STL operation. + bool operator<(const MountPointInfo& that) const { + return name < that.name; + } + }; + + MountPoints() {} + virtual ~MountPoints() {} + + // Revokes a mount point identified by |mount_name|. + // Returns false if the |mount_name| is not (no longer) registered. + // TODO(kinuko): Probably this should be rather named RevokeMountPoint. + virtual bool RevokeFileSystem(const std::string& mount_name) = 0; + + // Returns the mount point root path registered for a given |mount_name|. + // Returns false if the given |mount_name| is not valid. + virtual bool GetRegisteredPath(const std::string& mount_name, + FilePath* path) const = 0; + + // Cracks the given |virtual_path| (which is the path part of a filesystem URL + // without '/external' or '/isolated' prefix part) and populates the + // |mount_name|, |type|, and |path| if the <mount_name> part embedded in + // the |virtual_path| (i.e. the first component of the |virtual_path|) is a + // valid registered filesystem ID or mount name for an existing mount point. + // + // Returns false if the given virtual_path cannot be cracked. + // + // Note that |path| is set to empty paths if the filesystem type is isolated + // and |virtual_path| has no <relative_path> part (i.e. pointing to the + // virtual root). + virtual bool CrackVirtualPath(const FilePath& virtual_path, + std::string* mount_name, + FileSystemType* type, + FilePath* path) const = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(MountPoints); +}; + +} // namespace fileapi + +#endif // WEBKIT_FILEAPI_MOUNT_POINTS_H_ + diff --git a/webkit/fileapi/remote_file_system_proxy.h b/webkit/fileapi/remote_file_system_proxy.h new file mode 100644 index 0000000..e54a266 --- /dev/null +++ b/webkit/fileapi/remote_file_system_proxy.h @@ -0,0 +1,122 @@ +// Copyright (c) 2012 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. + +#ifndef WEBKIT_CHROMEOS_FILEAPI_REMOTE_FILE_SYSTEM_PROXY_H_ +#define WEBKIT_CHROMEOS_FILEAPI_REMOTE_FILE_SYSTEM_PROXY_H_ + +#include "base/callback.h" +#include "base/memory/ref_counted.h" +#include "webkit/fileapi/file_system_operation.h" + +namespace fileapi { + +typedef base::Callback< + void(base::PlatformFileError result, + const FilePath& platform_path, + const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref)> + WritableSnapshotFile; + +// The interface class for remote file system proxy. +class RemoteFileSystemProxyInterface : + public base::RefCountedThreadSafe<RemoteFileSystemProxyInterface> { + public: + // Gets the file or directory info for given|path|. + virtual void GetFileInfo(const FileSystemURL& url, + const FileSystemOperation::GetMetadataCallback& callback) = 0; + + // Copies a file or directory from |src_url| to |dest_url|. If + // |src_url| is a directory, the contents of |src_url| are copied to + // |dest_url| recursively. A new file or directory is created at + // |dest_url| as needed. + virtual void Copy( + const FileSystemURL& src_url, + const FileSystemURL& dest_url, + const FileSystemOperation::StatusCallback& callback) = 0; + + // Moves a file or directory from |src_url| to |dest_url|. A new file + // or directory is created at |dest_url| as needed. + virtual void Move( + const FileSystemURL& src_url, + const FileSystemURL& dest_url, + const FileSystemOperation::StatusCallback& callback) = 0; + + // Reads contents of a directory at |url|. + virtual void ReadDirectory(const FileSystemURL& url, + const FileSystemOperation::ReadDirectoryCallback& callback) = 0; + + // Removes a file or directory at |url|. If |recursive| is true, remove + // all files and directories under the directory at |url| recursively. + virtual void Remove(const FileSystemURL& url, bool recursive, + const FileSystemOperation::StatusCallback& callback) = 0; + + // Creates a directory at |url|. If |exclusive| is true, an error is + // raised in case a directory is already present at the URL. If + // |recursive| is true, create parent directories as needed just like + // mkdir -p does. + virtual void CreateDirectory( + const FileSystemURL& url, + bool exclusive, + bool recursive, + const FileSystemOperation::StatusCallback& callback) = 0; + + // Creates a file at |url|. If the flag |is_exclusive| is true, an + // error is raised when a file already exists at the path. It is + // an error if a directory or a hosted document is already present at the + // path, or the parent directory of the path is not present yet. + virtual void CreateFile( + const FileSystemURL& url, + bool exclusive, + const FileSystemOperation::StatusCallback& callback) = 0; + + // Changes the length of an existing file at |url| to |length|. If |length| + // is negative, an error is raised. If |length| is more than the current size + // of the file, zero is padded for the extended part. + virtual void Truncate( + const FileSystemURL& url, + int64 length, + const FileSystemOperation::StatusCallback& callback) = 0; + + // Creates a local snapshot file for a given |url| and returns the + // metadata and platform path of the snapshot file via |callback|. + // See also FileSystemOperation::CreateSnapshotFile(). + virtual void CreateSnapshotFile( + const FileSystemURL& url, + const FileSystemOperation::SnapshotFileCallback& callback) = 0; + + // Creates a local snapshot file for a given |url| and marks it for + // modification. A webkit_blob::ShareableFileReference is passed to + // |callback|, and when the reference is released, modification to the + // snapshot is marked for uploading to the remote file system. + virtual void CreateWritableSnapshotFile( + const FileSystemURL& url, + const WritableSnapshotFile& callback) = 0; + + // Opens file for a given |url| with specified |flags| (see + // base::PlatformFileFlags for details). + virtual void OpenFile( + const FileSystemURL& url, + int flags, + base::ProcessHandle peer_handle, + const FileSystemOperation::OpenFileCallback& callback) = 0; + + // Notifies that a file opened by OpenFile (at |path|) is closed. + virtual void NotifyCloseFile(const FileSystemURL& url) = 0; + + // Modifies the timestamp of a given |url| to |last_access_time| and + // |last_modified_time|. Note that unlike 'touch' command of Linux, it + // does not create a new file. + virtual void TouchFile( + const fileapi::FileSystemURL& url, + const base::Time& last_access_time, + const base::Time& last_modified_time, + const FileSystemOperation::StatusCallback& callback) = 0; + + protected: + friend class base::RefCountedThreadSafe<RemoteFileSystemProxyInterface>; + virtual ~RemoteFileSystemProxyInterface() {} +}; + +} // namespace fileapi + +#endif // WEBKIT_CHROMEOS_FILEAPI_REMOTE_FILE_SYSTEM_PROXY_H_ diff --git a/webkit/fileapi/syncable/canned_syncable_file_system.cc b/webkit/fileapi/syncable/canned_syncable_file_system.cc index 05448f3..e960959 100644 --- a/webkit/fileapi/syncable/canned_syncable_file_system.cc +++ b/webkit/fileapi/syncable/canned_syncable_file_system.cc @@ -16,7 +16,6 @@ #include "webkit/fileapi/file_system_context.h" #include "webkit/fileapi/file_system_operation_context.h" #include "webkit/fileapi/file_system_task_runners.h" -#include "webkit/fileapi/isolated_context.h" #include "webkit/fileapi/local_file_system_operation.h" #include "webkit/fileapi/mock_file_system_options.h" #include "webkit/fileapi/sandbox_mount_point_provider.h" diff --git a/webkit/fileapi/syncable/syncable_file_system_util.cc b/webkit/fileapi/syncable/syncable_file_system_util.cc index 207f802..21652d0 100644 --- a/webkit/fileapi/syncable/syncable_file_system_util.cc +++ b/webkit/fileapi/syncable/syncable_file_system_util.cc @@ -4,21 +4,22 @@ #include "webkit/fileapi/syncable/syncable_file_system_util.h" +#include "webkit/fileapi/external_mount_points.h" #include "webkit/fileapi/file_observers.h" #include "webkit/fileapi/file_system_context.h" #include "webkit/fileapi/file_system_util.h" -#include "webkit/fileapi/isolated_context.h" #include "webkit/fileapi/sandbox_mount_point_provider.h" namespace fileapi { bool RegisterSyncableFileSystem(const std::string& service_name) { - return IsolatedContext::GetInstance()->RegisterExternalFileSystem( + return ExternalMountPoints::GetSystemInstance()->RegisterFileSystem( service_name, kFileSystemTypeSyncable, FilePath()); } bool RevokeSyncableFileSystem(const std::string& service_name) { - return IsolatedContext::GetInstance()->RevokeFileSystem(service_name); + return ExternalMountPoints::GetSystemInstance()->RevokeFileSystem( + service_name); } GURL GetSyncableFileSystemRootURI(const GURL& origin, diff --git a/webkit/fileapi/syncable/syncable_file_system_util_unittest.cc b/webkit/fileapi/syncable/syncable_file_system_util_unittest.cc index b8d92f6..356ff53 100644 --- a/webkit/fileapi/syncable/syncable_file_system_util_unittest.cc +++ b/webkit/fileapi/syncable/syncable_file_system_util_unittest.cc @@ -8,7 +8,7 @@ #include "base/message_loop.h" #include "base/message_loop_proxy.h" #include "testing/gtest/include/gtest/gtest.h" -#include "webkit/fileapi/isolated_context.h" +#include "webkit/fileapi/external_mount_points.h" #include "webkit/fileapi/syncable/canned_syncable_file_system.h" #include "webkit/fileapi/syncable/local_file_sync_context.h" diff --git a/webkit/fileapi/webkit_fileapi.gypi b/webkit/fileapi/webkit_fileapi.gypi index 39288ee..324f9e5 100644 --- a/webkit/fileapi/webkit_fileapi.gypi +++ b/webkit/fileapi/webkit_fileapi.gypi @@ -5,6 +5,8 @@ { 'variables': { 'webkit_fileapi_sources': [ + '../fileapi/external_mount_points.cc', + '../fileapi/external_mount_points.h', '../fileapi/file_observers.h', '../fileapi/file_permission_policy.cc', '../fileapi/file_permission_policy.h', @@ -70,10 +72,13 @@ '../fileapi/media/mtp_device_file_system_config.h', '../fileapi/media/native_media_file_util.cc', '../fileapi/media/native_media_file_util.h', + '../fileapi/mount_points.cc', + '../fileapi/mount_points.h', '../fileapi/native_file_util.cc', '../fileapi/native_file_util.h', '../fileapi/obfuscated_file_util.cc', '../fileapi/obfuscated_file_util.h', + '../fileapi/remote_file_system_proxy.h', '../fileapi/sandbox_file_stream_writer.cc', '../fileapi/sandbox_file_stream_writer.h', '../fileapi/sandbox_mount_point_provider.cc', @@ -120,7 +125,6 @@ '../chromeos/fileapi/file_util_async.h', '../chromeos/fileapi/remote_file_system_operation.cc', '../chromeos/fileapi/remote_file_system_operation.h', - '../chromeos/fileapi/remote_file_system_proxy.h', '../chromeos/fileapi/remote_file_stream_writer.cc', '../chromeos/fileapi/remote_file_stream_writer.h', ], |