summaryrefslogtreecommitdiffstats
path: root/webkit/fileapi
diff options
context:
space:
mode:
Diffstat (limited to 'webkit/fileapi')
-rw-r--r--webkit/fileapi/file_system_context.cc9
-rw-r--r--webkit/fileapi/file_system_context.h2
-rw-r--r--webkit/fileapi/file_system_file_util.cc1
-rw-r--r--webkit/fileapi/file_system_mount_point_provider.h48
-rw-r--r--webkit/fileapi/file_system_operation.cc235
-rw-r--r--webkit/fileapi/file_system_operation.h33
-rw-r--r--webkit/fileapi/file_system_operation_context.cc21
-rw-r--r--webkit/fileapi/file_system_operation_context.h51
-rw-r--r--webkit/fileapi/file_system_operation_unittest.cc11
-rw-r--r--webkit/fileapi/file_system_path_manager.cc373
-rw-r--r--webkit/fileapi/file_system_path_manager.h78
-rw-r--r--webkit/fileapi/file_system_path_manager_unittest.cc126
-rw-r--r--webkit/fileapi/file_system_usage_tracker.cc7
-rw-r--r--webkit/fileapi/file_system_usage_tracker.h9
-rw-r--r--webkit/fileapi/file_system_usage_tracker_unittest.cc8
-rw-r--r--webkit/fileapi/file_system_util.cc80
-rw-r--r--webkit/fileapi/file_system_util.h4
-rw-r--r--webkit/fileapi/file_system_util_unittest.cc14
-rw-r--r--webkit/fileapi/local_file_system_file_util.cc178
-rw-r--r--webkit/fileapi/local_file_system_file_util.h112
-rw-r--r--webkit/fileapi/sandbox_mount_point_provider.cc312
-rw-r--r--webkit/fileapi/sandbox_mount_point_provider.h120
-rw-r--r--webkit/fileapi/sandbox_mount_point_provider_unittest.cc100
-rw-r--r--webkit/fileapi/webkit_fileapi.gypi7
24 files changed, 1410 insertions, 529 deletions
diff --git a/webkit/fileapi/file_system_context.cc b/webkit/fileapi/file_system_context.cc
index 71e5ed2..b5c1308 100644
--- a/webkit/fileapi/file_system_context.cc
+++ b/webkit/fileapi/file_system_context.cc
@@ -9,6 +9,7 @@
#include "googleurl/src/gurl.h"
#include "webkit/fileapi/file_system_path_manager.h"
#include "webkit/fileapi/file_system_usage_tracker.h"
+#include "webkit/fileapi/sandbox_mount_point_provider.h"
namespace fileapi {
@@ -50,8 +51,8 @@ void FileSystemContext::DeleteDataForOriginOnFileThread(
DCHECK(file_message_loop_->BelongsToCurrentThread());
std::string origin_identifier =
- FileSystemPathManager::GetOriginIdentifierFromURL(origin_url);
- FilePath path_for_origin = path_manager_->base_path().AppendASCII(
+ SandboxMountPointProvider::GetOriginIdentifierFromURL(origin_url);
+ FilePath path_for_origin = sandbox_provider()->base_path().AppendASCII(
origin_identifier);
file_util::Delete(path_for_origin, true /* recursive */);
@@ -65,4 +66,8 @@ void FileSystemContext::DeleteOnCorrectThread() const {
delete this;
}
+SandboxMountPointProvider* FileSystemContext::sandbox_provider() const {
+ return path_manager_->sandbox_provider();
+}
+
} // namespace fileapi
diff --git a/webkit/fileapi/file_system_context.h b/webkit/fileapi/file_system_context.h
index 0da1d99..16e3551 100644
--- a/webkit/fileapi/file_system_context.h
+++ b/webkit/fileapi/file_system_context.h
@@ -25,6 +25,7 @@ namespace fileapi {
class FileSystemContext;
class FileSystemPathManager;
class FileSystemUsageTracker;
+class SandboxMountPointProvider;
struct DefaultContextDeleter;
@@ -54,6 +55,7 @@ class FileSystemContext
private:
friend struct DefaultContextDeleter;
void DeleteOnCorrectThread() const;
+ SandboxMountPointProvider* sandbox_provider() const;
scoped_refptr<base::MessageLoopProxy> file_message_loop_;
scoped_refptr<base::MessageLoopProxy> io_message_loop_;
diff --git a/webkit/fileapi/file_system_file_util.cc b/webkit/fileapi/file_system_file_util.cc
index 8c11c48..10af22f 100644
--- a/webkit/fileapi/file_system_file_util.cc
+++ b/webkit/fileapi/file_system_file_util.cc
@@ -66,6 +66,7 @@ PlatformFileError FileSystemFileUtil::GetFileInfo(
return base::PLATFORM_FILE_ERROR_NOT_FOUND;
if (!file_util::GetFileInfo(file_path, file_info))
return base::PLATFORM_FILE_ERROR_FAILED;
+ file_info->path = file_path;
return base::PLATFORM_FILE_OK;
}
diff --git a/webkit/fileapi/file_system_mount_point_provider.h b/webkit/fileapi/file_system_mount_point_provider.h
new file mode 100644
index 0000000..3136636
--- /dev/null
+++ b/webkit/fileapi/file_system_mount_point_provider.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2011 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_FILE_SYSTEM_MOUNT_POINT_PROVIDER_H_
+#define WEBKIT_FILEAPI_FILE_SYSTEM_MOUNT_POINT_PROVIDER_H_
+
+#include "base/file_path.h"
+#include "googleurl/src/gurl.h"
+#include "webkit/fileapi/file_system_path_manager.h"
+#include "webkit/fileapi/file_system_types.h"
+
+namespace fileapi {
+
+// An interface to provide local filesystem paths.
+
+class FileSystemMountPointProvider {
+ public:
+ virtual ~FileSystemMountPointProvider() {}
+
+ // Checks if mount point access is allowed from |origin_url|.
+ virtual bool IsAccessAllowed(const GURL& origin_url) = 0;
+
+ // Retrieves the root path for the given |origin_url| and |type|, and
+ // calls the given |callback| with the root path and name.
+ // If |create| is true this also creates the directory if it doesn't exist.
+ virtual void GetFileSystemRootPath(
+ const GURL& origin_url,
+ FileSystemType type,
+ bool create,
+ FileSystemPathManager::GetRootPathCallback* callback) = 0;
+
+ // Like GetFileSystemRootPath, but synchronous, and can be called only while
+ // running on the file thread.
+ virtual FilePath GetFileSystemRootPathOnFileThread(
+ const GURL& origin_url,
+ FileSystemType type,
+ bool create) = 0;
+
+ // Checks if a given |name| contains any restricted names/chars in it.
+ // Callable on any thread.
+ virtual bool IsRestrictedFileName(const FilePath& filename) const = 0;
+};
+
+} // namespace fileapi
+
+#endif // WEBKIT_FILEAPI_FILE_SYSTEM_MOUNT_POINT_PROVIDER_H_
+
diff --git a/webkit/fileapi/file_system_operation.cc b/webkit/fileapi/file_system_operation.cc
index 0b800ba..5de0c64 100644
--- a/webkit/fileapi/file_system_operation.cc
+++ b/webkit/fileapi/file_system_operation.cc
@@ -11,18 +11,22 @@
#include "webkit/fileapi/file_system_file_util_proxy.h"
#include "webkit/fileapi/file_system_operation_context.h"
#include "webkit/fileapi/file_system_path_manager.h"
+#include "webkit/fileapi/file_system_util.h"
#include "webkit/fileapi/file_writer_delegate.h"
+#include "webkit/fileapi/local_file_system_file_util.h"
namespace fileapi {
FileSystemOperation::FileSystemOperation(
FileSystemCallbackDispatcher* dispatcher,
scoped_refptr<base::MessageLoopProxy> proxy,
- FileSystemContext* file_system_context)
+ FileSystemContext* file_system_context,
+ FileSystemFileUtil* file_system_file_util)
: proxy_(proxy),
dispatcher_(dispatcher),
- file_system_context_(file_system_context),
- file_system_operation_context_(FileSystemFileUtil::GetInstance()),
+ file_system_operation_context_(file_system_context,
+ file_system_file_util ? file_system_file_util :
+ LocalFileSystemFileUtil::GetInstance()),
callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
DCHECK(dispatcher);
#ifndef NDEBUG
@@ -45,8 +49,16 @@ void FileSystemOperation::OpenFileSystem(
kOperationOpenFileSystem);
#endif
- DCHECK(file_system_context_.get());
- file_system_context_->path_manager()->GetFileSystemRootPath(
+ DCHECK(file_system_context());
+ file_system_operation_context_.set_src_origin_url(origin_url);
+ file_system_operation_context_.set_src_type(type);
+ // TODO(ericu): We don't really need to make this call if !create.
+ // Also, in the future we won't need it either way, as long as we do all
+ // permission+quota checks beforehand. We only need it now because we have to
+ // create an unpredictable directory name. Without that, we could lazily
+ // create the root later on the first filesystem write operation, and just
+ // return GetFileSystemRootURI() here.
+ file_system_context()->path_manager()->GetFileSystemRootPath(
origin_url, type, create,
callback_factory_.NewCallback(&FileSystemOperation::DidGetRootPath));
}
@@ -57,14 +69,19 @@ void FileSystemOperation::CreateFile(const FilePath& path,
DCHECK(kOperationNone == pending_operation_);
pending_operation_ = kOperationCreateFile;
#endif
-
- if (!VerifyFileSystemPathForWrite(path, true /* create */)) {
+ FilePath virtual_path;
+ GURL origin_url;
+ FileSystemType type;
+ if (!VerifyFileSystemPathForWrite(
+ path, true /* create */, &origin_url, &type, &virtual_path)) {
delete this;
return;
}
+ file_system_operation_context_.set_src_origin_url(origin_url);
+ file_system_operation_context_.set_src_type(type);
FileSystemFileUtilProxy::EnsureFileExists(
file_system_operation_context_,
- proxy_, path, callback_factory_.NewCallback(
+ proxy_, virtual_path, callback_factory_.NewCallback(
exclusive ? &FileSystemOperation::DidEnsureFileExistsExclusive
: &FileSystemOperation::DidEnsureFileExistsNonExclusive));
}
@@ -76,14 +93,20 @@ void FileSystemOperation::CreateDirectory(const FilePath& path,
DCHECK(kOperationNone == pending_operation_);
pending_operation_ = kOperationCreateDirectory;
#endif
+ FilePath virtual_path;
+ GURL origin_url;
+ FileSystemType type;
- if (!VerifyFileSystemPathForWrite(path, true /* create */)) {
+ if (!VerifyFileSystemPathForWrite(
+ path, true /* create */, &origin_url, &type, &virtual_path)) {
delete this;
return;
}
+ file_system_operation_context_.set_src_origin_url(origin_url);
+ file_system_operation_context_.set_src_type(type);
FileSystemFileUtilProxy::CreateDirectory(
file_system_operation_context_,
- proxy_, path, exclusive, recursive, callback_factory_.NewCallback(
+ proxy_, virtual_path, exclusive, recursive, callback_factory_.NewCallback(
&FileSystemOperation::DidFinishFileOperation));
}
@@ -93,16 +116,37 @@ void FileSystemOperation::Copy(const FilePath& src_path,
DCHECK(kOperationNone == pending_operation_);
pending_operation_ = kOperationCopy;
#endif
-
- if (!VerifyFileSystemPathForRead(src_path) ||
- !VerifyFileSystemPathForWrite(dest_path, true /* create */)) {
+ FilePath virtual_path_0;
+ FilePath virtual_path_1;
+ GURL src_origin_url;
+ GURL dest_origin_url;
+ FileSystemType src_type;
+ FileSystemType dest_type;
+
+ if (!VerifyFileSystemPathForRead(src_path, &src_origin_url, &src_type,
+ &virtual_path_0) ||
+ !VerifyFileSystemPathForWrite(dest_path, true /* create */,
+ &dest_origin_url, &dest_type, &virtual_path_1)) {
delete this;
return;
}
+ if (src_origin_url.GetOrigin() != dest_origin_url.GetOrigin()) {
+ // TODO(ericu): We don't yet support copying across filesystem types, from
+ // extension to sandbox, etc. From temporary to persistent works, though.
+ // Since the sandbox code isn't in yet, I'm not sure exactly what check
+ // belongs here, but there's also no danger yet.
+ delete this;
+ return;
+ }
+ file_system_operation_context_.set_src_origin_url(src_origin_url);
+ file_system_operation_context_.set_dest_origin_url(dest_origin_url);
+ file_system_operation_context_.set_src_type(src_type);
+ file_system_operation_context_.set_dest_type(dest_type);
FileSystemFileUtilProxy::Copy(
file_system_operation_context_,
- proxy_, src_path, dest_path, callback_factory_.NewCallback(
- &FileSystemOperation::DidFinishFileOperation));
+ proxy_, virtual_path_0, virtual_path_1,
+ callback_factory_.NewCallback(
+ &FileSystemOperation::DidFinishFileOperation));
}
void FileSystemOperation::Move(const FilePath& src_path,
@@ -111,16 +155,35 @@ void FileSystemOperation::Move(const FilePath& src_path,
DCHECK(kOperationNone == pending_operation_);
pending_operation_ = kOperationMove;
#endif
-
- if (!VerifyFileSystemPathForRead(src_path) ||
- !VerifyFileSystemPathForWrite(dest_path, true /* create */)) {
+ FilePath virtual_path_0;
+ FilePath virtual_path_1;
+ GURL src_origin_url;
+ GURL dest_origin_url;
+ FileSystemType src_type;
+ FileSystemType dest_type;
+
+ if (!VerifyFileSystemPathForRead(src_path, &src_origin_url, &src_type,
+ &virtual_path_0) ||
+ !VerifyFileSystemPathForWrite(dest_path, true /* create */,
+ &dest_origin_url, &dest_type, &virtual_path_1)) {
+ delete this;
+ return;
+ }
+ if (src_origin_url.GetOrigin() != dest_origin_url.GetOrigin()) {
+ // TODO(ericu): We don't yet support moving across filesystem types, from
+ // extension to sandbox, etc. From temporary to persistent works, though.
delete this;
return;
}
+ file_system_operation_context_.set_src_origin_url(src_origin_url);
+ file_system_operation_context_.set_dest_origin_url(dest_origin_url);
+ file_system_operation_context_.set_src_type(src_type);
+ file_system_operation_context_.set_dest_type(dest_type);
FileSystemFileUtilProxy::Move(
file_system_operation_context_,
- proxy_, src_path, dest_path, callback_factory_.NewCallback(
- &FileSystemOperation::DidFinishFileOperation));
+ proxy_, virtual_path_0, virtual_path_1,
+ callback_factory_.NewCallback(
+ &FileSystemOperation::DidFinishFileOperation));
}
void FileSystemOperation::DirectoryExists(const FilePath& path) {
@@ -129,13 +192,18 @@ void FileSystemOperation::DirectoryExists(const FilePath& path) {
pending_operation_ = kOperationDirectoryExists;
#endif
- if (!VerifyFileSystemPathForRead(path)) {
+ FilePath virtual_path;
+ GURL origin_url;
+ FileSystemType type;
+ if (!VerifyFileSystemPathForRead(path, &origin_url, &type, &virtual_path)) {
delete this;
return;
}
+ file_system_operation_context_.set_src_origin_url(origin_url);
+ file_system_operation_context_.set_src_type(type);
FileSystemFileUtilProxy::GetFileInfo(
file_system_operation_context_,
- proxy_, path, callback_factory_.NewCallback(
+ proxy_, virtual_path, callback_factory_.NewCallback(
&FileSystemOperation::DidDirectoryExists));
}
@@ -145,13 +213,18 @@ void FileSystemOperation::FileExists(const FilePath& path) {
pending_operation_ = kOperationFileExists;
#endif
- if (!VerifyFileSystemPathForRead(path)) {
+ FilePath virtual_path;
+ GURL origin_url;
+ FileSystemType type;
+ if (!VerifyFileSystemPathForRead(path, &origin_url, &type, &virtual_path)) {
delete this;
return;
}
+ file_system_operation_context_.set_src_origin_url(origin_url);
+ file_system_operation_context_.set_src_type(type);
FileSystemFileUtilProxy::GetFileInfo(
file_system_operation_context_,
- proxy_, path, callback_factory_.NewCallback(
+ proxy_, virtual_path, callback_factory_.NewCallback(
&FileSystemOperation::DidFileExists));
}
@@ -161,13 +234,18 @@ void FileSystemOperation::GetMetadata(const FilePath& path) {
pending_operation_ = kOperationGetMetadata;
#endif
- if (!VerifyFileSystemPathForRead(path)) {
+ FilePath virtual_path;
+ GURL origin_url;
+ FileSystemType type;
+ if (!VerifyFileSystemPathForRead(path, &origin_url, &type, &virtual_path)) {
delete this;
return;
}
+ file_system_operation_context_.set_src_origin_url(origin_url);
+ file_system_operation_context_.set_src_type(type);
FileSystemFileUtilProxy::GetFileInfo(
file_system_operation_context_,
- proxy_, path, callback_factory_.NewCallback(
+ proxy_, virtual_path, callback_factory_.NewCallback(
&FileSystemOperation::DidGetMetadata));
}
@@ -177,13 +255,18 @@ void FileSystemOperation::ReadDirectory(const FilePath& path) {
pending_operation_ = kOperationReadDirectory;
#endif
- if (!VerifyFileSystemPathForRead(path)) {
+ FilePath virtual_path;
+ GURL origin_url;
+ FileSystemType type;
+ if (!VerifyFileSystemPathForRead(path, &origin_url, &type, &virtual_path)) {
delete this;
return;
}
+ file_system_operation_context_.set_src_origin_url(origin_url);
+ file_system_operation_context_.set_src_type(type);
FileSystemFileUtilProxy::ReadDirectory(
file_system_operation_context_,
- proxy_, path, callback_factory_.NewCallback(
+ proxy_, virtual_path, callback_factory_.NewCallback(
&FileSystemOperation::DidReadDirectory));
}
@@ -193,13 +276,19 @@ void FileSystemOperation::Remove(const FilePath& path, bool recursive) {
pending_operation_ = kOperationRemove;
#endif
- if (!VerifyFileSystemPathForWrite(path, false /* create */)) {
+ FilePath virtual_path;
+ GURL origin_url;
+ FileSystemType type;
+ if (!VerifyFileSystemPathForWrite(path, false /* create */, &origin_url,
+ &type, &virtual_path)) {
delete this;
return;
}
+ file_system_operation_context_.set_src_origin_url(origin_url);
+ file_system_operation_context_.set_src_type(type);
FileSystemFileUtilProxy::Delete(
file_system_operation_context_,
- proxy_, path, recursive, callback_factory_.NewCallback(
+ proxy_, virtual_path, recursive, callback_factory_.NewCallback(
&FileSystemOperation::DidFinishFileOperation));
}
@@ -212,10 +301,16 @@ void FileSystemOperation::Write(
DCHECK(kOperationNone == pending_operation_);
pending_operation_ = kOperationWrite;
#endif
- if (!VerifyFileSystemPathForWrite(path, true /* create */)) {
+ FilePath virtual_path;
+ GURL origin_url;
+ FileSystemType type;
+ if (!VerifyFileSystemPathForWrite(path, true /* create */, &origin_url,
+ &type, &virtual_path)) {
delete this;
return;
}
+ file_system_operation_context_.set_src_origin_url(origin_url);
+ file_system_operation_context_.set_src_type(type);
DCHECK(blob_url.is_valid());
file_writer_delegate_.reset(new FileWriterDelegate(this, offset));
blob_request_.reset(
@@ -224,7 +319,7 @@ void FileSystemOperation::Write(
FileSystemFileUtilProxy::CreateOrOpen(
file_system_operation_context_,
proxy_,
- path,
+ virtual_path,
base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE |
base::PLATFORM_FILE_ASYNC,
callback_factory_.NewCallback(
@@ -236,13 +331,19 @@ void FileSystemOperation::Truncate(const FilePath& path, int64 length) {
DCHECK(kOperationNone == pending_operation_);
pending_operation_ = kOperationTruncate;
#endif
- if (!VerifyFileSystemPathForWrite(path, false /* create */)) {
+ FilePath virtual_path;
+ GURL origin_url;
+ FileSystemType type;
+ if (!VerifyFileSystemPathForWrite(path, false /* create */, &origin_url,
+ &type, &virtual_path)) {
delete this;
return;
}
+ file_system_operation_context_.set_src_origin_url(origin_url);
+ file_system_operation_context_.set_src_type(type);
FileSystemFileUtilProxy::Truncate(
file_system_operation_context_,
- proxy_, path, length, callback_factory_.NewCallback(
+ proxy_, virtual_path, length, callback_factory_.NewCallback(
&FileSystemOperation::DidFinishFileOperation));
}
@@ -254,13 +355,19 @@ void FileSystemOperation::TouchFile(const FilePath& path,
pending_operation_ = kOperationTouchFile;
#endif
- if (!VerifyFileSystemPathForWrite(path, true /* create */)) {
+ FilePath virtual_path;
+ GURL origin_url;
+ FileSystemType type;
+ if (!VerifyFileSystemPathForWrite(path, true /* create */, &origin_url,
+ &type, &virtual_path)) {
delete this;
return;
}
+ file_system_operation_context_.set_src_origin_url(origin_url);
+ file_system_operation_context_.set_src_type(type);
FileSystemFileUtilProxy::Touch(
file_system_operation_context_,
- proxy_, path, last_access_time, last_modified_time,
+ proxy_, virtual_path, last_access_time, last_modified_time,
callback_factory_.NewCallback(&FileSystemOperation::DidTouchFile));
}
@@ -300,7 +407,16 @@ void FileSystemOperation::Cancel(FileSystemOperation* cancel_operation_ptr) {
void FileSystemOperation::DidGetRootPath(
bool success, const FilePath& path, const std::string& name) {
DCHECK(success || path.empty());
- dispatcher_->DidOpenFileSystem(name, path);
+ FilePath result;
+ // We ignore the path, and return a URL instead. The point was just to verify
+ // that we could create/find the path.
+ if (success) {
+ GURL root_url = GetFileSystemRootURI(
+ file_system_operation_context_.src_origin_url(),
+ file_system_operation_context_.src_type());
+ result = FilePath().AppendASCII(root_url.spec());
+ }
+ dispatcher_->DidOpenFileSystem(name, result);
delete this;
}
@@ -416,15 +532,21 @@ void FileSystemOperation::OnFileOpenedForWrite(
}
bool FileSystemOperation::VerifyFileSystemPathForRead(
- const FilePath& path) {
- // If we have no context, we just allow any operations.
- if (!file_system_context_.get())
+ const FilePath& path, GURL* origin_url, FileSystemType* type,
+ FilePath* virtual_path) {
+
+ // If we have no context, we just allow any operations, for testing.
+ // TODO(ericu): Revisit this hack for security.
+ if (!file_system_context()) {
+ *virtual_path = path;
+ *type = file_system_operation_context_.src_type();
return true;
+ }
// We may want do more checks, but for now it just checks if the given
// |path| is under the valid FileSystem root path for this host context.
- if (!file_system_context_->path_manager()->CrackFileSystemPath(
- path, NULL, NULL, NULL)) {
+ if (!file_system_context()->path_manager()->CrackFileSystemPath(
+ path, origin_url, type, virtual_path)) {
dispatcher_->DidFail(base::PLATFORM_FILE_ERROR_SECURITY);
return false;
}
@@ -432,32 +554,35 @@ bool FileSystemOperation::VerifyFileSystemPathForRead(
}
bool FileSystemOperation::VerifyFileSystemPathForWrite(
- const FilePath& path, bool create) {
- GURL origin_url;
- FilePath virtual_path;
-
- // If we have no context, we just allow any operations.
- if (!file_system_context_.get())
+ const FilePath& path, bool create, GURL* origin_url, FileSystemType* type,
+ FilePath* virtual_path) {
+
+ // If we have no context, we just allow any operations, for testing.
+ // TODO(ericu): Revisit this hack for security.
+ if (!file_system_context()) {
+ *virtual_path = path;
+ *type = file_system_operation_context_.dest_type();
return true;
+ }
- if (!file_system_context_->path_manager()->CrackFileSystemPath(
- path, &origin_url, NULL, &virtual_path)) {
+ if (!file_system_context()->path_manager()->CrackFileSystemPath(
+ path, origin_url, type, virtual_path)) {
dispatcher_->DidFail(base::PLATFORM_FILE_ERROR_SECURITY);
return false;
}
// Any write access is disallowed on the root path.
- if (virtual_path.value().length() == 0 ||
- virtual_path.DirName().value() == virtual_path.value()) {
+ if (virtual_path->value().length() == 0 ||
+ virtual_path->DirName().value() == virtual_path->value()) {
dispatcher_->DidFail(base::PLATFORM_FILE_ERROR_SECURITY);
return false;
}
- if (create && FileSystemPathManager::IsRestrictedFileName(
- path.BaseName())) {
+ if (create && file_system_context()->path_manager()->IsRestrictedFileName(
+ *type, virtual_path->BaseName())) {
dispatcher_->DidFail(base::PLATFORM_FILE_ERROR_SECURITY);
return false;
}
// TODO(kinuko): the check must be moved to QuotaFileSystemFileUtil.
- if (!file_system_context_->IsStorageUnlimited(origin_url)) {
+ if (!file_system_context()->IsStorageUnlimited(*origin_url)) {
dispatcher_->DidFail(base::PLATFORM_FILE_ERROR_NO_SPACE);
return false;
}
diff --git a/webkit/fileapi/file_system_operation.h b/webkit/fileapi/file_system_operation.h
index a7ee52b..ae2b619 100644
--- a/webkit/fileapi/file_system_operation.h
+++ b/webkit/fileapi/file_system_operation.h
@@ -9,6 +9,7 @@
#include "base/file_path.h"
#include "base/file_util_proxy.h"
+#include "base/gtest_prod_util.h"
#include "base/message_loop_proxy.h"
#include "base/platform_file.h"
#include "base/ref_counted.h"
@@ -34,6 +35,7 @@ namespace fileapi {
class FileSystemCallbackDispatcher;
class FileSystemContext;
class FileWriterDelegate;
+class FileSystemOperationTest;
// This class is designed to serve one-time file system operation per instance.
// Only one method(CreateFile, CreateDirectory, Copy, Move, DirectoryExists,
@@ -44,9 +46,12 @@ class FileWriterDelegate;
class FileSystemOperation {
public:
// |dispatcher| will be owned by this class.
+ // |file_system_file_util| is optional; if supplied, it will not be deleted by
+ // the class. It's expecting a pointer to a singleton.
FileSystemOperation(FileSystemCallbackDispatcher* dispatcher,
scoped_refptr<base::MessageLoopProxy> proxy,
- FileSystemContext* file_system_context);
+ FileSystemContext* file_system_context,
+ FileSystemFileUtil* file_system_file_util);
virtual ~FileSystemOperation();
void OpenFileSystem(const GURL& origin_url,
@@ -81,6 +86,15 @@ class FileSystemOperation {
void Cancel(FileSystemOperation* cancel_operation);
private:
+ FileSystemContext* file_system_context() const {
+ return file_system_operation_context_.file_system_context();
+ }
+
+ FileSystemOperationContext* file_system_operation_context() {
+ return &file_system_operation_context_;
+ }
+ friend class FileSystemOperationTest;
+
// A callback used for OpenFileSystem.
void DidGetRootPath(bool success,
const FilePath& path,
@@ -118,15 +132,20 @@ class FileSystemOperation {
base::PassPlatformFile file,
bool created);
- // Checks the validity of a given |path| for reading.
+ // Checks the validity of a given |path| for reading, and cracks the path into
+ // root URL and virtual path components.
// Returns true if the given |path| is a valid FileSystem path.
// Otherwise it calls dispatcher's DidFail method with
// PLATFORM_FILE_ERROR_SECURITY and returns false.
// (Note: this doesn't delete this when it calls DidFail and returns false;
// it's the caller's responsibility.)
- bool VerifyFileSystemPathForRead(const FilePath& path);
+ bool VerifyFileSystemPathForRead(const FilePath& path,
+ GURL* root_url,
+ FileSystemType* type,
+ FilePath* virtual_path);
- // Checks the validity of a given |path| for writing.
+ // Checks the validity of a given |path| for writing, and cracks the path into
+ // root URL and virtual path components.
// Returns true if the given |path| is a valid FileSystem path, and
// its origin embedded in the path has the right to write.
// Otherwise it fires dispatcher's DidFail method with
@@ -140,7 +159,10 @@ class FileSystemOperation {
// (Note: this doesn't delete this when it calls DidFail and returns false;
// it's the caller's responsibility.)
bool VerifyFileSystemPathForWrite(const FilePath& path,
- bool create);
+ bool create,
+ GURL* root_url,
+ FileSystemType* type,
+ FilePath* virtual_path);
#ifndef NDEBUG
enum OperationType {
@@ -170,7 +192,6 @@ class FileSystemOperation {
scoped_ptr<FileSystemCallbackDispatcher> dispatcher_;
- scoped_refptr<FileSystemContext> file_system_context_;
FileSystemOperationContext file_system_operation_context_;
base::ScopedCallbackFactory<FileSystemOperation> callback_factory_;
diff --git a/webkit/fileapi/file_system_operation_context.cc b/webkit/fileapi/file_system_operation_context.cc
new file mode 100644
index 0000000..1a57137
--- /dev/null
+++ b/webkit/fileapi/file_system_operation_context.cc
@@ -0,0 +1,21 @@
+// Copyright (c) 2011 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/file_system_operation_context.h"
+
+#include "webkit/fileapi/file_system_context.h"
+#include "webkit/fileapi/file_system_util.h"
+
+namespace fileapi {
+
+FileSystemOperationContext::FileSystemOperationContext(
+ FileSystemContext* context,
+ FileSystemFileUtil* file_system_file_util)
+ : file_system_context_(context),
+ file_system_file_util_(file_system_file_util),
+ src_type_(kFileSystemTypeUnknown),
+ dest_type_(kFileSystemTypeUnknown) {
+}
+
+} // namespace fileapi
diff --git a/webkit/fileapi/file_system_operation_context.h b/webkit/fileapi/file_system_operation_context.h
index 68f5e47..d4c7f2f 100644
--- a/webkit/fileapi/file_system_operation_context.h
+++ b/webkit/fileapi/file_system_operation_context.h
@@ -5,24 +5,71 @@
#ifndef WEBKIT_FILEAPI_FILE_SYSTEM_OPERATION_CONTEXT_H_
#define WEBKIT_FILEAPI_FILE_SYSTEM_OPERATION_CONTEXT_H_
+#include "base/ref_counted.h"
+#include "googleurl/src/gurl.h"
#include "webkit/fileapi/file_system_file_util.h"
+#include "webkit/fileapi/file_system_types.h"
namespace fileapi {
+class FileSystemContext;
+
class FileSystemOperationContext {
public:
- FileSystemOperationContext(FileSystemFileUtil* file_system_file_util)
- : file_system_file_util_(file_system_file_util) {
+ FileSystemOperationContext(
+ FileSystemContext* context,
+ FileSystemFileUtil* file_system_file_util);
+
+ FileSystemContext* file_system_context() const {
+ return file_system_context_.get();
}
FileSystemFileUtil* file_system_file_util() const {
return file_system_file_util_;
}
+ void set_src_origin_url(const GURL& url) {
+ src_origin_url_ = url;
+ }
+
+ const GURL& src_origin_url() const {
+ return src_origin_url_;
+ }
+
+ void set_dest_origin_url(const GURL& url) {
+ dest_origin_url_ = url;
+ }
+
+ const GURL& dest_origin_url() const {
+ return dest_origin_url_;
+ }
+
+ FileSystemType src_type() const {
+ return src_type_;
+ }
+
+ void set_src_type(FileSystemType src_type) {
+ src_type_ = src_type;
+ }
+
+ FileSystemType dest_type() const {
+ return dest_type_;
+ }
+
+ void set_dest_type(FileSystemType dest_type) {
+ dest_type_ = dest_type;
+ }
+
private:
// This file_system_file_util_ is not "owned" by FileSystemOperationContext.
// It is supposed to be a pointer to a singleton.
+ scoped_refptr<FileSystemContext> file_system_context_;
FileSystemFileUtil* file_system_file_util_;
+
+ GURL src_origin_url_; // Also used for any single-path operation.
+ GURL dest_origin_url_;
+ FileSystemType src_type_; // Also used for any single-path operation.
+ FileSystemType dest_type_;
};
} // namespace fileapi
diff --git a/webkit/fileapi/file_system_operation_unittest.cc b/webkit/fileapi/file_system_operation_unittest.cc
index 7e3a177..fe2b85d 100644
--- a/webkit/fileapi/file_system_operation_unittest.cc
+++ b/webkit/fileapi/file_system_operation_unittest.cc
@@ -10,6 +10,7 @@
#include "base/scoped_temp_dir.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webkit/fileapi/file_system_callback_dispatcher.h"
+#include "webkit/fileapi/file_system_file_util.h"
#include "webkit/fileapi/file_system_operation.h"
namespace fileapi {
@@ -97,10 +98,16 @@ class MockDispatcher : public FileSystemCallbackDispatcher {
};
FileSystemOperation* FileSystemOperationTest::operation() {
- return new FileSystemOperation(
+ FileSystemOperation* operation = new FileSystemOperation(
new MockDispatcher(this),
base::MessageLoopProxy::CreateForCurrentThread(),
- NULL);
+ NULL,
+ FileSystemFileUtil::GetInstance());
+ operation->file_system_operation_context()->set_src_type(
+ kFileSystemTypeTemporary);
+ operation->file_system_operation_context()->set_dest_type(
+ kFileSystemTypeTemporary);
+ return operation;
}
TEST_F(FileSystemOperationTest, TestMoveFailureSrcDoesntExist) {
diff --git a/webkit/fileapi/file_system_path_manager.cc b/webkit/fileapi/file_system_path_manager.cc
index 61aa49e..64f3274 100644
--- a/webkit/fileapi/file_system_path_manager.cc
+++ b/webkit/fileapi/file_system_path_manager.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -14,171 +14,33 @@
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "googleurl/src/gurl.h"
-#include "third_party/WebKit/Source/WebKit/chromium/public/WebCString.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFileSystem.h"
-#include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h"
+#include "webkit/fileapi/file_system_util.h"
+#include "webkit/fileapi/sandbox_mount_point_provider.h"
#include "webkit/glue/webkit_glue.h"
// We use some of WebKit types for conversions between origin identifiers
// and origin URLs.
using WebKit::WebFileSystem;
-using WebKit::WebSecurityOrigin;
-using WebKit::WebString;
using base::PlatformFileError;
-namespace fileapi {
-
-const FilePath::CharType FileSystemPathManager::kFileSystemDirectory[] =
- FILE_PATH_LITERAL("FileSystem");
-
-const char FileSystemPathManager::kPersistentName[] = "Persistent";
-const char FileSystemPathManager::kTemporaryName[] = "Temporary";
-
-static const FilePath::CharType kFileSystemUniqueNamePrefix[] =
- FILE_PATH_LITERAL("chrome-");
-static const int kFileSystemUniqueLength = 16;
-static const unsigned kFileSystemUniqueDirectoryNameLength =
- kFileSystemUniqueLength + arraysize(kFileSystemUniqueNamePrefix) - 1;
-
-namespace {
-
-// Restricted names.
-// http://dev.w3.org/2009/dap/file-system/file-dir-sys.html#naming-restrictions
-static const char* const kRestrictedNames[] = {
- "con", "prn", "aux", "nul",
- "com1", "com2", "com3", "com4", "com5", "com6", "com7", "com8", "com9",
- "lpt1", "lpt2", "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9",
-};
-
-// Restricted chars.
-static const FilePath::CharType kRestrictedChars[] = {
- '/', '\\', '<', '>', ':', '?', '*', '"', '|',
-};
-
-inline std::string FilePathStringToASCII(
- const FilePath::StringType& path_string) {
-#if defined(OS_WIN)
- return WideToASCII(path_string);
-#elif defined(OS_POSIX)
- return path_string;
-#endif
-}
-
-FilePath::StringType CreateUniqueDirectoryName(const GURL& origin_url) {
- // This can be anything but need to be unpredictable.
- static const FilePath::CharType letters[] = FILE_PATH_LITERAL(
- "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
- FilePath::StringType unique(kFileSystemUniqueNamePrefix);
- for (int i = 0; i < kFileSystemUniqueLength; ++i)
- unique += letters[base::RandInt(0, arraysize(letters) - 2)];
- return unique;
-}
-
static const char kExtensionScheme[] = "chrome-extension";
-} // anonymous namespace
-
-class FileSystemPathManager::GetFileSystemRootPathTask
- : public base::RefCountedThreadSafe<
- FileSystemPathManager::GetFileSystemRootPathTask> {
- public:
- GetFileSystemRootPathTask(
- scoped_refptr<base::MessageLoopProxy> file_message_loop,
- const std::string& name,
- FileSystemPathManager::GetRootPathCallback* callback)
- : file_message_loop_(file_message_loop),
- origin_message_loop_proxy_(
- base::MessageLoopProxy::CreateForCurrentThread()),
- name_(name),
- callback_(callback) {
- }
-
- void Start(const GURL& origin_url,
- const FilePath& origin_base_path,
- bool create) {
- file_message_loop_->PostTask(FROM_HERE, NewRunnableMethod(this,
- &GetFileSystemRootPathTask::GetFileSystemRootPathOnFileThread,
- origin_url, origin_base_path, create));
- }
-
- private:
- void GetFileSystemRootPathOnFileThread(
- const GURL& origin_url,
- const FilePath& base_path,
- bool create) {
- FilePath root;
- if (ReadOriginDirectory(base_path, origin_url, &root)) {
- DispatchCallbackOnCallerThread(root);
- return;
- }
-
- if (!create) {
- DispatchCallbackOnCallerThread(FilePath());
- return;
- }
-
- // Creates the root directory.
- root = base_path.Append(CreateUniqueDirectoryName(origin_url));
- if (!file_util::CreateDirectory(root)) {
- DispatchCallbackOnCallerThread(FilePath());
- return;
- }
- DispatchCallbackOnCallerThread(root);
- }
-
- bool ReadOriginDirectory(const FilePath& base_path,
- const GURL& origin_url,
- FilePath* unique) {
- file_util::FileEnumerator file_enum(
- base_path, false /* recursive */,
- file_util::FileEnumerator::DIRECTORIES,
- FilePath::StringType(kFileSystemUniqueNamePrefix) +
- FILE_PATH_LITERAL("*"));
- FilePath current;
- bool found = false;
- while (!(current = file_enum.Next()).empty()) {
- if (current.BaseName().value().length() !=
- kFileSystemUniqueDirectoryNameLength)
- continue;
- if (found) {
- // TODO(kinuko): Should notify the user to ask for some action.
- LOG(WARNING) << "Unexpectedly found more than one FileSystem "
- << "directories for " << origin_url;
- return false;
- }
- found = true;
- *unique = current;
- }
- return !unique->empty();
- }
-
- void DispatchCallbackOnCallerThread(const FilePath& root_path) {
- origin_message_loop_proxy_->PostTask(FROM_HERE,
- NewRunnableMethod(this, &GetFileSystemRootPathTask::DispatchCallback,
- root_path));
- }
-
- void DispatchCallback(const FilePath& root_path) {
- callback_->Run(!root_path.empty(), root_path, name_);
- callback_.reset();
- }
-
- scoped_refptr<base::MessageLoopProxy> file_message_loop_;
- scoped_refptr<base::MessageLoopProxy> origin_message_loop_proxy_;
- std::string name_;
- scoped_ptr<FileSystemPathManager::GetRootPathCallback> callback_;
-};
+namespace fileapi {
FileSystemPathManager::FileSystemPathManager(
scoped_refptr<base::MessageLoopProxy> file_message_loop,
const FilePath& profile_path,
bool is_incognito,
bool allow_file_access_from_files)
- : file_message_loop_(file_message_loop),
- base_path_(profile_path.Append(kFileSystemDirectory)),
- is_incognito_(is_incognito),
- allow_file_access_from_files_(allow_file_access_from_files) {
+ : is_incognito_(is_incognito),
+ allow_file_access_from_files_(allow_file_access_from_files),
+ sandbox_provider_(
+ new SandboxMountPointProvider(
+ ALLOW_THIS_IN_INITIALIZER_LIST(this),
+ file_message_loop,
+ profile_path)) {
}
FileSystemPathManager::~FileSystemPathManager() {}
@@ -186,95 +48,88 @@ FileSystemPathManager::~FileSystemPathManager() {}
void FileSystemPathManager::GetFileSystemRootPath(
const GURL& origin_url, fileapi::FileSystemType type,
bool create, GetRootPathCallback* callback_ptr) {
- scoped_ptr<GetRootPathCallback> callback(callback_ptr);
- if (is_incognito_) {
- // TODO(kinuko): return an isolated temporary directory.
- callback->Run(false, FilePath(), std::string());
- return;
- }
- if (!IsAllowedScheme(origin_url)) {
- callback->Run(false, FilePath(), std::string());
- return;
+ switch (type) {
+ case kFileSystemTypeTemporary:
+ case kFileSystemTypePersistent:
+ sandbox_provider_->GetFileSystemRootPath(
+ origin_url, type, create, callback_ptr);
+ break;
+ case kFileSystemTypeUnknown:
+ default:
+ NOTREACHED();
+ callback_ptr->Run(false, FilePath(), std::string());
}
+}
- std::string origin_identifier = GetOriginIdentifierFromURL(origin_url);
- FilePath origin_base_path = GetFileSystemBaseDirectoryForOriginAndType(
- base_path(), origin_identifier, type);
- if (origin_base_path.empty()) {
- callback->Run(false, FilePath(), std::string());
- return;
+FilePath FileSystemPathManager::GetFileSystemRootPathOnFileThread(
+ const GURL& origin_url, FileSystemType type, bool create) {
+ switch (type) {
+ case kFileSystemTypeTemporary:
+ case kFileSystemTypePersistent:
+ return sandbox_provider_->GetFileSystemRootPathOnFileThread(
+ origin_url, type, create);
+ break;
+ case kFileSystemTypeUnknown:
+ default:
+ NOTREACHED();
+ return FilePath();
}
-
- std::string type_string = GetFileSystemTypeString(type);
- DCHECK(!type_string.empty());
-
- scoped_refptr<GetFileSystemRootPathTask> task(
- new GetFileSystemRootPathTask(file_message_loop_,
- origin_identifier + ":" + type_string,
- callback.release()));
- task->Start(origin_url, origin_base_path, create);
}
bool FileSystemPathManager::CrackFileSystemPath(
const FilePath& path, GURL* origin_url, FileSystemType* type,
FilePath* virtual_path) const {
- // Any paths that includes parent references are considered invalid.
- if (path.ReferencesParent())
- return false;
-
- // The path should be a child of the profile FileSystem path.
- FilePath relative;
- if (!base_path_.AppendRelativePath(path, &relative))
- return false;
-
- // The relative path from the profile FileSystem path should contain
- // at least three components, one for storage identifier, one for type
- // and one for the 'unique' part.
- std::vector<FilePath::StringType> components;
- relative.GetComponents(&components);
- if (components.size() < 3)
- return false;
+ // TODO(ericu):
+ // Paths come in here [for now] as a URL, followed by a virtual path in
+ // platform format. For example, on Windows, this will look like
+ // filesystem:http://www.example.com/temporary/\path\to\file.txt.
+ // A potentially dangerous malicious path on Windows might look like:
+ // filesystem:http://www.example.com/temporary/foo/../../\path\to\file.txt.
+ // This code is ugly, but will get cleaned up as we fix the calling side.
+ // Eventually there won't be a distinction between a filesystem path and a
+ // filesystem URL--they'll all be URLs.
+ // We should be passing these to WebKit as string, not FilePath, for ease of
+ // manipulation, or possibly as GURL/KURL.
+
+ std::string path_as_string;
+#ifdef OS_WIN
+ path_as_string = WideToUTF8(path.value());
+#else
+ path_as_string = path.value();
+#endif
+ GURL path_as_url(path_as_string);
- // The second component of the relative path to the root directory
- // must be kPersistent or kTemporary.
- if (!IsStringASCII(components[1]))
+ FilePath local_path;
+ GURL local_url;
+ FileSystemType local_type;
+ if (!CrackFileSystemURL(path_as_url, &local_url, &local_type, &local_path))
return false;
- std::string ascii_type_component = FilePathStringToASCII(components[1]);
- FileSystemType cracked_type = kFileSystemTypeUnknown;
- if (ascii_type_component == kPersistentName)
- cracked_type = kFileSystemTypePersistent;
- else if (ascii_type_component == kTemporaryName)
- cracked_type = kFileSystemTypeTemporary;
- else
- return false;
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+ // TODO(ericu): This puts the separators back to windows-standard; they come
+ // out of the above code as '/' no matter the platform. Long-term, we'll
+ // want to let the underlying FileSystemFileUtil implementation do this part,
+ // since they won't all need it.
+ local_path = local_path.NormalizeWindowsPathSeparators();
+#endif
- DCHECK(cracked_type != kFileSystemTypeUnknown);
+ // Any paths that include parent references are considered invalid.
+ // These should have been taken care of in CrackFileSystemURL.
+ DCHECK(!local_path.ReferencesParent());
- // The given |path| seems valid. Populates the |origin_url|, |type|
+ // The given |local_path| seems valid. Populates the |origin_url|, |type|
// and |virtual_path| if they are given.
if (origin_url) {
- WebSecurityOrigin web_security_origin =
- WebSecurityOrigin::createFromDatabaseIdentifier(
- webkit_glue::FilePathStringToWebString(components[0]));
- *origin_url = GURL(web_security_origin.toString());
-
- // We need this work-around for file:/// URIs as
- // createFromDatabaseIdentifier returns empty origin_url for them.
- if (allow_file_access_from_files_ && origin_url->spec().empty() &&
- components[0].find(FILE_PATH_LITERAL("file")) == 0)
- *origin_url = GURL("file:///");
+ *origin_url = local_url;
}
if (type)
- *type = cracked_type;
+ *type = local_type;
if (virtual_path) {
- virtual_path->clear();
- for (size_t i = 3; i < components.size(); ++i)
- *virtual_path = virtual_path->Append(components[i]);
+ *virtual_path = local_path;
}
return true;
@@ -289,87 +144,27 @@ bool FileSystemPathManager::IsAllowedScheme(const GURL& url) const {
}
// static
-bool FileSystemPathManager::IsRestrictedFileName(const FilePath& filename) {
- if (filename.value().empty())
- return false;
-
- if (IsWhitespace(filename.value()[filename.value().size() - 1]) ||
- filename.value()[filename.value().size() - 1] == '.')
- return true;
-
- std::string filename_lower = StringToLowerASCII(
- FilePathStringToASCII(filename.value()));
-
- for (size_t i = 0; i < arraysize(kRestrictedNames); ++i) {
- // Exact match.
- if (filename_lower == kRestrictedNames[i])
- return true;
- // Starts with "RESTRICTED_NAME.".
- if (filename_lower.find(std::string(kRestrictedNames[i]) + ".") == 0)
- return true;
- }
-
- for (size_t i = 0; i < arraysize(kRestrictedChars); ++i) {
- if (filename.value().find(kRestrictedChars[i]) !=
- FilePath::StringType::npos)
- return true;
- }
-
- return false;
-}
-
-// static
std::string FileSystemPathManager::GetFileSystemTypeString(
fileapi::FileSystemType type) {
if (type == fileapi::kFileSystemTypeTemporary)
- return fileapi::FileSystemPathManager::kTemporaryName;
+ return fileapi::SandboxMountPointProvider::kTemporaryName;
else if (type == fileapi::kFileSystemTypePersistent)
- return fileapi::FileSystemPathManager::kPersistentName;
+ return fileapi::SandboxMountPointProvider::kPersistentName;
return std::string();
}
-// static
-std::string FileSystemPathManager::GetOriginIdentifierFromURL(
- const GURL& url) {
- WebKit::WebSecurityOrigin web_security_origin =
- WebKit::WebSecurityOrigin::createFromString(UTF8ToUTF16(url.spec()));
- return web_security_origin.databaseIdentifier().utf8();
-}
-
-// static
-FilePath FileSystemPathManager::GetFileSystemBaseDirectoryForOriginAndType(
- const FilePath& base_path, const std::string& origin_identifier,
- fileapi::FileSystemType type) {
- if (origin_identifier.empty())
- return FilePath();
- std::string type_string = GetFileSystemTypeString(type);
- if (type_string.empty()) {
- LOG(WARNING) << "Unknown filesystem type is requested:" << type;
- return FilePath();
+// Checks if a given |name| contains any restricted names/chars in it.
+bool FileSystemPathManager::IsRestrictedFileName(
+ FileSystemType type, const FilePath& filename) {
+ switch (type) {
+ case kFileSystemTypeTemporary:
+ case kFileSystemTypePersistent:
+ return sandbox_provider_->IsRestrictedFileName(filename);
+ case kFileSystemTypeUnknown:
+ default:
+ NOTREACHED();
+ return true;
}
- return base_path.AppendASCII(origin_identifier)
- .AppendASCII(type_string);
-}
-
-FileSystemPathManager::OriginEnumerator::OriginEnumerator(
- const FilePath& base_path)
- : enumerator_(base_path, false /* recursive */,
- file_util::FileEnumerator::DIRECTORIES) {
-}
-
-std::string FileSystemPathManager::OriginEnumerator::Next() {
- current_ = enumerator_.Next();
- return FilePathStringToASCII(current_.BaseName().value());
-}
-
-bool FileSystemPathManager::OriginEnumerator::HasTemporary() {
- return !current_.empty() && file_util::DirectoryExists(current_.AppendASCII(
- FileSystemPathManager::kTemporaryName));
-}
-
-bool FileSystemPathManager::OriginEnumerator::HasPersistent() {
- return !current_.empty() && file_util::DirectoryExists(current_.AppendASCII(
- FileSystemPathManager::kPersistentName));
}
} // namespace fileapi
diff --git a/webkit/fileapi/file_system_path_manager.h b/webkit/fileapi/file_system_path_manager.h
index 28082aa..c1d2df9 100644
--- a/webkit/fileapi/file_system_path_manager.h
+++ b/webkit/fileapi/file_system_path_manager.h
@@ -19,6 +19,8 @@ class MessageLoopProxy;
namespace fileapi {
+class SandboxMountPointProvider;
+
// TODO(kinuko): Probably this module must be called FileSystemPathUtil
// or something similar.
@@ -49,11 +51,17 @@ class FileSystemPathManager {
// Retrieves the root path for the given |origin_url| and |type|, and
// calls the given |callback| with the root path and name.
// If |create| is true this also creates the directory if it doesn't exist.
- void GetFileSystemRootPath(const GURL& origin_url,
- fileapi::FileSystemType type,
+ virtual void GetFileSystemRootPath(const GURL& origin_url,
+ FileSystemType type,
bool create,
- GetRootPathCallback* callback);
-
+ FileSystemPathManager::GetRootPathCallback*
+ callback);
+
+ // Like GetFileSystemRootPath, but synchronous, and can be called only while
+ // running on the file thread.
+ virtual FilePath GetFileSystemRootPathOnFileThread(const GURL& origin_url,
+ FileSystemType type,
+ bool create);
// Cracks the given |path|, retrieves the information embedded in the path
// and populates |origin_url|, |type| and |virtual_path|. The |virtual_path|
// is a sandboxed path in the file system, i.e. the relative path to the
@@ -67,66 +75,26 @@ class FileSystemPathManager {
// filesystem.
bool IsAllowedScheme(const GURL& url) const;
- // The FileSystem directory name.
- static const FilePath::CharType kFileSystemDirectory[];
-
- static const char kPersistentName[];
- static const char kTemporaryName[];
-
- const FilePath& base_path() const {
- return base_path_;
- }
-
- // Checks if a given |name| contains any restricted names/chars in it.
- static bool IsRestrictedFileName(const FilePath& filename);
-
// Returns the string for the given |type|.
// Returns an empty string if the |type| is invalid.
static std::string GetFileSystemTypeString(fileapi::FileSystemType type);
- // Returns the origin identifier string, which is used as a part of the
- // sandboxed path component, for the given |url|.
- static std::string GetOriginIdentifierFromURL(const GURL& url);
-
- // Gets a base directory path of the sandboxed filesystem that is
- // specified by |origin_identifier| and |type|.
- // |base_path| must be pointing the FileSystem's data directory
- // under the profile directory, i.e. <profile_dir>/kFileSystemDirectory.
- // Returns an empty path if any of the given parameters are invalid.
- // Returned directory path does not contain 'unique' part, therefore
- // it is not an actural root path for the filesystem.
- static FilePath GetFileSystemBaseDirectoryForOriginAndType(
- const FilePath& base_path,
- const std::string& origin_identifier,
- fileapi::FileSystemType type);
-
- // Enumerates origins under the given |base_path|.
- // This must be used on the FILE thread.
- class OriginEnumerator {
- public:
- OriginEnumerator(const FilePath& base_path);
-
- // Returns the next origin identifier. Returns empty if there are no
- // more origins.
- std::string Next();
-
- bool HasTemporary();
- bool HasPersistent();
- const FilePath& path() { return current_; }
-
- private:
- file_util::FileEnumerator enumerator_;
- FilePath current_;
- };
+ // Checks if a given |name| contains any restricted names/chars in it.
+ bool IsRestrictedFileName(FileSystemType type,
+ const FilePath& filename);
- private:
- class GetFileSystemRootPathTask;
+ SandboxMountPointProvider* sandbox_provider() const {
+ return sandbox_provider_.get();
+ }
- scoped_refptr<base::MessageLoopProxy> file_message_loop_;
+ bool is_incognito() const {
+ return is_incognito_;
+ }
- const FilePath base_path_;
+ private:
const bool is_incognito_;
const bool allow_file_access_from_files_;
+ scoped_ptr<SandboxMountPointProvider> sandbox_provider_;
DISALLOW_COPY_AND_ASSIGN(FileSystemPathManager);
};
diff --git a/webkit/fileapi/file_system_path_manager_unittest.cc b/webkit/fileapi/file_system_path_manager_unittest.cc
index 3d6c831..8f004c2 100644
--- a/webkit/fileapi/file_system_path_manager_unittest.cc
+++ b/webkit/fileapi/file_system_path_manager_unittest.cc
@@ -17,6 +17,8 @@
#include "base/scoped_temp_dir.h"
#include "googleurl/src/gurl.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/fileapi/file_system_util.h"
+#include "webkit/fileapi/sandbox_mount_point_provider.h"
using namespace fileapi;
@@ -212,7 +214,7 @@ class FileSystemPathManagerTest : public testing::Test {
FilePath data_path() { return data_dir_.path(); }
FilePath file_system_path() {
return data_dir_.path().Append(
- FileSystemPathManager::kFileSystemDirectory);
+ SandboxMountPointProvider::kFileSystemDirectory);
}
private:
@@ -345,16 +347,24 @@ TEST_F(FileSystemPathManagerTest, GetRootPathFileURIWithAllowFlag) {
TEST_F(FileSystemPathManagerTest, VirtualPathFromFileSystemPathTest) {
scoped_ptr<FileSystemPathManager> manager(NewPathManager(false, false));
- FilePath root_path;
- EXPECT_TRUE(GetRootPath(manager.get(), GURL("http://foo.com/"),
- fileapi::kFileSystemTypeTemporary,
- true /* create */, &root_path));
+ GURL root_url = GetFileSystemRootURI(
+ GURL("http://foo.com/"), fileapi::kFileSystemTypeTemporary);
+ FilePath root_path = FilePath().AppendASCII(root_url.spec());
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kPathToVirtualPathTestCases); ++i) {
SCOPED_TRACE(testing::Message() << "PathToVirtualPath #"
<< i << " " << kPathToVirtualPathTestCases[i]);
- FilePath absolute_path = root_path.AppendASCII(
- kPathToVirtualPathTestCases[i]);
+ FilePath absolute_path;
+ // TODO(ericu): Clean this up when we've got more sane path-handling.
+ // This hack is necessary because root_path is actually a URL [ending with a
+ // forward slash], and AppendASCII("") on Windows will delete the trailing
+ // slash, making the path invalid as far as CrackFileSystemPath is
+ // concerned.
+ if (strlen(kPathToVirtualPathTestCases[i]))
+ absolute_path = root_path.AppendASCII(
+ kPathToVirtualPathTestCases[i]);
+ else
+ absolute_path = root_path;
FilePath virtual_path;
EXPECT_TRUE(manager->CrackFileSystemPath(absolute_path, NULL, NULL,
&virtual_path));
@@ -369,19 +379,18 @@ TEST_F(FileSystemPathManagerTest, VirtualPathFromFileSystemPathTest) {
TEST_F(FileSystemPathManagerTest, TypeFromFileSystemPathTest) {
scoped_ptr<FileSystemPathManager> manager(NewPathManager(false, false));
- FilePath root_path;
fileapi::FileSystemType type;
- EXPECT_TRUE(GetRootPath(manager.get(), GURL("http://foo.com/"),
- fileapi::kFileSystemTypeTemporary,
- true /* create */, &root_path));
+ GURL root_url = GetFileSystemRootURI(
+ GURL("http://foo.com/"), fileapi::kFileSystemTypeTemporary);
+ FilePath root_path = FilePath().AppendASCII(root_url.spec());
FilePath path = root_path.AppendASCII("test");
EXPECT_TRUE(manager->CrackFileSystemPath(path, NULL, &type, NULL));
EXPECT_EQ(fileapi::kFileSystemTypeTemporary, type);
- EXPECT_TRUE(GetRootPath(manager.get(), GURL("http://foo.com/"),
- fileapi::kFileSystemTypePersistent,
- true /* create */, &root_path));
+ root_url = GetFileSystemRootURI(
+ GURL("http://foo.com/"), fileapi::kFileSystemTypePersistent);
+ root_path = FilePath().AppendASCII(root_url.spec());
path = root_path.AppendASCII("test");
EXPECT_TRUE(manager->CrackFileSystemPath(path, NULL, &type, NULL));
EXPECT_EQ(fileapi::kFileSystemTypePersistent, type);
@@ -389,9 +398,9 @@ TEST_F(FileSystemPathManagerTest, TypeFromFileSystemPathTest) {
TEST_F(FileSystemPathManagerTest, CheckValidPath) {
scoped_ptr<FileSystemPathManager> manager(NewPathManager(false, false));
- FilePath root_path;
- EXPECT_TRUE(GetRootPath(manager.get(), GURL("http://foo.com/"),
- kFileSystemTypePersistent, true, &root_path));
+ GURL root_url = GetFileSystemRootURI(
+ GURL("http://foo.com/"), fileapi::kFileSystemTypePersistent);
+ FilePath root_path = FilePath().AppendASCII(root_url.spec());
// The root path must be valid, but upper directories or directories
// that are not in our temporary or persistent directory must be
@@ -409,6 +418,9 @@ TEST_F(FileSystemPathManagerTest, CheckValidPath) {
SCOPED_TRACE(testing::Message() << "CheckValidPath #" << i << " "
<< kCheckValidPathTestCases[i].path);
FilePath path(kCheckValidPathTestCases[i].path);
+#ifdef FILE_PATH_USES_WIN_SEPARATORS
+ path = path.NormalizeWindowsPathSeparators();
+#endif
if (!path.IsAbsolute())
path = root_path.Append(path);
EXPECT_EQ(kCheckValidPathTestCases[i].expected_valid,
@@ -417,88 +429,12 @@ TEST_F(FileSystemPathManagerTest, CheckValidPath) {
}
TEST_F(FileSystemPathManagerTest, IsRestrictedName) {
+ scoped_ptr<FileSystemPathManager> manager(NewPathManager(false, false));
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kIsRestrictedNameTestCases); ++i) {
SCOPED_TRACE(testing::Message() << "IsRestrictedName #" << i << " "
<< kIsRestrictedNameTestCases[i].name);
FilePath name(kIsRestrictedNameTestCases[i].name);
EXPECT_EQ(kIsRestrictedNameTestCases[i].expected_dangerous,
- FileSystemPathManager::IsRestrictedFileName(name));
+ manager->IsRestrictedFileName(kFileSystemTypeTemporary, name));
}
}
-
-class FileSystemPathManagerOriginEnumeratorTest : public testing::Test {
- public:
- void SetUp() {
- ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
- enumerator_.reset(new FileSystemPathManager::OriginEnumerator(
- data_dir_.path()));
- }
-
- FileSystemPathManager::OriginEnumerator* enumerator() const {
- return enumerator_.get();
- }
-
- protected:
- void CreateOriginTypeDirectory(const std::string& origin_identifier,
- fileapi::FileSystemType type) {
- std::string type_string =
- FileSystemPathManager::GetFileSystemTypeString(type);
- ASSERT_TRUE(!type_string.empty());
- FilePath target = data_dir_.path().AppendASCII(origin_identifier)
- .AppendASCII(type_string);
- file_util::CreateDirectory(target);
- ASSERT_TRUE(file_util::DirectoryExists(target));
- }
-
- ScopedTempDir data_dir_;
- scoped_ptr<FileSystemPathManager::OriginEnumerator> enumerator_;
-};
-
-TEST_F(FileSystemPathManagerOriginEnumeratorTest, Empty) {
- ASSERT_TRUE(enumerator()->Next().empty());
-}
-
-TEST_F(FileSystemPathManagerOriginEnumeratorTest, EnumerateOrigins) {
- const char* temporary_origins[] = {
- "http_www.bar.com_0",
- "http_www.foo.com_0",
- "http_www.foo.com_80",
- "http_www.example.com_8080",
- "http_www.google.com_80",
- };
- const char* persistent_origins[] = {
- "http_www.bar.com_0",
- "http_www.foo.com_8080",
- "http_www.foo.com_80",
- };
- size_t temporary_size = ARRAYSIZE_UNSAFE(temporary_origins);
- size_t persistent_size = ARRAYSIZE_UNSAFE(persistent_origins);
- std::set<std::string> temporary_set, persistent_set;
- for (size_t i = 0; i < temporary_size; ++i) {
- CreateOriginTypeDirectory(temporary_origins[i],
- fileapi::kFileSystemTypeTemporary);
- temporary_set.insert(temporary_origins[i]);
- }
- for (size_t i = 0; i < persistent_size; ++i) {
- CreateOriginTypeDirectory(persistent_origins[i], kFileSystemTypePersistent);
- persistent_set.insert(persistent_origins[i]);
- }
-
- size_t temporary_actual_size = 0;
- size_t persistent_actual_size = 0;
- std::string current;
- while (!(current = enumerator()->Next()).empty()) {
- SCOPED_TRACE(testing::Message() << "EnumerateOrigin " << current);
- if (enumerator()->HasTemporary()) {
- ASSERT_TRUE(temporary_set.find(current) != temporary_set.end());
- ++temporary_actual_size;
- }
- if (enumerator()->HasPersistent()) {
- ASSERT_TRUE(persistent_set.find(current) != persistent_set.end());
- ++persistent_actual_size;
- }
- }
-
- ASSERT_EQ(temporary_size, temporary_actual_size);
- ASSERT_EQ(persistent_size, persistent_actual_size);
-}
diff --git a/webkit/fileapi/file_system_usage_tracker.cc b/webkit/fileapi/file_system_usage_tracker.cc
index 9456f2a..85498d3 100644
--- a/webkit/fileapi/file_system_usage_tracker.cc
+++ b/webkit/fileapi/file_system_usage_tracker.cc
@@ -15,6 +15,7 @@
#include "googleurl/src/gurl.h"
#include "webkit/fileapi/file_system_path_manager.h"
#include "webkit/fileapi/file_system_usage_cache.h"
+#include "webkit/fileapi/sandbox_mount_point_provider.h"
namespace fileapi {
@@ -98,7 +99,7 @@ FileSystemUsageTracker::FileSystemUsageTracker(
bool is_incognito)
: file_message_loop_(file_message_loop),
base_path_(profile_path.Append(
- FileSystemPathManager::kFileSystemDirectory)),
+ SandboxMountPointProvider::kFileSystemDirectory)),
is_incognito_(is_incognito) {
DCHECK(file_message_loop);
}
@@ -123,7 +124,7 @@ void FileSystemUsageTracker::GetOriginUsage(
}
std::string origin_identifier =
- FileSystemPathManager::GetOriginIdentifierFromURL(origin_url);
+ SandboxMountPointProvider::GetOriginIdentifierFromURL(origin_url);
std::string type_string =
FileSystemPathManager::GetFileSystemTypeString(type);
std::string fs_identifier = origin_identifier + ":" + type_string;
@@ -139,7 +140,7 @@ void FileSystemUsageTracker::GetOriginUsage(
// Get the filesystem base path (i.e. "FileSystem/<origin>/<type>",
// without unique part).
FilePath origin_base_path =
- FileSystemPathManager::GetFileSystemBaseDirectoryForOriginAndType(
+ SandboxMountPointProvider::GetFileSystemBaseDirectoryForOriginAndType(
base_path_, origin_identifier, type);
if (origin_base_path.empty()) {
// The directory does not exist.
diff --git a/webkit/fileapi/file_system_usage_tracker.h b/webkit/fileapi/file_system_usage_tracker.h
index 10a5177..af292a1 100644
--- a/webkit/fileapi/file_system_usage_tracker.h
+++ b/webkit/fileapi/file_system_usage_tracker.h
@@ -24,11 +24,10 @@ class MessageLoopProxy;
namespace fileapi {
-// Owned by the SandboxedFileSystemContext, which is a per-profile
-// instance, and has the same lifetime as the SandboxedFileSystemContext.
-// It's going to be created and destroyed on the IO thread in chrome.
-// (The destruction on the same thread where it is created was guaranteed
-// by its owner, SandboxedFileSystemContext.)
+// Owned by the FileSystemContext, which is a per-profile instance, and has the
+// same lifetime as the FileSystemContext. It's going to be created and
+// destroyed on the IO thread in chrome. (The destruction on the same thread
+// where it is created was guaranteed by its owner, FileSystemContext.)
class FileSystemUsageTracker {
public:
FileSystemUsageTracker(
diff --git a/webkit/fileapi/file_system_usage_tracker_unittest.cc b/webkit/fileapi/file_system_usage_tracker_unittest.cc
index 8d0c2c0..a78aba3 100644
--- a/webkit/fileapi/file_system_usage_tracker_unittest.cc
+++ b/webkit/fileapi/file_system_usage_tracker_unittest.cc
@@ -13,9 +13,9 @@
#include "googleurl/src/gurl.h"
#include "base/scoped_temp_dir.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/fileapi/file_system_path_manager.h"
#include "webkit/fileapi/file_system_types.h"
#include "webkit/fileapi/file_system_usage_cache.h"
+#include "webkit/fileapi/sandbox_mount_point_provider.h"
using namespace fileapi;
@@ -71,10 +71,10 @@ class FileSystemUsageTrackerTest : public testing::Test {
FilePath GetOriginBasePath(const GURL& origin_url,
fileapi::FileSystemType type) {
return
- FileSystemPathManager::GetFileSystemBaseDirectoryForOriginAndType(
+ SandboxMountPointProvider::GetFileSystemBaseDirectoryForOriginAndType(
data_dir_.path().Append(
- FileSystemPathManager::kFileSystemDirectory),
- FileSystemPathManager::GetOriginIdentifierFromURL(origin_url),
+ SandboxMountPointProvider::kFileSystemDirectory),
+ SandboxMountPointProvider::GetOriginIdentifierFromURL(origin_url),
type);
}
diff --git a/webkit/fileapi/file_system_util.cc b/webkit/fileapi/file_system_util.cc
index 07aa5a6..ae36fa850 100644
--- a/webkit/fileapi/file_system_util.cc
+++ b/webkit/fileapi/file_system_util.cc
@@ -7,6 +7,7 @@
#include "build/build_config.h"
#include "base/file_path.h"
+#include "base/logging.h"
#include "base/sys_string_conversions.h"
#include "googleurl/src/gurl.h"
#include "net/base/escape.h"
@@ -19,27 +20,61 @@ static const char kTemporaryDir[] = "/temporary/";
bool CrackFileSystemURL(const GURL& url, GURL* origin_url, FileSystemType* type,
FilePath* file_path) {
- *origin_url = GURL();
- *type = kFileSystemTypeUnknown;
- *file_path = FilePath();
+ GURL origin;
+ FileSystemType file_system_type;
if (url.scheme() != "filesystem")
return false;
- GURL bare_url(url.path());
- *origin_url = bare_url.GetOrigin();
+ std::string temp = url.path();
+ // TODO(ericu) remove this code when that ceases to be true, which should be
+ // soon.
+ // On Windows, this will have backslashes for now.
+ // url will look something like:
+ // filesystem:http://example.com/temporary/\dir\file.txt
+ // temp will look something like:
+ // http://example.com/temporary/\dir\file.txt
+ // On posix, url will look something like:
+ // filesystem:http://example.com/temporary/dir/file.txt
+ // temp will look something like:
+ // http://example.com/temporary/dir/file.txt
+ size_t pos = temp.find('\\');
+ for (; pos != std::string::npos; pos = temp.find('\\', pos + 1)) {
+ temp[pos] = '/';
+ }
+ // TODO(ericu): This should probably be done elsewhere after the stackable
+ // layers are properly in. We're supposed to reject any paths that contain
+ // '..' segments, but the GURL constructor is helpfully resolving them for us.
+ // Make sure there aren't any before we call it.
+ pos = temp.find("..");
+ for (; pos != std::string::npos; pos = temp.find("..", pos + 1)) {
+ if ((pos == 0 || temp[pos - 1] == '/') &&
+ (pos == temp.length() - 2 || temp[pos + 2] == '/'))
+ return false;
+ }
+
+ // bare_url will look something like:
+ // http://example.com/temporary//dir/file.txt [on Windows; the double slash
+ // before dir will be single on posix].
+ GURL bare_url(temp);
+
+ // The input URL was malformed, bail out early.
+ if (bare_url.path().empty())
+ return false;
+
+ origin = bare_url.GetOrigin();
// The input URL was malformed, bail out early.
- if (origin_url->is_empty() || bare_url.path().empty())
+ if (origin.is_empty())
return false;
std::string path = UnescapeURLComponent(bare_url.path(),
UnescapeRule::SPACES | UnescapeRule::URL_SPECIAL_CHARS);
if (path.compare(0, strlen(kPersistentDir), kPersistentDir) == 0) {
- *type = kFileSystemTypePersistent;
+ file_system_type = kFileSystemTypePersistent;
path = path.substr(strlen(kPersistentDir));
} else if (path.compare(0, strlen(kTemporaryDir), kTemporaryDir) == 0) {
- *type = kFileSystemTypeTemporary;
+ file_system_type = kFileSystemTypeTemporary;
path = path.substr(strlen(kTemporaryDir));
} else {
return false;
@@ -50,13 +85,36 @@ bool CrackFileSystemURL(const GURL& url, GURL* origin_url, FileSystemType* type,
path.erase(0, 1);
#if defined(OS_WIN)
- const FilePath::StringType& sys_path = base::SysUTF8ToWide(path);
+ const FilePath::StringType sys_path = base::SysUTF8ToWide(path);
#elif defined(OS_POSIX)
- const FilePath::StringType& sys_path = path;
+ const FilePath::StringType sys_path = path;
#endif
+ if (origin_url)
+ *origin_url = origin;
+ if (type)
+ *type = file_system_type;
+ if (file_path)
+ *file_path = FilePath(sys_path);
- *file_path = FilePath(sys_path);
return true;
}
+GURL GetFileSystemRootURI(
+ const GURL& origin_url, fileapi::FileSystemType type) {
+ std::string path("filesystem:");
+ path += origin_url.spec();
+ switch (type) {
+ case kFileSystemTypeTemporary:
+ path += (kTemporaryDir + 1); // We don't want the leading slash.
+ break;
+ case kFileSystemTypePersistent:
+ path += (kPersistentDir + 1); // We don't want the leading slash.
+ break;
+ default:
+ NOTREACHED();
+ return GURL();
+ }
+ return GURL(path);
+}
+
} // namespace fileapi
diff --git a/webkit/fileapi/file_system_util.h b/webkit/fileapi/file_system_util.h
index 4331b1a..b858c1b 100644
--- a/webkit/fileapi/file_system_util.h
+++ b/webkit/fileapi/file_system_util.h
@@ -13,9 +13,13 @@ class GURL;
namespace fileapi {
+// The file_path this returns will be using '/' as a path separator, no matter
+// what platform you're on.
bool CrackFileSystemURL(const GURL& url, GURL* origin_url, FileSystemType* type,
FilePath* file_path);
+GURL GetFileSystemRootURI(const GURL& origin_url, fileapi::FileSystemType type);
+
} // namespace fileapi
#endif // WEBKIT_FILEAPI_FILE_SYSTEM_UTIL_H_
diff --git a/webkit/fileapi/file_system_util_unittest.cc b/webkit/fileapi/file_system_util_unittest.cc
index 7cb4c59..e08fec7 100644
--- a/webkit/fileapi/file_system_util_unittest.cc
+++ b/webkit/fileapi/file_system_util_unittest.cc
@@ -71,5 +71,19 @@ TEST_F(FileSystemUtilTest, RejectMalformedURL) {
EXPECT_FALSE(CrackFileSystemURL("filesystem:foobar/file"));
}
+TEST_F(FileSystemUtilTest, GetTempFileSystemRootURI) {
+ GURL origin_url("http://chromium.org");
+ fileapi::FileSystemType type = fileapi::kFileSystemTypeTemporary;
+ GURL uri = GURL("filesystem:http://chromium.org/temporary/");
+ EXPECT_EQ(uri, GetFileSystemRootURI(origin_url, type));
+}
+
+TEST_F(FileSystemUtilTest, GetPersistentFileSystemRootURI) {
+ GURL origin_url("http://chromium.org");
+ fileapi::FileSystemType type = fileapi::kFileSystemTypePersistent;
+ GURL uri = GURL("filesystem:http://chromium.org/persistent/");
+ EXPECT_EQ(uri, GetFileSystemRootURI(origin_url, type));
+}
+
} // namespace (anonymous)
} // namespace fileapi
diff --git a/webkit/fileapi/local_file_system_file_util.cc b/webkit/fileapi/local_file_system_file_util.cc
new file mode 100644
index 0000000..a017d57
--- /dev/null
+++ b/webkit/fileapi/local_file_system_file_util.cc
@@ -0,0 +1,178 @@
+// Copyright (c) 2011 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/local_file_system_file_util.h"
+
+#include "base/file_util_proxy.h"
+#include "googleurl/src/gurl.h"
+#include "webkit/fileapi/file_system_context.h"
+#include "webkit/fileapi/file_system_operation_context.h"
+#include "webkit/fileapi/file_system_path_manager.h"
+#include "webkit/fileapi/file_system_types.h"
+#include "webkit/fileapi/file_system_util.h"
+
+namespace fileapi {
+
+LocalFileSystemFileUtil* LocalFileSystemFileUtil::GetInstance() {
+ return Singleton<LocalFileSystemFileUtil>::get();
+}
+
+PlatformFileError LocalFileSystemFileUtil::CreateOrOpen(
+ FileSystemOperationContext* context,
+ const FilePath& file_path, int file_flags,
+ PlatformFile* file_handle, bool* created) {
+ FilePath local_path =
+ GetLocalPath(context, context->src_origin_url(), context->src_type(),
+ file_path);
+ if (local_path.empty())
+ return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
+ return FileSystemFileUtil::GetInstance()->CreateOrOpen(
+ context, local_path, file_flags, file_handle, created);
+}
+
+PlatformFileError LocalFileSystemFileUtil::EnsureFileExists(
+ FileSystemOperationContext* context,
+ const FilePath& file_path,
+ bool* created) {
+ FilePath local_path =
+ GetLocalPath(context, context->src_origin_url(), context->src_type(),
+ file_path);
+ if (local_path.empty())
+ return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
+ return FileSystemFileUtil::GetInstance()->EnsureFileExists(
+ context, local_path, created);
+}
+
+PlatformFileError LocalFileSystemFileUtil::GetFileInfo(
+ FileSystemOperationContext* context,
+ const FilePath& file_path,
+ base::PlatformFileInfo* file_info) {
+ FilePath local_path =
+ GetLocalPath(context, context->src_origin_url(), context->src_type(),
+ file_path);
+ if (local_path.empty())
+ return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
+ return FileSystemFileUtil::GetInstance()->GetFileInfo(
+ context, local_path, file_info);
+}
+
+PlatformFileError LocalFileSystemFileUtil::ReadDirectory(
+ FileSystemOperationContext* context,
+ const FilePath& file_path,
+ std::vector<base::FileUtilProxy::Entry>* entries) {
+ // TODO(kkanetkar): Implement directory read in multiple chunks.
+ FilePath local_path =
+ GetLocalPath(context, context->src_origin_url(), context->src_type(),
+ file_path);
+ if (local_path.empty())
+ return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
+ return FileSystemFileUtil::GetInstance()->ReadDirectory(
+ context, local_path, entries);
+}
+
+PlatformFileError LocalFileSystemFileUtil::CreateDirectory(
+ FileSystemOperationContext* context,
+ const FilePath& file_path,
+ bool exclusive,
+ bool recursive) {
+ FilePath local_path =
+ GetLocalPath(context, context->src_origin_url(), context->src_type(),
+ file_path);
+ if (local_path.empty())
+ return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
+ return FileSystemFileUtil::GetInstance()->CreateDirectory(
+ context, local_path, exclusive, recursive);
+}
+
+PlatformFileError LocalFileSystemFileUtil::Copy(
+ FileSystemOperationContext* context,
+ const FilePath& src_file_path,
+ const FilePath& dest_file_path) {
+ // TODO(ericu): If they share a root URL, this could be optimized.
+ FilePath local_src_path =
+ GetLocalPath(context, context->src_origin_url(), context->src_type(),
+ src_file_path);
+ if (local_src_path.empty())
+ return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
+ FilePath local_dest_path =
+ GetLocalPath(context, context->dest_origin_url(), context->dest_type(),
+ dest_file_path);
+ if (local_dest_path.empty())
+ return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
+ return FileSystemFileUtil::GetInstance()->Copy(
+ context, local_src_path, local_dest_path);
+}
+
+PlatformFileError LocalFileSystemFileUtil::Move(
+ FileSystemOperationContext* context,
+ const FilePath& src_file_path,
+ const FilePath& dest_file_path) {
+ // TODO(ericu): If they share a root URL, this could be optimized.
+ FilePath local_src_path =
+ GetLocalPath(context, context->src_origin_url(), context->src_type(),
+ src_file_path);
+ if (local_src_path.empty())
+ return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
+ FilePath local_dest_path =
+ GetLocalPath(context, context->dest_origin_url(), context->dest_type(),
+ dest_file_path);
+ if (local_dest_path.empty())
+ return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
+ return FileSystemFileUtil::GetInstance()->Move(
+ context, local_src_path, local_dest_path);
+}
+
+PlatformFileError LocalFileSystemFileUtil::Delete(
+ FileSystemOperationContext* context,
+ const FilePath& file_path,
+ bool recursive) {
+ FilePath local_path =
+ GetLocalPath(context, context->src_origin_url(), context->src_type(),
+ file_path);
+ if (local_path.empty())
+ return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
+ return FileSystemFileUtil::GetInstance()->Delete(
+ context, local_path, recursive);
+}
+
+PlatformFileError LocalFileSystemFileUtil::Touch(
+ FileSystemOperationContext* context,
+ const FilePath& file_path,
+ const base::Time& last_access_time,
+ const base::Time& last_modified_time) {
+ FilePath local_path =
+ GetLocalPath(context, context->src_origin_url(), context->src_type(),
+ file_path);
+ if (local_path.empty())
+ return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
+ return FileSystemFileUtil::GetInstance()->Touch(
+ context, local_path, last_access_time, last_modified_time);
+}
+
+PlatformFileError LocalFileSystemFileUtil::Truncate(
+ FileSystemOperationContext* context,
+ const FilePath& file_path,
+ int64 length) {
+ FilePath local_path =
+ GetLocalPath(context, context->src_origin_url(), context->src_type(),
+ file_path);
+ if (local_path.empty())
+ return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
+ return FileSystemFileUtil::GetInstance()->Truncate(
+ context, local_path, length);
+}
+
+FilePath LocalFileSystemFileUtil::GetLocalPath(
+ FileSystemOperationContext* context,
+ const GURL& origin_url,
+ FileSystemType type,
+ const FilePath& virtual_path) {
+ FilePath root = context->file_system_context()->path_manager()->
+ GetFileSystemRootPathOnFileThread(origin_url, type, false);
+ if (root.empty())
+ return FilePath();
+ return root.Append(virtual_path);
+}
+
+} // namespace fileapi
diff --git a/webkit/fileapi/local_file_system_file_util.h b/webkit/fileapi/local_file_system_file_util.h
new file mode 100644
index 0000000..6fc2e11
--- /dev/null
+++ b/webkit/fileapi/local_file_system_file_util.h
@@ -0,0 +1,112 @@
+// Copyright (c) 2011 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_LOCAL_FILE_SYSTEM_FILE_UTIL_H_
+#define WEBKIT_FILEAPI_LOCAL_FILE_SYSTEM_FILE_UTIL_H_
+
+#include <vector>
+
+#include "base/callback.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/file_util_proxy.h"
+#include "base/logging.h"
+#include "base/platform_file.h"
+#include "base/ref_counted.h"
+#include "base/singleton.h"
+#include "base/tracked_objects.h"
+#include "webkit/fileapi/file_system_file_util.h"
+#include "webkit/fileapi/file_system_types.h"
+
+namespace base {
+struct PlatformFileInfo;
+class MessageLoopProxy;
+class Time;
+}
+
+class GURL;
+
+namespace fileapi {
+
+using base::PlatformFile;
+using base::PlatformFileError;
+
+class FileSystemOperationContext;
+
+class LocalFileSystemFileUtil : public FileSystemFileUtil {
+ public:
+ static LocalFileSystemFileUtil* GetInstance();
+
+ virtual PlatformFileError CreateOrOpen(
+ FileSystemOperationContext* context,
+ const FilePath& file_path,
+ int file_flags,
+ PlatformFile* file_handle,
+ bool* created);
+
+ virtual PlatformFileError EnsureFileExists(
+ FileSystemOperationContext* context,
+ const FilePath& file_path, bool* created);
+
+ virtual PlatformFileError GetFileInfo(
+ FileSystemOperationContext* context,
+ const FilePath& file_, base::PlatformFileInfo* file_info);
+
+ virtual PlatformFileError ReadDirectory(
+ FileSystemOperationContext* context,
+ const FilePath& file_path,
+ std::vector<base::FileUtilProxy::Entry>* entries);
+
+ virtual PlatformFileError CreateDirectory(
+ FileSystemOperationContext* context,
+ const FilePath& file_path,
+ bool exclusive,
+ bool recursive);
+
+ virtual PlatformFileError Copy(
+ FileSystemOperationContext* context,
+ const FilePath& src_file_path,
+ const FilePath& dest_file_path);
+
+ virtual PlatformFileError Move(
+ FileSystemOperationContext* context,
+ const FilePath& src_file_path,
+ const FilePath& dest_file_path);
+
+ virtual PlatformFileError Delete(
+ FileSystemOperationContext* context,
+ const FilePath& file_path,
+ bool recursive);
+
+ virtual PlatformFileError Touch(
+ FileSystemOperationContext* context,
+ const FilePath& file_path,
+ const base::Time& last_access_time,
+ const base::Time& last_modified_time);
+
+ virtual PlatformFileError Truncate(
+ FileSystemOperationContext* context,
+ const FilePath& path,
+ int64 length);
+
+ protected:
+ LocalFileSystemFileUtil() { }
+
+ friend struct DefaultSingletonTraits<LocalFileSystemFileUtil>;
+ DISALLOW_COPY_AND_ASSIGN(LocalFileSystemFileUtil);
+
+ private:
+ // Given the filesystem's root URL and a virtual path, produces a real, full
+ // local path.
+ FilePath GetLocalPath(
+ FileSystemOperationContext* context,
+ const GURL& origin_url,
+ FileSystemType type,
+ const FilePath& virtual_path);
+
+};
+
+} // namespace fileapi
+
+#endif // WEBKIT_FILEAPI_LOCAL_FILE_SYSTEM_FILE_UTIL_H_
diff --git a/webkit/fileapi/sandbox_mount_point_provider.cc b/webkit/fileapi/sandbox_mount_point_provider.cc
new file mode 100644
index 0000000..ac82cc8
--- /dev/null
+++ b/webkit/fileapi/sandbox_mount_point_provider.cc
@@ -0,0 +1,312 @@
+// Copyright (c) 2011 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/sandbox_mount_point_provider.h"
+
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/message_loop_proxy.h"
+#include "base/rand_util.h"
+#include "base/scoped_callback_factory.h"
+#include "base/scoped_ptr.h"
+#include "base/string_util.h"
+#include "base/stringprintf.h"
+#include "base/utf_string_conversions.h"
+#include "googleurl/src/gurl.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebCString.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h"
+#include "webkit/fileapi/file_system_path_manager.h"
+#include "webkit/fileapi/file_system_util.h"
+#include "webkit/glue/webkit_glue.h"
+
+namespace {
+
+static const FilePath::CharType kFileSystemUniqueNamePrefix[] =
+ FILE_PATH_LITERAL("chrome-");
+static const int kFileSystemUniqueLength = 16;
+static const unsigned kFileSystemUniqueDirectoryNameLength =
+ kFileSystemUniqueLength + arraysize(kFileSystemUniqueNamePrefix) - 1;
+
+// Restricted names.
+// http://dev.w3.org/2009/dap/file-system/file-dir-sys.html#naming-restrictions
+static const char* const kRestrictedNames[] = {
+ "con", "prn", "aux", "nul",
+ "com1", "com2", "com3", "com4", "com5", "com6", "com7", "com8", "com9",
+ "lpt1", "lpt2", "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9",
+};
+
+// Restricted chars.
+static const FilePath::CharType kRestrictedChars[] = {
+ '/', '\\', '<', '>', ':', '?', '*', '"', '|',
+};
+
+inline std::string FilePathStringToASCII(
+ const FilePath::StringType& path_string) {
+#if defined(OS_WIN)
+ return WideToASCII(path_string);
+#elif defined(OS_POSIX)
+ return path_string;
+#endif
+}
+
+FilePath::StringType CreateUniqueDirectoryName(const GURL& origin_url) {
+ // This can be anything but need to be unpredictable.
+ static const FilePath::CharType letters[] = FILE_PATH_LITERAL(
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
+ FilePath::StringType unique(kFileSystemUniqueNamePrefix);
+ for (int i = 0; i < kFileSystemUniqueLength; ++i)
+ unique += letters[base::RandInt(0, arraysize(letters) - 2)];
+ return unique;
+}
+
+bool ReadOriginDirectory(const FilePath& base_path,
+ const GURL& origin_url,
+ FilePath* unique) {
+ file_util::FileEnumerator file_enum(
+ base_path, false /* recursive */,
+ file_util::FileEnumerator::DIRECTORIES,
+ FilePath::StringType(kFileSystemUniqueNamePrefix) +
+ FILE_PATH_LITERAL("*"));
+ FilePath current;
+ bool found = false;
+ while (!(current = file_enum.Next()).empty()) {
+ if (current.BaseName().value().length() !=
+ kFileSystemUniqueDirectoryNameLength)
+ continue;
+ if (found) {
+ // TODO(kinuko): Should notify the user to ask for some action.
+ LOG(WARNING) << "Unexpectedly found more than one FileSystem "
+ << "directories for " << origin_url;
+ return false;
+ }
+ found = true;
+ *unique = current;
+ }
+ return !unique->empty();
+}
+
+FilePath GetFileSystemRootPathOnFileThreadHelper(
+ const GURL& origin_url, const FilePath &origin_base_path, bool create) {
+ FilePath root;
+ if (ReadOriginDirectory(origin_base_path, origin_url, &root))
+ return root;
+
+ if (!create)
+ return FilePath();
+
+ // Creates the root directory.
+ root = origin_base_path.Append(CreateUniqueDirectoryName(origin_url));
+ if (!file_util::CreateDirectory(root))
+ return FilePath();
+
+ return root;
+}
+
+} // anonymous namespace
+
+namespace fileapi {
+
+const FilePath::CharType SandboxMountPointProvider::kFileSystemDirectory[] =
+ FILE_PATH_LITERAL("FileSystem");
+
+const char SandboxMountPointProvider::kPersistentName[] = "Persistent";
+const char SandboxMountPointProvider::kTemporaryName[] = "Temporary";
+
+SandboxMountPointProvider::SandboxMountPointProvider(
+ FileSystemPathManager* path_manager,
+ scoped_refptr<base::MessageLoopProxy> file_message_loop,
+ const FilePath& profile_path)
+ : path_manager_(path_manager),
+ file_message_loop_(file_message_loop),
+ base_path_(profile_path.Append(kFileSystemDirectory)) {
+}
+
+bool SandboxMountPointProvider::IsAccessAllowed(const GURL& origin_url) {
+ // We essentially depend on quota to do our access controls.
+ return path_manager_->IsAllowedScheme(origin_url);
+}
+
+class SandboxMountPointProvider::GetFileSystemRootPathTask
+ : public base::RefCountedThreadSafe<
+ SandboxMountPointProvider::GetFileSystemRootPathTask> {
+ public:
+ GetFileSystemRootPathTask(
+ scoped_refptr<base::MessageLoopProxy> file_message_loop,
+ const std::string& name,
+ FileSystemPathManager::GetRootPathCallback* callback)
+ : file_message_loop_(file_message_loop),
+ origin_message_loop_proxy_(
+ base::MessageLoopProxy::CreateForCurrentThread()),
+ name_(name),
+ callback_(callback) {
+ }
+
+ void Start(const GURL& origin_url,
+ const FilePath& origin_base_path,
+ bool create) {
+ file_message_loop_->PostTask(FROM_HERE, NewRunnableMethod(this,
+ &GetFileSystemRootPathTask::GetFileSystemRootPathOnFileThread,
+ origin_url, origin_base_path, create));
+ }
+
+ private:
+ void GetFileSystemRootPathOnFileThread(
+ const GURL& origin_url,
+ const FilePath& origin_base_path,
+ bool create) {
+ DispatchCallbackOnCallerThread(
+ GetFileSystemRootPathOnFileThreadHelper(
+ origin_url, origin_base_path, create));
+ }
+
+ void DispatchCallbackOnCallerThread(const FilePath& root_path) {
+ origin_message_loop_proxy_->PostTask(FROM_HERE,
+ NewRunnableMethod(this, &GetFileSystemRootPathTask::DispatchCallback,
+ root_path));
+ }
+
+ void DispatchCallback(const FilePath& root_path) {
+ callback_->Run(!root_path.empty(), root_path, name_);
+ callback_.reset();
+ }
+
+ scoped_refptr<base::MessageLoopProxy> file_message_loop_;
+ scoped_refptr<base::MessageLoopProxy> origin_message_loop_proxy_;
+ std::string name_;
+ scoped_ptr<FileSystemPathManager::GetRootPathCallback> callback_;
+};
+
+bool SandboxMountPointProvider::IsRestrictedFileName(const FilePath& filename)
+ const {
+ if (filename.value().empty())
+ return false;
+
+ if (IsWhitespace(filename.value()[filename.value().size() - 1]) ||
+ filename.value()[filename.value().size() - 1] == '.')
+ return true;
+
+ std::string filename_lower = StringToLowerASCII(
+ FilePathStringToASCII(filename.value()));
+
+ for (size_t i = 0; i < arraysize(kRestrictedNames); ++i) {
+ // Exact match.
+ if (filename_lower == kRestrictedNames[i])
+ return true;
+ // Starts with "RESTRICTED_NAME.".
+ if (filename_lower.find(std::string(kRestrictedNames[i]) + ".") == 0)
+ return true;
+ }
+
+ for (size_t i = 0; i < arraysize(kRestrictedChars); ++i) {
+ if (filename.value().find(kRestrictedChars[i]) !=
+ FilePath::StringType::npos)
+ return true;
+ }
+
+ return false;
+}
+
+void SandboxMountPointProvider::GetFileSystemRootPath(
+ const GURL& origin_url, fileapi::FileSystemType type,
+ bool create, FileSystemPathManager::GetRootPathCallback* callback_ptr) {
+ scoped_ptr<FileSystemPathManager::GetRootPathCallback> callback(callback_ptr);
+ std::string name;
+ FilePath origin_base_path;
+
+ if (!GetOriginBasePathAndName(origin_url, &origin_base_path, type, &name)) {
+ callback->Run(false, FilePath(), std::string());
+ return;
+ }
+
+ scoped_refptr<GetFileSystemRootPathTask> task(
+ new GetFileSystemRootPathTask(file_message_loop_,
+ name,
+ callback.release()));
+ task->Start(origin_url, origin_base_path, create);
+};
+
+FilePath SandboxMountPointProvider::GetFileSystemRootPathOnFileThread(
+ const GURL& origin_url, FileSystemType type, bool create) {
+ FilePath origin_base_path;
+ if (!GetOriginBasePathAndName(origin_url, &origin_base_path, type, NULL)) {
+ return FilePath();
+ }
+ return GetFileSystemRootPathOnFileThreadHelper(
+ origin_url, origin_base_path, create);
+}
+
+// static
+std::string SandboxMountPointProvider::GetOriginIdentifierFromURL(
+ const GURL& url) {
+ WebKit::WebSecurityOrigin web_security_origin =
+ WebKit::WebSecurityOrigin::createFromString(UTF8ToUTF16(url.spec()));
+ return web_security_origin.databaseIdentifier().utf8();
+}
+
+// static
+FilePath SandboxMountPointProvider::GetFileSystemBaseDirectoryForOriginAndType(
+ const FilePath& base_path, const std::string& origin_identifier,
+ fileapi::FileSystemType type) {
+ if (origin_identifier.empty())
+ return FilePath();
+ std::string type_string =
+ FileSystemPathManager::GetFileSystemTypeString(type);
+ if (type_string.empty()) {
+ LOG(WARNING) << "Unknown filesystem type is requested:" << type;
+ return FilePath();
+ }
+ return base_path.AppendASCII(origin_identifier)
+ .AppendASCII(type_string);
+}
+
+SandboxMountPointProvider::OriginEnumerator::OriginEnumerator(
+ const FilePath& base_path)
+ : enumerator_(base_path, false /* recursive */,
+ file_util::FileEnumerator::DIRECTORIES) {
+}
+
+std::string SandboxMountPointProvider::OriginEnumerator::Next() {
+ current_ = enumerator_.Next();
+ return FilePathStringToASCII(current_.BaseName().value());
+}
+
+bool SandboxMountPointProvider::OriginEnumerator::HasTemporary() {
+ return !current_.empty() && file_util::DirectoryExists(current_.AppendASCII(
+ SandboxMountPointProvider::kTemporaryName));
+}
+
+bool SandboxMountPointProvider::OriginEnumerator::HasPersistent() {
+ return !current_.empty() && file_util::DirectoryExists(current_.AppendASCII(
+ SandboxMountPointProvider::kPersistentName));
+}
+
+bool SandboxMountPointProvider::GetOriginBasePathAndName(
+ const GURL& origin_url,
+ FilePath* origin_base_path,
+ FileSystemType type,
+ std::string* name) {
+
+ if (path_manager_->is_incognito())
+ // TODO(kinuko): return an isolated temporary directory.
+ return false;
+
+ if (!path_manager_->IsAllowedScheme(origin_url))
+ return false;
+
+ std::string origin_identifier = GetOriginIdentifierFromURL(origin_url);
+ *origin_base_path = GetFileSystemBaseDirectoryForOriginAndType(
+ base_path(), origin_identifier, type);
+ if (origin_base_path->empty())
+ return false;
+
+ std::string type_string =
+ FileSystemPathManager::GetFileSystemTypeString(type);
+ DCHECK(!type_string.empty());
+ if (name)
+ *name = origin_identifier + ":" + type_string;
+ return true;
+}
+
+} // namespace fileapi
diff --git a/webkit/fileapi/sandbox_mount_point_provider.h b/webkit/fileapi/sandbox_mount_point_provider.h
new file mode 100644
index 0000000..d981cc8
--- /dev/null
+++ b/webkit/fileapi/sandbox_mount_point_provider.h
@@ -0,0 +1,120 @@
+// Copyright (c) 2011 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_SANDBOX_MOUNT_POINT_PROVIDER_H_
+#define WEBKIT_FILEAPI_SANDBOX_MOUNT_POINT_PROVIDER_H_
+
+#include <string>
+
+#include "base/file_path.h"
+#include "googleurl/src/gurl.h"
+#include "webkit/fileapi/file_system_mount_point_provider.h"
+
+class GURL;
+
+namespace base {
+class MessageLoopProxy;
+}
+
+namespace fileapi {
+
+class SandboxMountPointProvider : public FileSystemMountPointProvider {
+ public:
+
+ SandboxMountPointProvider(
+ FileSystemPathManager* path_manager,
+ scoped_refptr<base::MessageLoopProxy> file_message_loop,
+ const FilePath& profile_path);
+
+ // Checks if mount point access is allowed from |origin_url|.
+ virtual bool IsAccessAllowed(const GURL& origin_url);
+
+ // Retrieves the root path for the given |origin_url| and |type|, and
+ // calls the given |callback| with the root path and name.
+ // If |create| is true this also creates the directory if it doesn't exist.
+ void GetFileSystemRootPath(
+ const GURL& origin_url,
+ FileSystemType type,
+ bool create,
+ FileSystemPathManager::GetRootPathCallback* callback);
+
+ // Like GetFileSystemRootPath, but synchronous, and can be called only while
+ // running on the file thread.
+ FilePath GetFileSystemRootPathOnFileThread(
+ const GURL& origin_url,
+ FileSystemType type,
+ bool create);
+
+ // The FileSystem directory name.
+ static const FilePath::CharType kFileSystemDirectory[];
+
+ static const char kPersistentName[];
+ static const char kTemporaryName[];
+
+ const FilePath& base_path() const {
+ return base_path_;
+ }
+
+ // Checks if a given |name| contains any restricted names/chars in it.
+ virtual bool IsRestrictedFileName(const FilePath& filename) const;
+
+ // Returns the origin identifier string, which is used as a part of the
+ // sandboxed path component, for the given |url|.
+ static std::string GetOriginIdentifierFromURL(const GURL& url);
+
+ // Gets a base directory path of the sandboxed filesystem that is
+ // specified by |origin_identifier| and |type|.
+ // |base_path| must be pointing the FileSystem's data directory
+ // under the profile directory, i.e. <profile_dir>/kFileSystemDirectory.
+ // Returns an empty path if any of the given parameters are invalid.
+ // Returned directory path does not contain 'unique' part, therefore
+ // it is not an actual root path for the filesystem.
+ static FilePath GetFileSystemBaseDirectoryForOriginAndType(
+ const FilePath& base_path,
+ const std::string& origin_identifier,
+ fileapi::FileSystemType type);
+
+ // Enumerates origins under the given |base_path|.
+ // This must be used on the FILE thread.
+ class OriginEnumerator {
+ public:
+ explicit OriginEnumerator(const FilePath& base_path);
+
+ // Returns the next origin identifier. Returns empty if there are no
+ // more origins.
+ std::string Next();
+
+ bool HasTemporary();
+ bool HasPersistent();
+ const FilePath& path() { return current_; }
+
+ private:
+ file_util::FileEnumerator enumerator_;
+ FilePath current_;
+ };
+
+ private:
+ bool GetOriginBasePathAndName(
+ const GURL& origin_url,
+ FilePath* base_path,
+ FileSystemType type,
+ std::string* name);
+
+ class GetFileSystemRootPathTask;
+
+ // The path_manager_ isn't owned by this instance; this instance is owned by
+ // the path_manager_, and they have the same lifetime.
+ FileSystemPathManager* path_manager_;
+
+ scoped_refptr<base::MessageLoopProxy> file_message_loop_;
+
+ const FilePath base_path_;
+
+ DISALLOW_COPY_AND_ASSIGN(SandboxMountPointProvider);
+};
+
+} // namespace fileapi
+
+#endif // WEBKIT_FILEAPI_SANDBOX_MOUNT_POINT_PROVIDER_H_
+
diff --git a/webkit/fileapi/sandbox_mount_point_provider_unittest.cc b/webkit/fileapi/sandbox_mount_point_provider_unittest.cc
new file mode 100644
index 0000000..f4d12a5f
--- /dev/null
+++ b/webkit/fileapi/sandbox_mount_point_provider_unittest.cc
@@ -0,0 +1,100 @@
+// Copyright (c) 2010 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/sandbox_mount_point_provider.h"
+
+#include <set>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/file_util.h"
+#include "base/message_loop.h"
+#include "base/message_loop_proxy.h"
+#include "base/ref_counted.h"
+#include "base/scoped_callback_factory.h"
+#include "base/scoped_ptr.h"
+#include "base/scoped_temp_dir.h"
+#include "googleurl/src/gurl.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/fileapi/file_system_path_manager.h"
+#include "webkit/fileapi/file_system_util.h"
+
+using namespace fileapi;
+
+class SandboxMountPointProviderOriginEnumeratorTest : public testing::Test {
+ public:
+ void SetUp() {
+ ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
+ enumerator_.reset(new SandboxMountPointProvider::OriginEnumerator(
+ data_dir_.path()));
+ }
+
+ SandboxMountPointProvider::OriginEnumerator* enumerator() const {
+ return enumerator_.get();
+ }
+
+ protected:
+ void CreateOriginTypeDirectory(const std::string& origin_identifier,
+ fileapi::FileSystemType type) {
+ std::string type_string =
+ FileSystemPathManager::GetFileSystemTypeString(type);
+ ASSERT_TRUE(!type_string.empty());
+ FilePath target = data_dir_.path().AppendASCII(origin_identifier)
+ .AppendASCII(type_string);
+ file_util::CreateDirectory(target);
+ ASSERT_TRUE(file_util::DirectoryExists(target));
+ }
+
+ ScopedTempDir data_dir_;
+ scoped_ptr<SandboxMountPointProvider::OriginEnumerator> enumerator_;
+};
+
+TEST_F(SandboxMountPointProviderOriginEnumeratorTest, Empty) {
+ ASSERT_TRUE(enumerator()->Next().empty());
+}
+
+TEST_F(SandboxMountPointProviderOriginEnumeratorTest, EnumerateOrigins) {
+ const char* temporary_origins[] = {
+ "http_www.bar.com_0",
+ "http_www.foo.com_0",
+ "http_www.foo.com_80",
+ "http_www.example.com_8080",
+ "http_www.google.com_80",
+ };
+ const char* persistent_origins[] = {
+ "http_www.bar.com_0",
+ "http_www.foo.com_8080",
+ "http_www.foo.com_80",
+ };
+ size_t temporary_size = ARRAYSIZE_UNSAFE(temporary_origins);
+ size_t persistent_size = ARRAYSIZE_UNSAFE(persistent_origins);
+ std::set<std::string> temporary_set, persistent_set;
+ for (size_t i = 0; i < temporary_size; ++i) {
+ CreateOriginTypeDirectory(temporary_origins[i],
+ fileapi::kFileSystemTypeTemporary);
+ temporary_set.insert(temporary_origins[i]);
+ }
+ for (size_t i = 0; i < persistent_size; ++i) {
+ CreateOriginTypeDirectory(persistent_origins[i], kFileSystemTypePersistent);
+ persistent_set.insert(persistent_origins[i]);
+ }
+
+ size_t temporary_actual_size = 0;
+ size_t persistent_actual_size = 0;
+ std::string current;
+ while (!(current = enumerator()->Next()).empty()) {
+ SCOPED_TRACE(testing::Message() << "EnumerateOrigin " << current);
+ if (enumerator()->HasTemporary()) {
+ ASSERT_TRUE(temporary_set.find(current) != temporary_set.end());
+ ++temporary_actual_size;
+ }
+ if (enumerator()->HasPersistent()) {
+ ASSERT_TRUE(persistent_set.find(current) != persistent_set.end());
+ ++persistent_actual_size;
+ }
+ }
+
+ ASSERT_EQ(temporary_size, temporary_actual_size);
+ ASSERT_EQ(persistent_size, persistent_actual_size);
+}
diff --git a/webkit/fileapi/webkit_fileapi.gypi b/webkit/fileapi/webkit_fileapi.gypi
index f1191c6..1b0e127 100644
--- a/webkit/fileapi/webkit_fileapi.gypi
+++ b/webkit/fileapi/webkit_fileapi.gypi
@@ -23,8 +23,11 @@
'file_system_file_util.h',
'file_system_file_util_proxy.cc',
'file_system_file_util_proxy.h',
+ 'file_system_mount_point_provider.h',
'file_system_operation.cc',
'file_system_operation.h',
+ 'file_system_operation_context.cc',
+ 'file_system_operation_context.h',
'file_system_path_manager.cc',
'file_system_path_manager.h',
'file_system_types.h',
@@ -38,6 +41,10 @@
'file_system_usage_cache.cc',
'file_writer_delegate.cc',
'file_writer_delegate.h',
+ 'local_file_system_file_util.cc',
+ 'local_file_system_file_util.h',
+ 'sandbox_mount_point_provider.cc',
+ 'sandbox_mount_point_provider.h',
'webfilewriter_base.cc',
'webfilewriter_base.h',
],