summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-04-02 09:35:05 +0000
committerkinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-04-02 09:35:05 +0000
commit6fe6965e2d0e4ac248d6825a88b5e53a77ac5ffe (patch)
tree674002b384f19261c6bf00c1033954b7a771345c
parentb93a8aea9cc770f414fdfad8fad7dcae432eb177 (diff)
downloadchromium_src-6fe6965e2d0e4ac248d6825a88b5e53a77ac5ffe.zip
chromium_src-6fe6965e2d0e4ac248d6825a88b5e53a77ac5ffe.tar.gz
chromium_src-6fe6965e2d0e4ac248d6825a88b5e53a77ac5ffe.tar.bz2
Add isolated file_util for directory (and file) drag-and-drop support.
patch from http://codereview.chromium.org/9204009/ BUG=99823 TEST=test_shell_tests:IsolatedFileUtil* Review URL: https://chromiumcodereview.appspot.com/9272007 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@130110 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--webkit/fileapi/file_system_context.cc6
-rw-r--r--webkit/fileapi/file_system_context.h2
-rw-r--r--webkit/fileapi/file_system_operation.h3
-rw-r--r--webkit/fileapi/file_system_types.h3
-rw-r--r--webkit/fileapi/file_system_util.cc49
-rw-r--r--webkit/fileapi/file_system_util.h2
-rw-r--r--webkit/fileapi/isolated_context.cc4
-rw-r--r--webkit/fileapi/isolated_context.h18
-rw-r--r--webkit/fileapi/isolated_context_unittest.cc20
-rw-r--r--webkit/fileapi/isolated_file_util.cc388
-rw-r--r--webkit/fileapi/isolated_file_util.h98
-rw-r--r--webkit/fileapi/isolated_file_util_unittest.cc432
-rw-r--r--webkit/fileapi/isolated_mount_point_provider.cc102
-rw-r--r--webkit/fileapi/isolated_mount_point_provider.h57
-rw-r--r--webkit/fileapi/test_file_set.cc31
-rw-r--r--webkit/fileapi/webkit_fileapi.gypi4
-rw-r--r--webkit/glue/webdropdata.cc3
-rw-r--r--webkit/tools/test_shell/test_shell.gypi1
18 files changed, 1172 insertions, 51 deletions
diff --git a/webkit/fileapi/file_system_context.cc b/webkit/fileapi/file_system_context.cc
index 600518e..07acff2 100644
--- a/webkit/fileapi/file_system_context.cc
+++ b/webkit/fileapi/file_system_context.cc
@@ -13,6 +13,7 @@
#include "webkit/fileapi/file_system_options.h"
#include "webkit/fileapi/file_system_quota_client.h"
#include "webkit/fileapi/file_system_util.h"
+#include "webkit/fileapi/isolated_mount_point_provider.h"
#include "webkit/fileapi/sandbox_mount_point_provider.h"
#include "webkit/quota/quota_manager.h"
#include "webkit/quota/special_storage_policy.h"
@@ -57,7 +58,8 @@ FileSystemContext::FileSystemContext(
new SandboxMountPointProvider(
file_message_loop,
profile_path,
- options)) {
+ options)),
+ isolated_provider_(new IsolatedMountPointProvider) {
if (quota_manager_proxy) {
quota_manager_proxy->RegisterClient(CreateQuotaClient(
file_message_loop, this, options.is_incognito()));
@@ -123,6 +125,8 @@ FileSystemMountPointProvider* FileSystemContext::GetMountPointProvider(
return sandbox_provider_.get();
case kFileSystemTypeExternal:
return external_provider_.get();
+ case kFileSystemTypeIsolated:
+ return isolated_provider_.get();
case kFileSystemTypeUnknown:
default:
NOTREACHED();
diff --git a/webkit/fileapi/file_system_context.h b/webkit/fileapi/file_system_context.h
index 2a6b211..7824e9d 100644
--- a/webkit/fileapi/file_system_context.h
+++ b/webkit/fileapi/file_system_context.h
@@ -32,6 +32,7 @@ class FileSystemOperationInterface;
class FileSystemOptions;
class FileSystemPathManager;
class FileSystemQuotaUtil;
+class IsolatedMountPointProvider;
class SandboxMountPointProvider;
struct DefaultContextDeleter;
@@ -122,6 +123,7 @@ class FileSystemContext
// Mount point providers.
scoped_ptr<SandboxMountPointProvider> sandbox_provider_;
+ scoped_ptr<IsolatedMountPointProvider> isolated_provider_;
scoped_ptr<ExternalFileSystemMountPointProvider> external_provider_;
DISALLOW_IMPLICIT_CONSTRUCTORS(FileSystemContext);
diff --git a/webkit/fileapi/file_system_operation.h b/webkit/fileapi/file_system_operation.h
index 0bf87cd..380e3ee 100644
--- a/webkit/fileapi/file_system_operation.h
+++ b/webkit/fileapi/file_system_operation.h
@@ -119,8 +119,9 @@ class FileSystemOperation : public FileSystemOperationInterface {
// Only MountPointProviders or testing class can create a
// new operation directly.
- friend class SandboxMountPointProvider;
friend class FileSystemTestHelper;
+ friend class IsolatedMountPointProvider;
+ friend class SandboxMountPointProvider;
friend class chromeos::CrosMountPointProvider;
friend class FileSystemOperationTest;
diff --git a/webkit/fileapi/file_system_types.h b/webkit/fileapi/file_system_types.h
index b7c96f1..b48d746 100644
--- a/webkit/fileapi/file_system_types.h
+++ b/webkit/fileapi/file_system_types.h
@@ -23,6 +23,9 @@ enum FileSystemType {
kFileSystemTypeTemporary = WebKit::WebFileSystem::TypeTemporary,
kFileSystemTypePersistent = WebKit::WebFileSystem::TypePersistent,
+ // Indicates non-sandboxed isolated filesystem.
+ kFileSystemTypeIsolated = WebKit::WebFileSystem::TypeIsolated,
+
// Indicates non-sandboxed filesystem where files are placed outside the
// profile directory (thus called 'external' filesystem).
// This filesystem is used only by Chrome OS as of writing.
diff --git a/webkit/fileapi/file_system_util.cc b/webkit/fileapi/file_system_util.cc
index ab145f1..ed365c6 100644
--- a/webkit/fileapi/file_system_util.cc
+++ b/webkit/fileapi/file_system_util.cc
@@ -8,6 +8,7 @@
#include "base/file_path.h"
#include "base/logging.h"
+#include "base/string_util.h"
#include "base/sys_string_conversions.h"
#include "base/utf_string_conversions.h"
#include "googleurl/src/gurl.h"
@@ -21,16 +22,18 @@ namespace fileapi {
const char kPersistentDir[] = "/persistent/";
const char kTemporaryDir[] = "/temporary/";
+const char kIsolatedDir[] = "/isolated/";
const char kExternalDir[] = "/external/";
const char kPersistentName[] = "Persistent";
const char kTemporaryName[] = "Temporary";
+const char kIsolatedName[] = "Isolated";
const char kExternalName[] = "External";
bool CrackFileSystemURL(const GURL& url, GURL* origin_url, FileSystemType* type,
FilePath* file_path) {
GURL origin;
- FileSystemType file_system_type;
+ FileSystemType file_system_type = kFileSystemTypeUnknown;
if (url.scheme() != "filesystem")
return false;
@@ -64,19 +67,27 @@ bool CrackFileSystemURL(const GURL& url, GURL* origin_url, FileSystemType* type,
std::string path = net::UnescapeURLComponent(bare_url.path(),
net::UnescapeRule::SPACES | net::UnescapeRule::URL_SPECIAL_CHARS |
net::UnescapeRule::CONTROL_CHARS);
- if (path.compare(0, strlen(kPersistentDir), kPersistentDir) == 0) {
- file_system_type = kFileSystemTypePersistent;
- path = path.substr(strlen(kPersistentDir));
- } else if (path.compare(0, strlen(kTemporaryDir), kTemporaryDir) == 0) {
- file_system_type = kFileSystemTypeTemporary;
- path = path.substr(strlen(kTemporaryDir));
- } else if (path.compare(0, strlen(kExternalDir), kExternalDir) == 0) {
- file_system_type = kFileSystemTypeExternal;
- path = path.substr(strlen(kExternalDir));
- } else {
- return false;
+
+ const struct {
+ FileSystemType type;
+ const char* dir;
+ } kValidTypes[] = {
+ { kFileSystemTypePersistent, kPersistentDir },
+ { kFileSystemTypeTemporary, kTemporaryDir },
+ { kFileSystemTypeIsolated, kIsolatedDir },
+ { kFileSystemTypeExternal, kExternalDir },
+ };
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kValidTypes); ++i) {
+ if (StartsWithASCII(path, kValidTypes[i].dir, true)) {
+ file_system_type = kValidTypes[i].type;
+ path = path.substr(strlen(kValidTypes[i].dir));
+ break;
+ }
}
+ if (file_system_type == kFileSystemTypeUnknown)
+ return false;
+
// Ensure the path is relative.
while (!path.empty() && path[0] == '/')
path.erase(0, 1);
@@ -143,18 +154,20 @@ GURL GetFileSystemRootURI(const GURL& origin_url, FileSystemType type) {
switch (type) {
case kFileSystemTypeTemporary:
path += (kTemporaryDir + 1); // We don't want the leading slash.
- break;
+ return GURL(path);
case kFileSystemTypePersistent:
path += (kPersistentDir + 1); // We don't want the leading slash.
- break;
+ return GURL(path);
case kFileSystemTypeExternal:
path += (kExternalDir + 1); // We don't want the leading slash.
- break;
- default:
+ return GURL(path);
+ case kFileSystemTypeIsolated:
+ // Falling through; we won't call this for isolated filesystems.
+ case kFileSystemTypeUnknown:
NOTREACHED();
- return GURL();
}
- return GURL(path);
+ NOTREACHED();
+ return GURL();
}
std::string GetFileSystemName(const GURL& origin_url, FileSystemType type) {
diff --git a/webkit/fileapi/file_system_util.h b/webkit/fileapi/file_system_util.h
index 730cc55..475565f 100644
--- a/webkit/fileapi/file_system_util.h
+++ b/webkit/fileapi/file_system_util.h
@@ -17,9 +17,11 @@ namespace fileapi {
extern const char kPersistentDir[];
extern const char kTemporaryDir[];
extern const char kExternalDir[];
+extern const char kIsolatedDir[];
extern const char kPersistentName[];
extern const char kTemporaryName[];
extern const char kExternalName[];
+extern const char kIsolatedName[];
// Cracks the given filesystem |url| and populates |origin_url|, |type|
// and |file_path|. Returns true if the given |url| is a valid filesystem
diff --git a/webkit/fileapi/isolated_context.cc b/webkit/fileapi/isolated_context.cc
index 64a3a02..61133f6 100644
--- a/webkit/fileapi/isolated_context.cc
+++ b/webkit/fileapi/isolated_context.cc
@@ -55,6 +55,7 @@ void IsolatedContext::RevokeIsolatedFileSystem(
bool IsolatedContext::CrackIsolatedPath(const FilePath& virtual_path,
std::string* filesystem_id,
+ FilePath* root_path,
FilePath* platform_path) const {
DCHECK(filesystem_id);
DCHECK(platform_path);
@@ -87,6 +88,8 @@ bool IsolatedContext::CrackIsolatedPath(const FilePath& virtual_path,
if (found == found_toplevels->second.end())
return false;
FilePath path = found->second;
+ if (root_path)
+ *root_path = path;
for (size_t i = 2; i < components.size(); ++i) {
path = path.Append(components[i]);
}
@@ -97,6 +100,7 @@ bool IsolatedContext::CrackIsolatedPath(const FilePath& virtual_path,
bool IsolatedContext::GetTopLevelPaths(std::string filesystem_id,
std::vector<FilePath>* paths) const {
DCHECK(paths);
+ base::AutoLock locker(lock_);
IDToPathMap::const_iterator found = toplevel_map_.find(filesystem_id);
if (found == toplevel_map_.end())
return false;
diff --git a/webkit/fileapi/isolated_context.h b/webkit/fileapi/isolated_context.h
index e9233c3..de4afda 100644
--- a/webkit/fileapi/isolated_context.h
+++ b/webkit/fileapi/isolated_context.h
@@ -56,14 +56,20 @@ class IsolatedContext {
// Cracks the given |virtual_path| (which should look like
// "/<filesystem_id>/<relative_path>") and populates the |filesystem_id|
- // and |platform_path| if the embedded <filesystem_id> is registered
- // to this context.
+ // and |platform_path| if the embedded <filesystem_id> is registerred
+ // to this context. |root_path| is also populated to have the platform
+ // root (toplevel) path for the |virtual_path|
+ // (i.e. |platform_path| = |root_path| + <relative_path>).
+ //
// Returns false if the given virtual_path or the cracked filesystem_id
// is not valid.
- // Note that |platform_path| is set to an empty path if |virtual_path| has no
- // <relative_path> part (i.e. pointing to the virtual root).
+ //
+ // Note that |root_path| and |platform_path| are set to empty paths if
+ // |virtual_path| has no <relative_path> part (i.e. pointing to
+ // the virtual root).
bool CrackIsolatedPath(const FilePath& virtual_path,
std::string* filesystem_id,
+ FilePath* root_path,
FilePath* platform_path) const;
// Returns a vector of the full paths of the top-level entry paths
@@ -73,8 +79,6 @@ class IsolatedContext {
std::vector<FilePath>* paths) const;
// Returns the virtual path that looks like /<filesystem_id>/<relative_path>.
- // This method is only used by the testing code (as the actual virtual path
- // in the real code is created in the renderer side).
FilePath CreateVirtualPath(const std::string& filesystem_id,
const FilePath& relative_path) const;
@@ -92,7 +96,7 @@ class IsolatedContext {
// Returns a new filesystem_id. Called with lock.
std::string GetNewFileSystemId() const;
- // This lock needs to be obtained when accessing the fileset_.
+ // This lock needs to be obtained when accessing the toplevel_map_.
mutable base::Lock lock_;
// Maps the toplevel entries to the filesystem id.
diff --git a/webkit/fileapi/isolated_context_unittest.cc b/webkit/fileapi/isolated_context_unittest.cc
index e32adef..5a828f5 100644
--- a/webkit/fileapi/isolated_context_unittest.cc
+++ b/webkit/fileapi/isolated_context_unittest.cc
@@ -77,11 +77,13 @@ TEST_F(IsolatedContextTest, RegisterAndRevokeTest) {
FilePath virtual_path = isolated_context()->CreateVirtualPath(
id_, kTestPaths[i].BaseName());
std::string cracked_id;
- FilePath cracked_path;
+ FilePath root_path, cracked_path;
ASSERT_TRUE(isolated_context()->CrackIsolatedPath(
- virtual_path, &cracked_id, &cracked_path));
+ virtual_path, &cracked_id, &root_path, &cracked_path));
ASSERT_EQ(kTestPaths[i].NormalizePathSeparators().value(),
cracked_path.value());
+ ASSERT_TRUE(fileset_.find(root_path.NormalizePathSeparators())
+ != fileset_.end());
ASSERT_EQ(id_, cracked_id);
}
@@ -123,14 +125,16 @@ TEST_F(IsolatedContextTest, CrackWithRelativePaths) {
FilePath virtual_path = isolated_context()->CreateVirtualPath(
id_, kTestPaths[i].BaseName().Append(relatives[j].path));
std::string cracked_id;
- FilePath cracked_path;
+ FilePath root_path, cracked_path;
if (!relatives[j].valid) {
ASSERT_FALSE(isolated_context()->CrackIsolatedPath(
- virtual_path, &cracked_id, &cracked_path));
+ virtual_path, &cracked_id, &root_path, &cracked_path));
continue;
}
ASSERT_TRUE(isolated_context()->CrackIsolatedPath(
- virtual_path, &cracked_id, &cracked_path));
+ virtual_path, &cracked_id, &root_path, &cracked_path));
+ ASSERT_TRUE(fileset_.find(root_path.NormalizePathSeparators())
+ != fileset_.end());
ASSERT_EQ(kTestPaths[i].Append(relatives[j].path)
.NormalizePathSeparators().value(),
cracked_path.value());
@@ -141,7 +145,7 @@ TEST_F(IsolatedContextTest, CrackWithRelativePaths) {
TEST_F(IsolatedContextTest, TestWithVirtualRoot) {
std::string cracked_id;
- FilePath cracked_path;
+ FilePath root_path, cracked_path;
const FilePath root(FPL("/"));
// Trying to crack virtual root "/" returns true but with empty cracked path
@@ -149,7 +153,7 @@ TEST_F(IsolatedContextTest, TestWithVirtualRoot) {
// that has no corresponding platform directory.
FilePath virtual_path = isolated_context()->CreateVirtualPath(id_, root);
ASSERT_TRUE(isolated_context()->CrackIsolatedPath(
- virtual_path, &cracked_id, &cracked_path));
+ virtual_path, &cracked_id, &root_path, &cracked_path));
ASSERT_EQ(FPL(""), cracked_path.value());
ASSERT_EQ(id_, cracked_id);
@@ -158,7 +162,7 @@ TEST_F(IsolatedContextTest, TestWithVirtualRoot) {
virtual_path = isolated_context()->CreateVirtualPath(
id_, FilePath(FPL("foo")));
ASSERT_FALSE(isolated_context()->CrackIsolatedPath(
- virtual_path, &cracked_id, &cracked_path));
+ virtual_path, &cracked_id, &root_path, &cracked_path));
}
} // namespace fileapi
diff --git a/webkit/fileapi/isolated_file_util.cc b/webkit/fileapi/isolated_file_util.cc
new file mode 100644
index 0000000..f699135
--- /dev/null
+++ b/webkit/fileapi/isolated_file_util.cc
@@ -0,0 +1,388 @@
+// 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.
+
+#include "webkit/fileapi/isolated_file_util.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "webkit/fileapi/file_system_context.h"
+#include "webkit/fileapi/file_system_operation_context.h"
+#include "webkit/fileapi/file_system_path.h"
+#include "webkit/fileapi/isolated_context.h"
+
+using base::PlatformFileError;
+using base::PlatformFileInfo;
+
+namespace fileapi {
+
+namespace {
+
+// Simply enumerate each path from a given paths set.
+// Used to enumerate top-level paths of an isolated filesystem.
+class SetFileEnumerator : public FileSystemFileUtil::AbstractFileEnumerator {
+ public:
+ SetFileEnumerator(FileSystemFileUtil* underlying_file_util,
+ const FileSystemOperationContext& context,
+ const std::vector<FilePath>& paths,
+ const FileSystemPath& root)
+ : underlying_file_util_(underlying_file_util),
+ context_(context),
+ paths_(paths),
+ root_(root) {
+ DCHECK(underlying_file_util_);
+ path_iter_ = paths_.begin();
+ }
+ virtual ~SetFileEnumerator() {}
+
+ // AbstractFileEnumerator overrides.
+ virtual FilePath Next() OVERRIDE {
+ if (path_iter_ == paths_.end())
+ return FilePath();
+ FilePath platform_path;
+ underlying_file_util_->GetFileInfo(
+ &context_, root_.WithInternalPath(*path_iter_++),
+ &file_info_, &platform_path);
+ return root_.internal_path().Append(platform_path.BaseName());
+ }
+ virtual int64 Size() OVERRIDE { return file_info_.size; }
+ virtual bool IsDirectory() OVERRIDE { return file_info_.is_directory; }
+ virtual base::Time LastModifiedTime() OVERRIDE {
+ return file_info_.last_modified;
+ }
+ virtual bool IsLink() OVERRIDE { return file_info_.is_symbolic_link; }
+
+ private:
+ // Not owned; Enumerator is instantiated only within methods of
+ // FileSystemFileUtil so it must be ok to assume the underlying_file_util
+ // is alive throughout the lifetime of the enumerator.
+ FileSystemFileUtil* underlying_file_util_;
+
+ FileSystemOperationContext context_;
+ std::vector<FilePath> paths_;
+ std::vector<FilePath>::const_iterator path_iter_;
+ FileSystemPath root_;
+ base::PlatformFileInfo file_info_;
+};
+
+// A wrapper file enumerator which returns a virtual path of the path returned
+// by the wrapped enumerator.
+//
+// A virtual path is constructed as following:
+// virtual_path = |virtual_base_path| + relative-path-to-|platform_base_path|
+//
+// Where |virtual_base_path| is in our case the virtual top-level directory
+// that looks like: '/<filesystem_id>'.
+//
+// Example:
+// Suppose virtual_base_path is: '/CAFEBABE',
+// platform_base_path is: '/full/path/to/example/dir', and
+// a path returned by wrapped_is: '/full/path/to/example/dir/a/b/c',
+// Next() would return: '/CAFEBABE/dir/a/b/c'.
+//
+class PathConverterEnumerator
+ : public FileSystemFileUtil::AbstractFileEnumerator {
+ public:
+ PathConverterEnumerator(
+ FileSystemFileUtil::AbstractFileEnumerator* wrapped,
+ const FilePath& virtual_base_path,
+ const FilePath& platform_base_path)
+ : wrapped_(wrapped),
+ virtual_base_path_(virtual_base_path),
+ platform_base_path_(platform_base_path) {}
+ virtual ~PathConverterEnumerator() {}
+
+ // AbstractFileEnumerator overrides.
+ virtual FilePath Next() OVERRIDE {
+ DCHECK(wrapped_.get());
+ FilePath path = wrapped_->Next();
+ if (path.empty())
+ return path;
+ FilePath virtual_path = virtual_base_path_;
+ platform_base_path_.DirName().AppendRelativePath(path, &virtual_path);
+ return virtual_path;
+ }
+ virtual int64 Size() OVERRIDE { return wrapped_->Size(); }
+ virtual bool IsDirectory() OVERRIDE { return wrapped_->IsDirectory(); }
+ virtual base::Time LastModifiedTime() OVERRIDE {
+ return wrapped_->LastModifiedTime();
+ }
+ virtual bool IsLink() OVERRIDE { return wrapped_->IsLink(); }
+
+ private:
+ scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator> wrapped_;
+ FilePath virtual_base_path_;
+ FilePath platform_base_path_;
+};
+
+// Recursively enumerate each path from a given paths set.
+class RecursiveSetFileEnumerator
+ : public FileSystemFileUtil::AbstractFileEnumerator {
+ public:
+ RecursiveSetFileEnumerator(FileSystemFileUtil* underlying_file_util,
+ const FileSystemOperationContext& context,
+ const FilePath& virtual_base_path,
+ const std::vector<FilePath>& paths,
+ const FileSystemPath& root)
+ : underlying_file_util_(underlying_file_util),
+ context_(context),
+ virtual_base_path_(virtual_base_path),
+ paths_(paths),
+ root_(root) {
+ DCHECK(underlying_file_util_);
+ path_iter_ = paths_.begin();
+ current_enumerator_.reset(
+ new SetFileEnumerator(underlying_file_util, context, paths, root));
+ }
+ virtual ~RecursiveSetFileEnumerator() {}
+
+ // AbstractFileEnumerator overrides.
+ virtual FilePath Next() OVERRIDE;
+ virtual int64 Size() OVERRIDE {
+ DCHECK(current_enumerator_.get());
+ return current_enumerator_->Size();
+ }
+ virtual bool IsDirectory() OVERRIDE {
+ DCHECK(current_enumerator_.get());
+ return current_enumerator_->IsDirectory();
+ }
+ virtual base::Time LastModifiedTime() OVERRIDE {
+ DCHECK(current_enumerator_.get());
+ return current_enumerator_->LastModifiedTime();
+ }
+ virtual bool IsLink() OVERRIDE {
+ DCHECK(current_enumerator_.get());
+ return current_enumerator_->IsLink();
+ }
+
+ private:
+ // Not owned.
+ FileSystemFileUtil* underlying_file_util_;
+
+ FileSystemOperationContext context_;
+ FilePath virtual_base_path_;
+ std::vector<FilePath> paths_;
+ std::vector<FilePath>::iterator path_iter_;
+ base::PlatformFileInfo file_info_;
+ FileSystemPath root_;
+ scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator> current_enumerator_;
+};
+
+FilePath RecursiveSetFileEnumerator::Next() {
+ if (current_enumerator_.get()) {
+ FilePath path = current_enumerator_->Next();
+ if (!path.empty())
+ return path;
+ }
+
+ // We reached the end.
+ if (path_iter_ == paths_.end())
+ return FilePath();
+
+ // Enumerates subdirectories of the next path.
+ FilePath next_path = *path_iter_++;
+ current_enumerator_.reset(
+ new PathConverterEnumerator(
+ underlying_file_util_->CreateFileEnumerator(
+ &context_, root_.WithInternalPath(next_path),
+ true /* recursive */),
+ virtual_base_path_, next_path));
+ DCHECK(current_enumerator_.get());
+ return current_enumerator_->Next();
+}
+
+} // namespace
+
+IsolatedFileUtil::IsolatedFileUtil(FileSystemFileUtil* underlying_file_util)
+ : FileSystemFileUtil(underlying_file_util) {
+ DCHECK(underlying_file_util);
+}
+
+PlatformFileError IsolatedFileUtil::CreateOrOpen(
+ FileSystemOperationContext* context,
+ const FileSystemPath& path, int file_flags,
+ PlatformFile* file_handle, bool* created) {
+ return base::PLATFORM_FILE_ERROR_SECURITY;
+}
+
+PlatformFileError IsolatedFileUtil::Close(
+ FileSystemOperationContext* context,
+ PlatformFile file_handle) {
+ // We don't allow open thus Close won't be called.
+ return base::PLATFORM_FILE_ERROR_SECURITY;
+}
+
+PlatformFileError IsolatedFileUtil::EnsureFileExists(
+ FileSystemOperationContext* context,
+ const FileSystemPath& path,
+ bool* created) {
+ return base::PLATFORM_FILE_ERROR_SECURITY;
+}
+
+PlatformFileError IsolatedFileUtil::CreateDirectory(
+ FileSystemOperationContext* context,
+ const FileSystemPath& path,
+ bool exclusive,
+ bool recursive) {
+ return base::PLATFORM_FILE_ERROR_SECURITY;
+}
+
+PlatformFileError IsolatedFileUtil::GetFileInfo(
+ FileSystemOperationContext* context,
+ const FileSystemPath& path,
+ PlatformFileInfo* file_info,
+ FilePath* platform_path) {
+ DCHECK(file_info);
+ std::string filesystem_id;
+ FilePath root_unused, cracked_path;
+ if (!IsolatedContext::GetInstance()->CrackIsolatedPath(
+ path.internal_path(), &filesystem_id, &root_unused, &cracked_path))
+ return base::PLATFORM_FILE_ERROR_SECURITY;
+ if (cracked_path.empty()) {
+ // The root directory case.
+ // For now we leave three time fields (modified/accessed/creation time)
+ // NULL as it is not really clear what to be set for this virtual directory.
+ // TODO(kinuko): Maybe we want to set the time when this filesystem is
+ // created (i.e. when the files/directories are dropped).
+ file_info->is_directory = true;
+ file_info->is_symbolic_link = false;
+ file_info->size = 0;
+ return base::PLATFORM_FILE_OK;
+ }
+ return underlying_file_util()->GetFileInfo(
+ context, path.WithInternalPath(cracked_path), file_info, platform_path);
+}
+
+FileSystemFileUtil::AbstractFileEnumerator*
+IsolatedFileUtil::CreateFileEnumerator(
+ FileSystemOperationContext* context,
+ const FileSystemPath& root,
+ bool recursive) {
+ std::string filesystem_id;
+ FilePath root_path, cracked_path;
+ if (!IsolatedContext::GetInstance()->CrackIsolatedPath(
+ root.internal_path(), &filesystem_id, &root_path, &cracked_path))
+ return NULL;
+
+ FilePath virtual_base_path =
+ IsolatedContext::GetInstance()->CreateVirtualPath(filesystem_id,
+ FilePath());
+
+ if (!cracked_path.empty()) {
+ return new PathConverterEnumerator(
+ underlying_file_util()->CreateFileEnumerator(
+ context, root.WithInternalPath(cracked_path), recursive),
+ virtual_base_path, root_path);
+ }
+
+ // Root path case.
+ std::vector<FilePath> toplevels;
+ IsolatedContext::GetInstance()->GetTopLevelPaths(filesystem_id, &toplevels);
+ if (!recursive)
+ return new SetFileEnumerator(underlying_file_util(), *context,
+ toplevels, root);
+ return new RecursiveSetFileEnumerator(underlying_file_util(), *context,
+ virtual_base_path, toplevels, root);
+}
+
+PlatformFileError IsolatedFileUtil::Touch(
+ FileSystemOperationContext* context,
+ const FileSystemPath& path,
+ const base::Time& last_access_time,
+ const base::Time& last_modified_time) {
+ return base::PLATFORM_FILE_ERROR_SECURITY;
+}
+
+PlatformFileError IsolatedFileUtil::Truncate(
+ FileSystemOperationContext* context,
+ const FileSystemPath& path,
+ int64 length) {
+ return base::PLATFORM_FILE_ERROR_SECURITY;
+}
+
+bool IsolatedFileUtil::PathExists(
+ FileSystemOperationContext* context,
+ const FileSystemPath& path) {
+ FilePath platform_path;
+ if (!GetPlatformPath(path, &platform_path))
+ return false;
+ if (platform_path.empty()) {
+ // The root directory case.
+ return true;
+ }
+ return underlying_file_util()->PathExists(
+ context, path.WithInternalPath(platform_path));
+}
+
+bool IsolatedFileUtil::DirectoryExists(
+ FileSystemOperationContext* context,
+ const FileSystemPath& path) {
+ FilePath platform_path;
+ if (!GetPlatformPath(path, &platform_path))
+ return false;
+ if (platform_path.empty()) {
+ // The root directory case.
+ return true;
+ }
+ return underlying_file_util()->DirectoryExists(
+ context, path.WithInternalPath(platform_path));
+}
+
+bool IsolatedFileUtil::IsDirectoryEmpty(
+ FileSystemOperationContext* context,
+ const FileSystemPath& path) {
+ std::string filesystem_id;
+ FilePath platform_path;
+ if (!GetPlatformPath(path, &platform_path))
+ return false;
+ if (platform_path.empty()) {
+ // The root directory case.
+ std::vector<FilePath> toplevels;
+ bool success = IsolatedContext::GetInstance()->GetTopLevelPaths(
+ filesystem_id, &toplevels);
+ DCHECK(success);
+ return toplevels.empty();
+ }
+ return underlying_file_util()->IsDirectoryEmpty(
+ context, path.WithInternalPath(platform_path));
+}
+
+PlatformFileError IsolatedFileUtil::CopyOrMoveFile(
+ FileSystemOperationContext* context,
+ const FileSystemPath& src_path,
+ const FileSystemPath& dest_path,
+ bool copy) {
+ return base::PLATFORM_FILE_ERROR_SECURITY;
+}
+
+PlatformFileError IsolatedFileUtil::CopyInForeignFile(
+ FileSystemOperationContext* context,
+ const FileSystemPath& src_path,
+ const FileSystemPath& dest_path) {
+ return base::PLATFORM_FILE_ERROR_SECURITY;
+}
+
+PlatformFileError IsolatedFileUtil::DeleteFile(
+ FileSystemOperationContext* context,
+ const FileSystemPath& path) {
+ return base::PLATFORM_FILE_ERROR_SECURITY;
+}
+
+PlatformFileError IsolatedFileUtil::DeleteSingleDirectory(
+ FileSystemOperationContext* context,
+ const FileSystemPath& path) {
+ return base::PLATFORM_FILE_ERROR_SECURITY;
+}
+
+bool IsolatedFileUtil::GetPlatformPath(const FileSystemPath& virtual_path,
+ FilePath* platform_path) const {
+ DCHECK(platform_path);
+ std::string filesystem_id;
+ FilePath root_path;
+ if (!IsolatedContext::GetInstance()->CrackIsolatedPath(
+ virtual_path.internal_path(), &filesystem_id,
+ &root_path, platform_path))
+ return false;
+ return true;
+}
+
+} // namespace
diff --git a/webkit/fileapi/isolated_file_util.h b/webkit/fileapi/isolated_file_util.h
new file mode 100644
index 0000000..d49c6ac
--- /dev/null
+++ b/webkit/fileapi/isolated_file_util.h
@@ -0,0 +1,98 @@
+// 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_FILEAPI_ISOLATED_FILE_UTIL_H_
+#define WEBKIT_FILEAPI_ISOLATED_FILE_UTIL_H_
+
+#include "base/file_path.h"
+#include "base/file_util_proxy.h"
+#include "base/platform_file.h"
+#include "webkit/fileapi/file_system_file_util.h"
+
+namespace base {
+class Time;
+}
+
+namespace fileapi {
+
+class FileSystemOperationContext;
+class IsolatedContext;
+
+class IsolatedFileUtil : public FileSystemFileUtil {
+ public:
+ IsolatedFileUtil(FileSystemFileUtil* underlying_file_util);
+ virtual ~IsolatedFileUtil() {}
+
+ // FileSystemFileUtil overrides.
+ virtual base::PlatformFileError CreateOrOpen(
+ FileSystemOperationContext* context,
+ const FileSystemPath& path,
+ int file_flags,
+ base::PlatformFile* file_handle,
+ bool* created) OVERRIDE;
+ virtual base::PlatformFileError Close(
+ FileSystemOperationContext* context,
+ base::PlatformFile) OVERRIDE;
+ virtual base::PlatformFileError EnsureFileExists(
+ FileSystemOperationContext* context,
+ const FileSystemPath& path, bool* created) OVERRIDE;
+ virtual base::PlatformFileError CreateDirectory(
+ FileSystemOperationContext* context,
+ const FileSystemPath& path,
+ bool exclusive,
+ bool recursive) OVERRIDE;
+ virtual base::PlatformFileError GetFileInfo(
+ FileSystemOperationContext* context,
+ const FileSystemPath& path,
+ base::PlatformFileInfo* file_info,
+ FilePath* platform_path) OVERRIDE;
+ virtual AbstractFileEnumerator* CreateFileEnumerator(
+ FileSystemOperationContext* context,
+ const FileSystemPath& root_path,
+ bool recursive) OVERRIDE;
+ virtual base::PlatformFileError Touch(
+ FileSystemOperationContext* context,
+ const FileSystemPath& path,
+ const base::Time& last_access_time,
+ const base::Time& last_modified_time) OVERRIDE;
+ virtual base::PlatformFileError Truncate(
+ FileSystemOperationContext* context,
+ const FileSystemPath& path,
+ int64 length) OVERRIDE;
+ virtual bool PathExists(
+ FileSystemOperationContext* context,
+ const FileSystemPath& path) OVERRIDE;
+ virtual bool DirectoryExists(
+ FileSystemOperationContext* context,
+ const FileSystemPath& path) OVERRIDE;
+ virtual bool IsDirectoryEmpty(
+ FileSystemOperationContext* context,
+ const FileSystemPath& path) OVERRIDE;
+ virtual base::PlatformFileError CopyOrMoveFile(
+ FileSystemOperationContext* context,
+ const FileSystemPath& src_path,
+ const FileSystemPath& dest_path,
+ bool copy) OVERRIDE;
+ virtual base::PlatformFileError CopyInForeignFile(
+ FileSystemOperationContext* context,
+ const FileSystemPath& underlying_src_path,
+ const FileSystemPath& dest_path) OVERRIDE;
+ virtual base::PlatformFileError DeleteFile(
+ FileSystemOperationContext* context,
+ const FileSystemPath& path) OVERRIDE;
+ virtual base::PlatformFileError DeleteSingleDirectory(
+ FileSystemOperationContext* context,
+ const FileSystemPath& path) OVERRIDE;
+
+ private:
+ // Returns false if the given |virtual_path| is not a valid path.
+ bool GetPlatformPath(const FileSystemPath& virtual_path,
+ FilePath* platform_path) const;
+
+ DISALLOW_COPY_AND_ASSIGN(IsolatedFileUtil);
+};
+
+} // namespace fileapi
+
+#endif // WEBKIT_FILEAPI_ISOLATED_FILE_UTIL_H_
diff --git a/webkit/fileapi/isolated_file_util_unittest.cc b/webkit/fileapi/isolated_file_util_unittest.cc
new file mode 100644
index 0000000..a422ff9
--- /dev/null
+++ b/webkit/fileapi/isolated_file_util_unittest.cc
@@ -0,0 +1,432 @@
+// 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.
+
+#include <string>
+
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/message_loop_proxy.h"
+#include "base/scoped_temp_dir.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/fileapi/file_system_context.h"
+#include "webkit/fileapi/file_system_operation_context.h"
+#include "webkit/fileapi/file_system_test_helper.h"
+#include "webkit/fileapi/file_util_helper.h"
+#include "webkit/fileapi/isolated_context.h"
+#include "webkit/fileapi/isolated_file_util.h"
+#include "webkit/fileapi/local_file_util.h"
+#include "webkit/fileapi/mock_file_system_options.h"
+#include "webkit/fileapi/native_file_util.h"
+#include "webkit/fileapi/test_file_set.h"
+#include "webkit/quota/mock_special_storage_policy.h"
+
+using file_util::FileEnumerator;
+
+namespace fileapi {
+
+namespace {
+
+// Used in IsolatedFileUtilTest::SimulateDropFiles().
+// Random root paths in which we create each file/directory of the
+// RegularTestCases (so that we can simulate a drop with files/directories
+// from multiple directories).
+static const FilePath::CharType* kRootPaths[] = {
+ FILE_PATH_LITERAL("a"),
+ FILE_PATH_LITERAL("b/c"),
+ FILE_PATH_LITERAL("etc"),
+};
+
+FilePath GetTopLevelPath(const FilePath& path) {
+ std::vector<FilePath::StringType> components;
+ path.GetComponents(&components);
+ return FilePath(components[0]);
+}
+
+} // namespace
+
+class IsolatedFileUtilTest : public testing::Test {
+ public:
+ IsolatedFileUtilTest() {}
+
+ void SetUp() {
+ ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
+ file_util_.reset(new IsolatedFileUtil(new NativeFileUtil()));
+
+ // Register the files/directories of RegularTestCases (with random
+ // root paths) as dropped files.
+ SimulateDropFiles();
+
+ file_system_context_ = new FileSystemContext(
+ base::MessageLoopProxy::current(),
+ base::MessageLoopProxy::current(),
+ new quota::MockSpecialStoragePolicy(),
+ NULL /* quota_manager */,
+ data_dir_.path(),
+ CreateAllowFileAccessOptions());
+
+ // For cross-FileUtil copy/move tests.
+ other_file_util_.reset(new LocalFileUtil(new NativeFileUtil()));
+ other_file_util_helper_.SetUp(file_system_context_, other_file_util_.get());
+ }
+
+ void TearDown() {
+ isolated_context()->RevokeIsolatedFileSystem(filesystem_id_);
+ other_file_util_helper_.TearDown();
+ }
+
+ protected:
+ IsolatedContext* isolated_context() const {
+ return IsolatedContext::GetInstance();
+ }
+ const FilePath& root_path() const {
+ return data_dir_.path();
+ }
+ FileSystemContext* file_system_context() const {
+ return file_system_context_.get();
+ }
+ FileSystemFileUtil* file_util() const { return file_util_.get(); }
+ FileSystemFileUtil* other_file_util() const { return other_file_util_.get(); }
+ std::string filesystem_id() const { return filesystem_id_; }
+
+ FilePath GetTestCasePlatformPath(const FilePath::StringType& path) {
+ return toplevel_root_map_[GetTopLevelPath(FilePath(path))].Append(path).
+ NormalizePathSeparators();
+ }
+
+ FileSystemPath GetFileSystemPath(const FilePath& path) const {
+ FilePath virtual_path = isolated_context()->CreateVirtualPath(
+ filesystem_id(), path);
+ return FileSystemPath(GURL("http://example.com"),
+ kFileSystemTypeIsolated,
+ virtual_path);
+ }
+
+ FileSystemPath GetOtherFileSystemPath(const FilePath& path) {
+ return other_file_util_helper_.CreatePath(path);
+ }
+
+ void VerifyFilesHaveSameContent(FileSystemFileUtil* file_util1,
+ FileSystemFileUtil* file_util2,
+ const FileSystemPath& path1,
+ const FileSystemPath& path2) {
+ scoped_ptr<FileSystemOperationContext> context;
+
+ // Get the file info for path1.
+ base::PlatformFileInfo info1;
+ FilePath platform_path1;
+ context.reset(new FileSystemOperationContext(file_system_context()));
+ ASSERT_EQ(base::PLATFORM_FILE_OK,
+ file_util1->GetFileInfo(context.get(), path1,
+ &info1, &platform_path1));
+
+ // Get the file info for path2.
+ base::PlatformFileInfo info2;
+ FilePath platform_path2;
+ context.reset(new FileSystemOperationContext(file_system_context()));
+ ASSERT_EQ(base::PLATFORM_FILE_OK,
+ file_util2->GetFileInfo(context.get(), path2,
+ &info2, &platform_path2));
+
+ // See if file info matches with the other one.
+ EXPECT_EQ(info1.is_directory, info2.is_directory);
+ EXPECT_EQ(info1.size, info2.size);
+ EXPECT_EQ(info1.is_symbolic_link, info2.is_symbolic_link);
+ EXPECT_NE(platform_path1, platform_path2);
+
+ std::string content1, content2;
+ EXPECT_TRUE(file_util::ReadFileToString(platform_path1, &content1));
+ EXPECT_TRUE(file_util::ReadFileToString(platform_path2, &content2));
+ EXPECT_EQ(content1, content2);
+ }
+
+ void VerifyDirectoriesHaveSameContent(FileSystemFileUtil* file_util1,
+ FileSystemFileUtil* file_util2,
+ const FileSystemPath& root1,
+ const FileSystemPath& root2) {
+ scoped_ptr<FileSystemOperationContext> context;
+
+ scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator> file_enum1;
+ context.reset(new FileSystemOperationContext(file_system_context()));
+ file_enum1.reset(file_util1->CreateFileEnumerator(
+ context.get(), root1, true /* recursive */));
+
+ FilePath current;
+ std::set<FilePath> file_set1;
+ while (!(current = file_enum1->Next()).empty()) {
+ if (file_enum1->IsDirectory())
+ continue;
+ file_set1.insert(current);
+ }
+
+ scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator> file_enum2;
+ context.reset(new FileSystemOperationContext(file_system_context()));
+ file_enum2.reset(file_util2->CreateFileEnumerator(
+ context.get(), root2, true /* recursive */));
+
+ while (!(current = file_enum2->Next()).empty()) {
+ FileSystemPath path1 = root1.WithInternalPath(current);
+ FileSystemPath path2 = root2.WithInternalPath(current);
+ if (file_enum2->IsDirectory()) {
+ FileSystemOperationContext context1(file_system_context());
+ FileSystemOperationContext context2(file_system_context());
+ EXPECT_EQ(file_util1->IsDirectoryEmpty(&context1, path1),
+ file_util2->IsDirectoryEmpty(&context2, path2));
+ continue;
+ }
+ EXPECT_TRUE(file_set1.find(current) != file_set1.end());
+ VerifyFilesHaveSameContent(file_util1, file_util2, path1, path2);
+ }
+ }
+
+ private:
+ void SimulateDropFiles() {
+ size_t root_path_index = 0;
+
+ std::set<FilePath> toplevels;
+ for (size_t i = 0; i < test::kRegularTestCaseSize; ++i) {
+ const test::TestCaseRecord& test_case = test::kRegularTestCases[i];
+ FilePath path(test_case.path);
+ FilePath toplevel = GetTopLevelPath(path);
+
+ // We create the test case files under one of the kRootPaths
+ // to simulate a drop with multiple directories.
+ if (toplevel_root_map_.find(toplevel) == toplevel_root_map_.end()) {
+ FilePath root = root_path().Append(
+ kRootPaths[(root_path_index++) % arraysize(kRootPaths)]);
+ toplevel_root_map_[toplevel] = root;
+ toplevels.insert(root.Append(path));
+ }
+
+ test::SetUpOneTestCase(toplevel_root_map_[toplevel], test_case);
+ }
+
+ // Register the toplevel entries.
+ filesystem_id_ = isolated_context()->RegisterIsolatedFileSystem(toplevels);
+ }
+
+ ScopedTempDir data_dir_;
+ std::string filesystem_id_;
+ scoped_refptr<FileSystemContext> file_system_context_;
+ std::map<FilePath, FilePath> toplevel_root_map_;
+ scoped_ptr<IsolatedFileUtil> file_util_;
+ scoped_ptr<LocalFileUtil> other_file_util_;
+ FileSystemTestOriginHelper other_file_util_helper_;
+ DISALLOW_COPY_AND_ASSIGN(IsolatedFileUtilTest);
+};
+
+TEST_F(IsolatedFileUtilTest, BasicTest) {
+ for (size_t i = 0; i < test::kRegularTestCaseSize; ++i) {
+ SCOPED_TRACE(testing::Message() << "Testing RegularTestCases " << i);
+ const test::TestCaseRecord& test_case = test::kRegularTestCases[i];
+
+ FileSystemPath path = GetFileSystemPath(FilePath(test_case.path));
+
+ // See if we can query the file info via the isolated FileUtil.
+ // (This should succeed since we have registered all the top-level
+ // entries of the test cases in SetUp())
+ base::PlatformFileInfo info;
+ FilePath platform_path;
+ FileSystemOperationContext context(file_system_context());
+ ASSERT_EQ(base::PLATFORM_FILE_OK,
+ file_util()->GetFileInfo(&context, path, &info, &platform_path));
+
+ // See if the obtained file info is correct.
+ if (!test_case.is_directory)
+ ASSERT_EQ(test_case.data_file_size, info.size);
+ ASSERT_EQ(test_case.is_directory, info.is_directory);
+ ASSERT_EQ(GetTestCasePlatformPath(test_case.path),
+ platform_path.NormalizePathSeparators());
+ }
+}
+
+TEST_F(IsolatedFileUtilTest, UnregisteredPathsTest) {
+ static const fileapi::test::TestCaseRecord kUnregisteredCases[] = {
+ {true, FILE_PATH_LITERAL("nonexistent"), 0},
+ {true, FILE_PATH_LITERAL("nonexistent/dir foo"), 0},
+ {false, FILE_PATH_LITERAL("nonexistent/false"), 0},
+ {false, FILE_PATH_LITERAL("foo"), 30},
+ {false, FILE_PATH_LITERAL("bar"), 20},
+ };
+
+ for (size_t i = 0; i < arraysize(kUnregisteredCases); ++i) {
+ SCOPED_TRACE(testing::Message() << "Creating kUnregisteredCases " << i);
+ const test::TestCaseRecord& test_case = kUnregisteredCases[i];
+
+ // Prepare the test file/directory.
+ SetUpOneTestCase(root_path(), test_case);
+
+ // Make sure regular GetFileInfo succeeds.
+ base::PlatformFileInfo info;
+ ASSERT_TRUE(file_util::GetFileInfo(
+ root_path().Append(test_case.path), &info));
+ if (!test_case.is_directory)
+ ASSERT_EQ(test_case.data_file_size, info.size);
+ ASSERT_EQ(test_case.is_directory, info.is_directory);
+ }
+
+ for (size_t i = 0; i < arraysize(kUnregisteredCases); ++i) {
+ SCOPED_TRACE(testing::Message() << "Creating kUnregisteredCases " << i);
+ const test::TestCaseRecord& test_case = kUnregisteredCases[i];
+ FileSystemPath path = GetFileSystemPath(FilePath(test_case.path));
+
+ // This should fail as the paths in kUnregisteredCases are not included
+ // in the dropped files (i.e. the regular test cases).
+ base::PlatformFileInfo info;
+ FilePath platform_path;
+ FileSystemOperationContext context(file_system_context());
+ ASSERT_EQ(base::PLATFORM_FILE_ERROR_SECURITY,
+ file_util()->GetFileInfo(&context, path, &info, &platform_path));
+ }
+}
+
+TEST_F(IsolatedFileUtilTest, ReadDirectoryTest) {
+ for (size_t i = 0; i < test::kRegularTestCaseSize; ++i) {
+ const test::TestCaseRecord& test_case = test::kRegularTestCases[i];
+ if (!test_case.is_directory)
+ continue;
+
+ SCOPED_TRACE(testing::Message() << "Testing RegularTestCases " << i
+ << ": " << test_case.path);
+
+ // Read entries in the directory to construct the expected results map.
+ typedef std::map<FilePath::StringType, base::FileUtilProxy::Entry> EntryMap;
+ EntryMap expected_entry_map;
+
+ FileEnumerator file_enum(
+ GetTestCasePlatformPath(test_case.path),
+ false /* recursive */,
+ static_cast<file_util::FileEnumerator::FileType>(
+ FileEnumerator::FILES | FileEnumerator::DIRECTORIES));
+ FilePath current;
+ while (!(current = file_enum.Next()).empty()) {
+ FileEnumerator::FindInfo file_info;
+ file_enum.GetFindInfo(&file_info);
+ base::FileUtilProxy::Entry entry;
+ entry.is_directory = FileEnumerator::IsDirectory(file_info);
+ entry.name = current.BaseName().value();
+ entry.size = FileEnumerator::GetFilesize(file_info);
+ entry.last_modified_time = FileEnumerator::GetLastModifiedTime(file_info);
+ expected_entry_map[entry.name] = entry;
+ }
+
+ // Perform ReadDirectory in the isolated filesystem.
+ FileSystemPath path = GetFileSystemPath(FilePath(test_case.path));
+ std::vector<base::FileUtilProxy::Entry> entries;
+ FileSystemOperationContext context(file_system_context());
+ ASSERT_EQ(base::PLATFORM_FILE_OK,
+ FileUtilHelper::ReadDirectory(
+ &context, file_util(), path, &entries));
+
+ EXPECT_EQ(expected_entry_map.size(), entries.size());
+ for (size_t i = 0; i < entries.size(); ++i) {
+ const base::FileUtilProxy::Entry& entry = entries[i];
+ EntryMap::iterator found = expected_entry_map.find(entry.name);
+ EXPECT_TRUE(found != expected_entry_map.end());
+ EXPECT_EQ(found->second.name, entry.name);
+ EXPECT_EQ(found->second.is_directory, entry.is_directory);
+ EXPECT_EQ(found->second.size, entry.size);
+ EXPECT_EQ(found->second.last_modified_time.ToDoubleT(),
+ entry.last_modified_time.ToDoubleT());
+ }
+ }
+}
+
+TEST_F(IsolatedFileUtilTest, CopyOutFileTest) {
+ scoped_ptr<FileSystemOperationContext> context(
+ new FileSystemOperationContext(file_system_context()));
+ FileSystemPath root_path = GetFileSystemPath(FilePath());
+ scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator> file_enum(
+ file_util()->CreateFileEnumerator(context.get(),
+ root_path,
+ true /* recursive */));
+ FilePath current;
+ while (!(current = file_enum->Next()).empty()) {
+ if (file_enum->IsDirectory())
+ continue;
+
+ SCOPED_TRACE(testing::Message() << "Testing file copy "
+ << current.value());
+
+ FileSystemPath src_path = root_path.WithInternalPath(current);
+ FileSystemPath dest_path = GetOtherFileSystemPath(current);
+
+ // Create the parent directory of the destination.
+ context.reset(new FileSystemOperationContext(file_system_context()));
+ ASSERT_EQ(base::PLATFORM_FILE_OK,
+ other_file_util()->CreateDirectory(
+ context.get(),
+ GetOtherFileSystemPath(current.DirName()),
+ false /* exclusive */,
+ true /* recursive */));
+
+ context.reset(new FileSystemOperationContext(file_system_context()));
+ ASSERT_EQ(base::PLATFORM_FILE_OK,
+ FileUtilHelper::Copy(
+ context.get(),
+ file_util(), other_file_util(),
+ src_path, dest_path));
+
+ // The other way (copy-in) should not work.
+ context.reset(new FileSystemOperationContext(file_system_context()));
+ ASSERT_EQ(base::PLATFORM_FILE_ERROR_SECURITY,
+ FileUtilHelper::Copy(
+ context.get(),
+ other_file_util(), file_util(),
+ dest_path, src_path));
+
+ VerifyFilesHaveSameContent(file_util(), other_file_util(),
+ src_path, dest_path);
+ }
+}
+
+TEST_F(IsolatedFileUtilTest, CopyOutDirectoryTest) {
+ scoped_ptr<FileSystemOperationContext> context(
+ new FileSystemOperationContext(file_system_context()));
+ FileSystemPath root_path = GetFileSystemPath(FilePath());
+ scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator> file_enum(
+ file_util()->CreateFileEnumerator(context.get(),
+ root_path,
+ false /* recursive */));
+ FilePath current;
+ while (!(current = file_enum->Next()).empty()) {
+ if (!file_enum->IsDirectory())
+ continue;
+
+ SCOPED_TRACE(testing::Message() << "Testing directory copy "
+ << current.value());
+
+ FileSystemPath src_path = root_path.WithInternalPath(current);
+ FileSystemPath dest_path = GetOtherFileSystemPath(current);
+
+ // Create the parent directory of the destination.
+ context.reset(new FileSystemOperationContext(file_system_context()));
+ ASSERT_EQ(base::PLATFORM_FILE_OK,
+ other_file_util()->CreateDirectory(
+ context.get(),
+ GetOtherFileSystemPath(current.DirName()),
+ false /* exclusive */,
+ true /* recursive */));
+
+ context.reset(new FileSystemOperationContext(file_system_context()));
+ ASSERT_EQ(base::PLATFORM_FILE_OK,
+ FileUtilHelper::Copy(
+ context.get(),
+ file_util(), other_file_util(),
+ src_path, dest_path));
+
+ // The other way (copy-in) should not work for two reasons:
+ // write is prohibited in the isolated filesystem, and copying directory
+ // to non-empty directory shouldn't work.
+ context.reset(new FileSystemOperationContext(file_system_context()));
+ base::PlatformFileError result = FileUtilHelper::Copy(
+ context.get(), other_file_util(), file_util(), dest_path, src_path);
+ ASSERT_TRUE(result == base::PLATFORM_FILE_ERROR_FAILED ||
+ result == base::PLATFORM_FILE_ERROR_NOT_EMPTY);
+
+ VerifyDirectoriesHaveSameContent(file_util(), other_file_util(),
+ src_path, dest_path);
+ }
+}
+
+} // namespace fileapi
diff --git a/webkit/fileapi/isolated_mount_point_provider.cc b/webkit/fileapi/isolated_mount_point_provider.cc
new file mode 100644
index 0000000..e05833c
--- /dev/null
+++ b/webkit/fileapi/isolated_mount_point_provider.cc
@@ -0,0 +1,102 @@
+// 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.
+
+#include "webkit/fileapi/isolated_mount_point_provider.h"
+
+#include "base/bind.h"
+#include "base/file_path.h"
+#include "base/logging.h"
+#include "base/message_loop_proxy.h"
+#include "googleurl/src/gurl.h"
+#include "webkit/fileapi/file_system_callback_dispatcher.h"
+#include "webkit/fileapi/file_system_operation.h"
+#include "webkit/fileapi/file_system_types.h"
+#include "webkit/fileapi/isolated_context.h"
+#include "webkit/fileapi/isolated_file_util.h"
+#include "webkit/fileapi/native_file_util.h"
+
+namespace fileapi {
+
+IsolatedMountPointProvider::IsolatedMountPointProvider()
+ : isolated_file_util_(new IsolatedFileUtil(new NativeFileUtil())) {
+}
+
+IsolatedMountPointProvider::~IsolatedMountPointProvider() {
+}
+
+void IsolatedMountPointProvider::ValidateFileSystemRoot(
+ const GURL& origin_url,
+ FileSystemType type,
+ bool create,
+ const ValidateFileSystemCallback& callback) {
+ // We never allow opening a new isolated FileSystem via usual OpenFileSystem.
+ base::MessageLoopProxy::current()->PostTask(
+ FROM_HERE,
+ base::Bind(callback, base::PLATFORM_FILE_ERROR_SECURITY));
+}
+
+FilePath IsolatedMountPointProvider::GetFileSystemRootPathOnFileThread(
+ const GURL& origin_url,
+ FileSystemType type,
+ const FilePath& virtual_path,
+ bool create) {
+ if (create || type != kFileSystemTypeIsolated)
+ return FilePath();
+ std::string fsid;
+ FilePath root, path;
+ if (!isolated_context()->CrackIsolatedPath(virtual_path, &fsid, &root, &path))
+ return FilePath();
+ return root;
+}
+
+bool IsolatedMountPointProvider::IsAccessAllowed(
+ const GURL& origin_url, FileSystemType type, const FilePath& virtual_path) {
+ if (type != fileapi::kFileSystemTypeIsolated)
+ return false;
+
+ std::string filesystem_id;
+ FilePath root, path;
+ return isolated_context()->CrackIsolatedPath(
+ virtual_path, &filesystem_id, &root, &path);
+}
+
+bool IsolatedMountPointProvider::IsRestrictedFileName(
+ const FilePath& filename) const {
+ return false;
+}
+
+std::vector<FilePath> IsolatedMountPointProvider::GetRootDirectories() const {
+ // We have no pre-defined root directories that need to be given
+ // access permission.
+ return std::vector<FilePath>();
+}
+
+FileSystemFileUtil* IsolatedMountPointProvider::GetFileUtil() {
+ return isolated_file_util_.get();
+}
+
+FilePath IsolatedMountPointProvider::GetPathForPermissionsCheck(
+ const FilePath& virtual_path) const {
+ std::string fsid;
+ FilePath root, path;
+ if (!isolated_context()->CrackIsolatedPath(virtual_path, &fsid, &root, &path))
+ return FilePath();
+ return path;
+}
+
+FileSystemOperationInterface*
+IsolatedMountPointProvider::CreateFileSystemOperation(
+ const GURL& origin_url,
+ FileSystemType file_system_type,
+ const FilePath& virtual_path,
+ base::MessageLoopProxy* file_proxy,
+ FileSystemContext* context) const {
+ return new FileSystemOperation(file_proxy, context);
+}
+
+IsolatedContext* IsolatedMountPointProvider::isolated_context() const {
+ return IsolatedContext::GetInstance();
+}
+
+} // namespace fileapi
diff --git a/webkit/fileapi/isolated_mount_point_provider.h b/webkit/fileapi/isolated_mount_point_provider.h
new file mode 100644
index 0000000..3784b40
--- /dev/null
+++ b/webkit/fileapi/isolated_mount_point_provider.h
@@ -0,0 +1,57 @@
+// 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_FILEAPI_ISOLATED_MOUNT_POINT_PROVIDER_H_
+#define WEBKIT_FILEAPI_ISOLATED_MOUNT_POINT_PROVIDER_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "webkit/fileapi/file_system_mount_point_provider.h"
+
+namespace fileapi {
+
+class IsolatedContext;
+
+class IsolatedMountPointProvider : public FileSystemMountPointProvider {
+ public:
+ typedef FileSystemMountPointProvider::ValidateFileSystemCallback
+ ValidateFileSystemCallback;
+
+ IsolatedMountPointProvider();
+ virtual ~IsolatedMountPointProvider();
+
+ // FileSystemMountPointProvider implementation.
+ virtual void ValidateFileSystemRoot(
+ const GURL& origin_url,
+ FileSystemType type,
+ bool create,
+ const ValidateFileSystemCallback& callback) OVERRIDE;
+ virtual FilePath GetFileSystemRootPathOnFileThread(
+ const GURL& origin_url,
+ FileSystemType type,
+ const FilePath& virtual_path,
+ bool create) OVERRIDE;
+ virtual bool IsAccessAllowed(const GURL& origin_url,
+ FileSystemType type,
+ const FilePath& virtual_path) OVERRIDE;
+ virtual bool IsRestrictedFileName(const FilePath& filename) const OVERRIDE;
+ virtual std::vector<FilePath> GetRootDirectories() const OVERRIDE;
+ virtual FileSystemFileUtil* GetFileUtil() OVERRIDE;
+ virtual FilePath GetPathForPermissionsCheck(const FilePath& virtual_path)
+ const OVERRIDE;
+ virtual FileSystemOperationInterface* CreateFileSystemOperation(
+ const GURL& origin_url,
+ FileSystemType file_system_type,
+ const FilePath& virtual_path,
+ base::MessageLoopProxy* file_proxy,
+ FileSystemContext* context) const OVERRIDE;
+
+ private:
+ IsolatedContext* isolated_context() const;
+
+ scoped_ptr<FileSystemFileUtil> isolated_file_util_;
+};
+
+} // namespace fileapi
+
+#endif // WEBKIT_FILEAPI_ISOLATED_MOUNT_POINT_PROVIDER_H_
diff --git a/webkit/fileapi/test_file_set.cc b/webkit/fileapi/test_file_set.cc
index badb7fb..995ab6f 100644
--- a/webkit/fileapi/test_file_set.cc
+++ b/webkit/fileapi/test_file_set.cc
@@ -7,6 +7,7 @@
#include "base/file_util.h"
#include "base/logging.h"
#include "base/platform_file.h"
+#include "base/rand_util.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace fileapi {
@@ -15,7 +16,7 @@ namespace test {
const TestCaseRecord kRegularTestCases[] = {
{true, FILE_PATH_LITERAL("dir a"), 0},
- {true, FILE_PATH_LITERAL("dir a/dir a"), 0},
+ {true, FILE_PATH_LITERAL("dir a/dir A"), 0},
{true, FILE_PATH_LITERAL("dir a/dir d"), 0},
{true, FILE_PATH_LITERAL("dir a/dir d/dir e"), 0},
{true, FILE_PATH_LITERAL("dir a/dir d/dir e/dir f"), 0},
@@ -41,18 +42,22 @@ void SetUpOneTestCase(const FilePath& root_path,
FilePath path = root_path.Append(test_case.path);
if (test_case.is_directory) {
ASSERT_TRUE(file_util::CreateDirectory(path));
- } else {
- base::PlatformFileError error_code;
- bool created = false;
- int file_flags = base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_WRITE;
- base::PlatformFile file_handle =
- base::CreatePlatformFile(path, file_flags, &created, &error_code);
- EXPECT_TRUE(created);
- ASSERT_NE(base::kInvalidPlatformFileValue, file_handle);
- ASSERT_EQ(base::PLATFORM_FILE_OK, error_code);
- ASSERT_TRUE(
- base::TruncatePlatformFile(file_handle, test_case.data_file_size));
- EXPECT_TRUE(base::ClosePlatformFile(file_handle));
+ return;
+ }
+ base::PlatformFileError error_code;
+ bool created = false;
+ int file_flags = base::PLATFORM_FILE_CREATE_ALWAYS |
+ base::PLATFORM_FILE_WRITE;
+ base::PlatformFile file_handle =
+ base::CreatePlatformFile(path, file_flags, &created, &error_code);
+ EXPECT_TRUE(created);
+ ASSERT_EQ(base::PLATFORM_FILE_OK, error_code);
+ ASSERT_NE(base::kInvalidPlatformFileValue, file_handle);
+ EXPECT_TRUE(base::ClosePlatformFile(file_handle));
+ if (test_case.data_file_size > 0U) {
+ std::string content = base::RandBytesAsString(test_case.data_file_size);
+ ASSERT_EQ(static_cast<int>(content.size()),
+ file_util::WriteFile(path, content.data(), content.size()));
}
}
diff --git a/webkit/fileapi/webkit_fileapi.gypi b/webkit/fileapi/webkit_fileapi.gypi
index 4ac71cf..195f187 100644
--- a/webkit/fileapi/webkit_fileapi.gypi
+++ b/webkit/fileapi/webkit_fileapi.gypi
@@ -58,6 +58,10 @@
'file_writer_delegate.h',
'isolated_context.cc',
'isolated_context.h',
+ 'isolated_file_util.cc',
+ 'isolated_file_util.h',
+ 'isolated_mount_point_provider.cc',
+ 'isolated_mount_point_provider.h',
'local_file_util.cc',
'local_file_util.h',
'native_file_util.cc',
diff --git a/webkit/glue/webdropdata.cc b/webkit/glue/webdropdata.cc
index 43323f8..02a0a94 100644
--- a/webkit/glue/webdropdata.cc
+++ b/webkit/glue/webdropdata.cc
@@ -124,9 +124,6 @@ WebDragData WebDropData::ToDragData() const {
WebDragData result;
result.initialize();
result.setItems(item_list);
-#ifdef WEBKIT_DRAG_DROP_SUPPORT_FILESYSTEM
- // TODO(kinuko): remove this ifdef once we update the WebKit API.
result.setFilesystemId(filesystem_id);
-#endif
return result;
}
diff --git a/webkit/tools/test_shell/test_shell.gypi b/webkit/tools/test_shell/test_shell.gypi
index 5358649..354ac6e 100644
--- a/webkit/tools/test_shell/test_shell.gypi
+++ b/webkit/tools/test_shell/test_shell.gypi
@@ -419,6 +419,7 @@
'../../fileapi/file_system_usage_cache_unittest.cc',
'../../fileapi/file_system_util_unittest.cc',
'../../fileapi/isolated_context_unittest.cc',
+ '../../fileapi/isolated_file_util_unittest.cc',
'../../fileapi/local_file_util_unittest.cc',
'../../fileapi/mock_file_system_options.cc',
'../../fileapi/mock_file_system_options.h',