diff options
Diffstat (limited to 'webkit/fileapi')
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', ], |