diff options
26 files changed, 1144 insertions, 1138 deletions
diff --git a/base/platform_file.h b/base/platform_file.h index abe5cdd..c5ab477 100644 --- a/base/platform_file.h +++ b/base/platform_file.h @@ -44,6 +44,9 @@ enum PlatformFileFlags { PLATFORM_FILE_WRITE_ATTRIBUTES = 8192 // Used on Windows only }; +// PLATFORM_FILE_ERROR_ACCESS_DENIED is returned when a call fails because of +// a filesystem restriction. PLATFORM_FILE_ERROR_SECURITY is returned when a +// browser policy doesn't allow the operation to be executed. enum PlatformFileError { PLATFORM_FILE_OK = 0, PLATFORM_FILE_ERROR_FAILED = -1, @@ -55,7 +58,9 @@ enum PlatformFileError { PLATFORM_FILE_ERROR_NO_MEMORY = -7, PLATFORM_FILE_ERROR_NO_SPACE = -8, PLATFORM_FILE_ERROR_NOT_A_DIRECTORY = -9, - PLATFORM_FILE_ERROR_INVALID_OPERATION = -10 + PLATFORM_FILE_ERROR_INVALID_OPERATION = -10, + PLATFORM_FILE_ERROR_SECURITY = -11, + PLATFORM_FILE_ERROR_ABORT = -12 }; // Used to hold information about a given file. diff --git a/chrome/browser/file_system/browser_file_system_callback_dispatcher.cc b/chrome/browser/file_system/browser_file_system_callback_dispatcher.cc new file mode 100644 index 0000000..107515e --- /dev/null +++ b/chrome/browser/file_system/browser_file_system_callback_dispatcher.cc @@ -0,0 +1,45 @@ +// 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 "chrome/browser/file_system/browser_file_system_callback_dispatcher.h" + +#include "chrome/browser/file_system/file_system_dispatcher_host.h" + +BrowserFileSystemCallbackDispatcher::BrowserFileSystemCallbackDispatcher( + FileSystemDispatcherHost* dispatcher_host, int request_id) + : dispatcher_host_(dispatcher_host), + request_id_(request_id) { + DCHECK(dispatcher_host_); +} + +void BrowserFileSystemCallbackDispatcher::DidSucceed() { + dispatcher_host_->Send(new ViewMsg_FileSystem_DidSucceed(request_id_)); + dispatcher_host_->RemoveCompletedOperation(request_id_); +} + +void BrowserFileSystemCallbackDispatcher::DidReadMetadata( + const base::PlatformFileInfo& info) { + dispatcher_host_->Send(new ViewMsg_FileSystem_DidReadMetadata( + request_id_, info)); + dispatcher_host_->RemoveCompletedOperation(request_id_); +} + +void BrowserFileSystemCallbackDispatcher::DidReadDirectory( + const std::vector<base::file_util_proxy::Entry>& entries, bool has_more) { + dispatcher_host_->Send(new ViewMsg_FileSystem_DidReadDirectory( + request_id_, entries, has_more)); + dispatcher_host_->RemoveCompletedOperation(request_id_); +} + +void BrowserFileSystemCallbackDispatcher::DidOpenFileSystem( + const string16&, const FilePath&) { + NOTREACHED(); +} + +void BrowserFileSystemCallbackDispatcher::DidFail( + base::PlatformFileError error_code) { + dispatcher_host_->Send(new ViewMsg_FileSystem_DidFail( + request_id_, error_code)); + dispatcher_host_->RemoveCompletedOperation(request_id_); +} diff --git a/chrome/browser/file_system/browser_file_system_callback_dispatcher.h b/chrome/browser/file_system/browser_file_system_callback_dispatcher.h new file mode 100644 index 0000000..0372e09 --- /dev/null +++ b/chrome/browser/file_system/browser_file_system_callback_dispatcher.h @@ -0,0 +1,33 @@ +// 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. + +#ifndef CHROME_BROWSER_FILE_SYSTEM_BROWSER_FILE_SYSTEM_CALLBACK_DISPATCHER_H_ +#define CHROME_BROWSER_FILE_SYSTEM_BROWSER_FILE_SYSTEM_CALLBACK_DISPATCHER_H_ + +#include "webkit/fileapi/file_system_callback_dispatcher.h" + +class FileSystemDispatcherHost; + +class BrowserFileSystemCallbackDispatcher + : public fileapi::FileSystemCallbackDispatcher { + public: + BrowserFileSystemCallbackDispatcher(FileSystemDispatcherHost* dispatcher_host, + int request_id); + + // FileSystemCallbackDispatcher implementation. + virtual void DidSucceed(); + virtual void DidReadMetadata(const base::PlatformFileInfo& file_info); + virtual void DidReadDirectory( + const std::vector<base::file_util_proxy::Entry>& entries, + bool has_more); + virtual void DidOpenFileSystem(const string16& name, + const FilePath& root_path); + virtual void DidFail(base::PlatformFileError error_code); + + private: + scoped_refptr<FileSystemDispatcherHost> dispatcher_host_; + int request_id_; +}; + +#endif // CHROME_BROWSER_FILE_SYSTEM_BROWSER_FILE_SYSTEM_CALLBACK_DISPATCHER_H_ diff --git a/chrome/browser/file_system/chrome_file_system_operation.cc b/chrome/browser/file_system/chrome_file_system_operation.cc deleted file mode 100644 index 020aa3e..0000000 --- a/chrome/browser/file_system/chrome_file_system_operation.cc +++ /dev/null @@ -1,14 +0,0 @@ -// 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 "chrome/browser/file_system/chrome_file_system_operation.h" - -#include "chrome/browser/chrome_thread.h" - -ChromeFileSystemOperation::ChromeFileSystemOperation( - int request_id, fileapi::FileSystemOperationClient* client) - : fileapi::FileSystemOperation(client, - ChromeThread::GetMessageLoopProxyForThread(ChromeThread::FILE)), - request_id_(request_id) { } - diff --git a/chrome/browser/file_system/chrome_file_system_operation.h b/chrome/browser/file_system/chrome_file_system_operation.h deleted file mode 100644 index 3b1d3ca..0000000 --- a/chrome/browser/file_system/chrome_file_system_operation.h +++ /dev/null @@ -1,28 +0,0 @@ -// 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. - -#ifndef CHROME_BROWSER_FILE_SYSTEM_CHROME_FILE_SYSTEM_OPERATION_H_ -#define CHROME_BROWSER_FILE_SYSTEM_CHROME_FILE_SYSTEM_OPERATION_H_ - -#include "webkit/fileapi/file_system_operation.h" - -// This class is designed to serve one-time file system operation per instance. -// Only one method(CreateFile, CreateDirectory, Copy, Move, DirectoryExists, -// GetMetadata, ReadDirectory and Remove) may be called during the lifetime of -// this object and it should be called no more than once. -class ChromeFileSystemOperation : public fileapi::FileSystemOperation { - public: - ChromeFileSystemOperation( - int request_id, fileapi::FileSystemOperationClient* client); - - int request_id() const { return request_id_; } - - private: - int request_id_; - - DISALLOW_COPY_AND_ASSIGN(ChromeFileSystemOperation); -}; - -#endif // CHROME_BROWSER_FILE_SYSTEM_CHROME_FILE_SYSTEM_OPERATION_H_ - diff --git a/chrome/browser/file_system/chrome_file_system_operation_unittest.cc b/chrome/browser/file_system/chrome_file_system_operation_unittest.cc deleted file mode 100644 index 57ca164..0000000 --- a/chrome/browser/file_system/chrome_file_system_operation_unittest.cc +++ /dev/null @@ -1,571 +0,0 @@ -// 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 "chrome/browser/file_system/chrome_file_system_operation.h" - -#include "base/logging.h" -#include "base/rand_util.h" -#include "base/scoped_ptr.h" -#include "base/scoped_temp_dir.h" -#include "chrome/browser/chrome_thread.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/WebKit/WebKit/chromium/public/WebFileError.h" -#include "webkit/fileapi/file_system_operation_client.h" - -namespace { -int kInvalidRequestId = -1; -int kFileOperationStatusNotSet = 0; -int kFileOperationSucceeded = 1; -} - -using fileapi::FileSystemOperation; - -bool FileExists(FilePath path) { - return file_util::PathExists(path) && !file_util::DirectoryExists(path); -} - -class MockClient: public fileapi::FileSystemOperationClient { - public: - MockClient() - : status_(kFileOperationStatusNotSet), - request_id_(kInvalidRequestId) { - } - - ~MockClient() {} - - virtual void DidFail(WebKit::WebFileError status, - FileSystemOperation* operation) { - status_ = status; - request_id_ = - static_cast<ChromeFileSystemOperation*>(operation)->request_id(); - } - - virtual void DidSucceed(FileSystemOperation* operation) { - status_ = kFileOperationSucceeded; - request_id_ = - static_cast<ChromeFileSystemOperation*>(operation)->request_id(); - } - - virtual void DidReadMetadata( - const base::PlatformFileInfo& info, - FileSystemOperation* operation) { - info_ = info; - request_id_ = - static_cast<ChromeFileSystemOperation*>(operation)->request_id(); - } - - virtual void DidReadDirectory( - const std::vector<base::file_util_proxy::Entry>& entries, - bool has_more, - FileSystemOperation* operation) { - entries_ = entries; - request_id_ = - static_cast<ChromeFileSystemOperation*>(operation)->request_id(); - } - - // Helpers for testing. - int status() const { return status_; } - int request_id() const { return request_id_; } - const base::PlatformFileInfo& info() const { return info_; } - const std::vector<base::file_util_proxy::Entry>& entries() const { - return entries_; - } - - private: - int status_; - int request_id_; - base::PlatformFileInfo info_; - std::vector<base::file_util_proxy::Entry> entries_; -}; - -class ChromeFileSystemOperationTest : public testing::Test { - public: - ChromeFileSystemOperationTest() - : ui_thread_(ChromeThread::UI, &loop_), - file_thread_(ChromeThread::FILE, &loop_) { - base_.CreateUniqueTempDir(); - } - - protected: - virtual void SetUp() { - mock_client_.reset(new MockClient()); - current_request_id_ = kInvalidRequestId; - ASSERT_TRUE(base_.IsValid()); - } - - // Returns a new operation pointer that is created each time it's called. - // The pointer is owned by the test class. - ChromeFileSystemOperation* operation() { - current_request_id_ = base::RandInt(0, kint32max); - operation_.reset(new ChromeFileSystemOperation( - current_request_id_, mock_client_.get())); - return operation_.get(); - } - - scoped_ptr<MockClient> mock_client_; - int current_request_id_; - - MessageLoop loop_; - ChromeThread ui_thread_; - ChromeThread file_thread_; - - // Common temp base for all non-existing file/dir path test cases. - // This is in case a dir on test machine exists. It's better to - // create temp and then create non-existing file paths under it. - ScopedTempDir base_; - - private: - scoped_ptr<ChromeFileSystemOperation> operation_; - - DISALLOW_COPY_AND_ASSIGN(ChromeFileSystemOperationTest); -}; - -TEST_F(ChromeFileSystemOperationTest, TestMoveFailureSrcDoesntExist) { - FilePath src(base_.path().Append(FILE_PATH_LITERAL("a"))); - FilePath dest(base_.path().Append(FILE_PATH_LITERAL("b"))); - operation()->Move(src, dest); - loop_.RunAllPending(); - EXPECT_EQ(WebKit::WebFileErrorNotFound, mock_client_->status()); - EXPECT_EQ(current_request_id_, mock_client_->request_id()); -} - - -TEST_F(ChromeFileSystemOperationTest, TestMoveFailureContainsPath) { - FilePath file_under_base = base_.path().Append(FILE_PATH_LITERAL("b")); - operation()->Move(base_.path(), file_under_base); - loop_.RunAllPending(); - EXPECT_EQ(WebKit::WebFileErrorInvalidModification, mock_client_->status()); - EXPECT_EQ(current_request_id_, mock_client_->request_id()); -} - -TEST_F(ChromeFileSystemOperationTest, TestMoveFailureSrcDirExistsDestFile) { - // Src exists and is dir. Dest is a file. - ScopedTempDir dest_dir; - ASSERT_TRUE(dest_dir.CreateUniqueTempDir()); - FilePath dest_file; - file_util::CreateTemporaryFileInDir(dest_dir.path(), &dest_file); - - operation()->Move(base_.path(), dest_file); - loop_.RunAllPending(); - EXPECT_EQ(mock_client_->status(), WebKit::WebFileErrorInvalidModification); - EXPECT_EQ(current_request_id_, mock_client_->request_id()); -} - -TEST_F(ChromeFileSystemOperationTest, TestMoveFailureDestParentDoesntExist) { - // Dest. parent path does not exist. - ScopedTempDir src_dir; - ASSERT_TRUE(src_dir.CreateUniqueTempDir()); - FilePath nonexisting(base_.path().Append(FILE_PATH_LITERAL("DontExistDir"))); - FilePath nonexisting_file = nonexisting.Append( - FILE_PATH_LITERAL("DontExistFile")); - - operation()->Move(src_dir.path(), nonexisting_file); - loop_.RunAllPending(); - EXPECT_EQ(mock_client_->status(), WebKit::WebFileErrorNotFound); - EXPECT_EQ(current_request_id_, mock_client_->request_id()); -} - -TEST_F(ChromeFileSystemOperationTest, TestMoveSuccessSrcFileAndOverwrite) { - ScopedTempDir src_dir; - ASSERT_TRUE(src_dir.CreateUniqueTempDir()); - FilePath src_file; - file_util::CreateTemporaryFileInDir(src_dir.path(), &src_file); - - ScopedTempDir dest_dir; - ASSERT_TRUE(dest_dir.CreateUniqueTempDir()); - FilePath dest_file; - file_util::CreateTemporaryFileInDir(dest_dir.path(), &dest_file); - - operation()->Move(src_file, dest_file); - loop_.RunAllPending(); - EXPECT_EQ(kFileOperationSucceeded, mock_client_->status()); - EXPECT_TRUE(FileExists(dest_file)); - EXPECT_EQ(current_request_id_, mock_client_->request_id()); -} - -TEST_F(ChromeFileSystemOperationTest, TestMoveSuccessSrcFileAndNew) { - ScopedTempDir src_dir; - ASSERT_TRUE(src_dir.CreateUniqueTempDir()); - FilePath src_file; - file_util::CreateTemporaryFileInDir(src_dir.path(), &src_file); - - ScopedTempDir dest_dir; - ASSERT_TRUE(dest_dir.CreateUniqueTempDir()); - FilePath dest_file(dest_dir.path().Append(FILE_PATH_LITERAL("NewFile"))); - - operation()->Move(src_file, dest_file); - loop_.RunAllPending(); - EXPECT_EQ(kFileOperationSucceeded, mock_client_->status()); - EXPECT_TRUE(FileExists(dest_file)); - EXPECT_EQ(current_request_id_, mock_client_->request_id()); -} - -TEST_F(ChromeFileSystemOperationTest, TestCopyFailureSrcDoesntExist) { - FilePath src(base_.path().Append(FILE_PATH_LITERAL("a"))); - FilePath dest(base_.path().Append(FILE_PATH_LITERAL("b"))); - operation()->Copy(src, dest); - loop_.RunAllPending(); - EXPECT_EQ(WebKit::WebFileErrorNotFound, mock_client_->status()); - EXPECT_EQ(current_request_id_, mock_client_->request_id()); -} - -TEST_F(ChromeFileSystemOperationTest, TestCopyFailureContainsPath) { - FilePath file_under_base = base_.path().Append(FILE_PATH_LITERAL("b")); - operation()->Copy(base_.path(), file_under_base); - loop_.RunAllPending(); - EXPECT_EQ(WebKit::WebFileErrorInvalidModification, mock_client_->status()); - EXPECT_EQ(current_request_id_, mock_client_->request_id()); -} - -TEST_F(ChromeFileSystemOperationTest, TestCopyFailureSrcDirExistsDestFile) { - // Src exists and is dir. Dest is a file. - ScopedTempDir dir; - ASSERT_TRUE(dir.CreateUniqueTempDir()); - FilePath dest_file; - file_util::CreateTemporaryFileInDir(dir.path(), &dest_file); - - operation()->Copy(base_.path(), dest_file); - loop_.RunAllPending(); - EXPECT_EQ(mock_client_->status(), WebKit::WebFileErrorInvalidModification); - EXPECT_EQ(current_request_id_, mock_client_->request_id()); -} - -TEST_F(ChromeFileSystemOperationTest, TestCopyFailureDestParentDoesntExist) { - // Dest. parent path does not exist. - ScopedTempDir dir; - ASSERT_TRUE(dir.CreateUniqueTempDir()); - FilePath src_dir = dir.path(); - - FilePath nonexisting(base_.path().Append(FILE_PATH_LITERAL("DontExistDir"))); - file_util::EnsureEndsWithSeparator(&nonexisting); - FilePath nonexisting_file = nonexisting.Append( - FILE_PATH_LITERAL("DontExistFile")); - - operation()->Copy(src_dir, nonexisting_file); - loop_.RunAllPending(); - EXPECT_EQ(mock_client_->status(), WebKit::WebFileErrorNotFound); - EXPECT_EQ(current_request_id_, mock_client_->request_id()); -} - -TEST_F(ChromeFileSystemOperationTest, TestCopySuccessSrcFileAndOverwrite) { - ScopedTempDir src_dir; - ASSERT_TRUE(src_dir.CreateUniqueTempDir()); - FilePath src_file; - file_util::CreateTemporaryFileInDir(src_dir.path(), &src_file); - - ScopedTempDir dest_dir; - ASSERT_TRUE(dest_dir.CreateUniqueTempDir()); - FilePath dest_file; - file_util::CreateTemporaryFileInDir(dest_dir.path(), &dest_file); - - operation()->Copy(src_file, dest_file); - loop_.RunAllPending(); - EXPECT_EQ(kFileOperationSucceeded, mock_client_->status()); - EXPECT_TRUE(FileExists(dest_file)); - EXPECT_EQ(current_request_id_, mock_client_->request_id()); -} - -TEST_F(ChromeFileSystemOperationTest, TestCopySuccessSrcFileAndNew) { - ScopedTempDir src_dir; - ASSERT_TRUE(src_dir.CreateUniqueTempDir()); - FilePath src_file; - file_util::CreateTemporaryFileInDir(src_dir.path(), &src_file); - - ScopedTempDir dest_dir; - ASSERT_TRUE(dest_dir.CreateUniqueTempDir()); - FilePath dest_file(dest_dir.path().Append(FILE_PATH_LITERAL("NewFile"))); - - operation()->Copy(src_file, dest_file); - loop_.RunAllPending(); - EXPECT_EQ(kFileOperationSucceeded, mock_client_->status()); - EXPECT_TRUE(FileExists(dest_file)); - EXPECT_EQ(current_request_id_, mock_client_->request_id()); -} - -TEST_F(ChromeFileSystemOperationTest, TestCopySuccessSrcDir) { - ScopedTempDir src_dir; - ASSERT_TRUE(src_dir.CreateUniqueTempDir()); - - ScopedTempDir dest_dir; - ASSERT_TRUE(dest_dir.CreateUniqueTempDir()); - - operation()->Copy(src_dir.path(), dest_dir.path()); - loop_.RunAllPending(); - EXPECT_EQ(kFileOperationSucceeded, mock_client_->status()); - EXPECT_EQ(current_request_id_, mock_client_->request_id()); -} - -TEST_F(ChromeFileSystemOperationTest, TestCopyDestParentExistsSuccess) { - ScopedTempDir src_dir; - ASSERT_TRUE(src_dir.CreateUniqueTempDir()); - FilePath src_file; - file_util::CreateTemporaryFileInDir(src_dir.path(), &src_file); - - ScopedTempDir dest_dir; - ASSERT_TRUE(dest_dir.CreateUniqueTempDir()); - - operation()->Copy(src_file, dest_dir.path()); - loop_.RunAllPending(); - EXPECT_EQ(kFileOperationSucceeded, mock_client_->status()); - EXPECT_EQ(current_request_id_, mock_client_->request_id()); - - FilePath src_filename(src_file.BaseName()); - EXPECT_TRUE(FileExists(dest_dir.path().Append(src_filename))); -} - -TEST_F(ChromeFileSystemOperationTest, TestCreateFileFailure) { - // Already existing file and exclusive true. - ScopedTempDir dir; - ASSERT_TRUE(dir.CreateUniqueTempDir()); - FilePath file; - - file_util::CreateTemporaryFileInDir(dir.path(), &file); - operation()->CreateFile(file, true); - loop_.RunAllPending(); - EXPECT_EQ(mock_client_->status(), WebKit::WebFileErrorInvalidModification); - EXPECT_EQ(current_request_id_, mock_client_->request_id()); -} - -TEST_F(ChromeFileSystemOperationTest, TestCreateFileSuccessFileExists) { - // Already existing file and exclusive false. - ScopedTempDir dir; - ASSERT_TRUE(dir.CreateUniqueTempDir()); - FilePath file; - file_util::CreateTemporaryFileInDir(dir.path(), &file); - - operation()->CreateFile(file, false); - loop_.RunAllPending(); - EXPECT_EQ(kFileOperationSucceeded, mock_client_->status()); - EXPECT_TRUE(FileExists(file)); - EXPECT_EQ(current_request_id_, mock_client_->request_id()); -} - -TEST_F(ChromeFileSystemOperationTest, TestCreateFileSuccessExclusive) { - // File doesn't exist but exclusive is true. - ScopedTempDir dir; - ASSERT_TRUE(dir.CreateUniqueTempDir()); - FilePath file = dir.path().Append(FILE_PATH_LITERAL("FileDoesntExist")); - operation()->CreateFile(file, true); - loop_.RunAllPending(); - EXPECT_EQ(kFileOperationSucceeded, mock_client_->status()); - EXPECT_TRUE(FileExists(file)); - EXPECT_EQ(current_request_id_, mock_client_->request_id()); -} - -TEST_F(ChromeFileSystemOperationTest, TestCreateFileSuccessFileDoesntExist) { - // Non existing file. - ScopedTempDir dir; - ASSERT_TRUE(dir.CreateUniqueTempDir()); - FilePath file = dir.path().Append(FILE_PATH_LITERAL("FileDoesntExist")); - operation()->CreateFile(file, false); - loop_.RunAllPending(); - EXPECT_EQ(kFileOperationSucceeded, mock_client_->status()); - EXPECT_EQ(current_request_id_, mock_client_->request_id()); -} - -TEST_F(ChromeFileSystemOperationTest, - TestCreateDirFailureDestParentDoesntExist) { - // Dest. parent path does not exist. - FilePath nonexisting(base_.path().Append( - FILE_PATH_LITERAL("DirDoesntExist"))); - file_util::EnsureEndsWithSeparator(&nonexisting); - FilePath nonexisting_file = nonexisting.Append( - FILE_PATH_LITERAL("FileDoesntExist")); - operation()->CreateDirectory(nonexisting_file, false); - loop_.RunAllPending(); - EXPECT_EQ(WebKit::WebFileErrorNotFound, mock_client_->status()); - EXPECT_EQ(current_request_id_, mock_client_->request_id()); -} - -TEST_F(ChromeFileSystemOperationTest, TestCreateDirFailureDirExists) { - // Exclusive and dir existing at path. - operation()->CreateDirectory(base_.path(), true); - loop_.RunAllPending(); - EXPECT_EQ(WebKit::WebFileErrorInvalidModification, mock_client_->status()); - EXPECT_EQ(current_request_id_, mock_client_->request_id()); -} - -TEST_F(ChromeFileSystemOperationTest, TestCreateDirFailureFileExists) { - // Exclusive true and file existing at path. - ScopedTempDir dir; - ASSERT_TRUE(dir.CreateUniqueTempDir()); - FilePath file; - file_util::CreateTemporaryFileInDir(dir.path(), &file); - operation()->CreateDirectory(file, true); - loop_.RunAllPending(); - EXPECT_EQ(mock_client_->status(), - WebKit::WebFileErrorInvalidModification); - EXPECT_EQ(current_request_id_, mock_client_->request_id()); -} - -TEST_F(ChromeFileSystemOperationTest, TestCreateDirSuccess) { - // Dir exists and exclusive is false. - ScopedTempDir dir; - ASSERT_TRUE(dir.CreateUniqueTempDir()); - operation()->CreateDirectory(dir.path(), false); - loop_.RunAllPending(); - EXPECT_EQ(kFileOperationSucceeded, mock_client_->status()); - EXPECT_EQ(current_request_id_, mock_client_->request_id()); - - // Dir doesn't exist. - FilePath nonexisting_dir_path(FILE_PATH_LITERAL("nonexistingdir")); - operation()->CreateDirectory(nonexisting_dir_path, false); - loop_.RunAllPending(); - EXPECT_EQ(kFileOperationSucceeded, mock_client_->status()); - EXPECT_TRUE(file_util::DirectoryExists(nonexisting_dir_path)); - EXPECT_EQ(current_request_id_, mock_client_->request_id()); -} - -TEST_F(ChromeFileSystemOperationTest, TestCreateDirSuccessExclusive) { - // Dir doesn't exist. - ScopedTempDir dir; - ASSERT_TRUE(dir.CreateUniqueTempDir()); - FilePath nonexisting_dir_path(dir.path().Append( - FILE_PATH_LITERAL("nonexistingdir"))); - - operation()->CreateDirectory(nonexisting_dir_path, true); - loop_.RunAllPending(); - EXPECT_EQ(kFileOperationSucceeded, mock_client_->status()); - EXPECT_TRUE(file_util::DirectoryExists(nonexisting_dir_path)); - EXPECT_EQ(current_request_id_, mock_client_->request_id()); -} - -TEST_F(ChromeFileSystemOperationTest, TestExistsAndMetadataFailure) { - FilePath nonexisting_dir_path(base_.path().Append( - FILE_PATH_LITERAL("nonexistingdir"))); - operation()->GetMetadata(nonexisting_dir_path); - loop_.RunAllPending(); - EXPECT_EQ(WebKit::WebFileErrorNotFound, mock_client_->status()); - - operation()->FileExists(nonexisting_dir_path); - loop_.RunAllPending(); - EXPECT_EQ(WebKit::WebFileErrorNotFound, mock_client_->status()); - EXPECT_EQ(current_request_id_, mock_client_->request_id()); - - file_util::EnsureEndsWithSeparator(&nonexisting_dir_path); - operation()->DirectoryExists(nonexisting_dir_path); - loop_.RunAllPending(); - EXPECT_EQ(WebKit::WebFileErrorNotFound, mock_client_->status()); - EXPECT_EQ(current_request_id_, mock_client_->request_id()); -} - -TEST_F(ChromeFileSystemOperationTest, TestExistsAndMetadataSuccess) { - ScopedTempDir dir; - ASSERT_TRUE(dir.CreateUniqueTempDir()); - - operation()->DirectoryExists(dir.path()); - loop_.RunAllPending(); - EXPECT_EQ(kFileOperationSucceeded, mock_client_->status()); - EXPECT_EQ(current_request_id_, mock_client_->request_id()); - - operation()->GetMetadata(dir.path()); - loop_.RunAllPending(); - EXPECT_EQ(kFileOperationSucceeded, mock_client_->status()); - EXPECT_TRUE(mock_client_->info().is_directory); - EXPECT_EQ(current_request_id_, mock_client_->request_id()); - - FilePath file; - file_util::CreateTemporaryFileInDir(dir.path(), &file); - operation()->FileExists(file); - loop_.RunAllPending(); - EXPECT_EQ(kFileOperationSucceeded, mock_client_->status()); - EXPECT_EQ(current_request_id_, mock_client_->request_id()); - - operation()->GetMetadata(file); - loop_.RunAllPending(); - EXPECT_EQ(kFileOperationSucceeded, mock_client_->status()); - EXPECT_FALSE(mock_client_->info().is_directory); - EXPECT_EQ(current_request_id_, mock_client_->request_id()); -} - -TEST_F(ChromeFileSystemOperationTest, TestReadDirFailure) { - // Path doesn't exists - FilePath nonexisting_dir_path(base_.path().Append( - FILE_PATH_LITERAL("NonExistingDir"))); - file_util::EnsureEndsWithSeparator(&nonexisting_dir_path); - operation()->ReadDirectory(nonexisting_dir_path); - loop_.RunAllPending(); - EXPECT_EQ(WebKit::WebFileErrorNotFound, mock_client_->status()); - EXPECT_EQ(current_request_id_, mock_client_->request_id()); - - // File exists. - ScopedTempDir dir; - ASSERT_TRUE(dir.CreateUniqueTempDir()); - FilePath file; - file_util::CreateTemporaryFileInDir(dir.path(), &file); - operation()->ReadDirectory(file); - loop_.RunAllPending(); - // TODO(kkanetkar) crbug.com/54309 to change the error code. - EXPECT_EQ(WebKit::WebFileErrorNotFound, mock_client_->status()); - EXPECT_EQ(current_request_id_, mock_client_->request_id()); -} - -TEST_F(ChromeFileSystemOperationTest, TestReadDirSuccess) { - // parent_dir - // | | - // child_dir child_file - // Verify reading parent_dir. - ScopedTempDir parent_dir; - ASSERT_TRUE(parent_dir.CreateUniqueTempDir()); - FilePath child_file; - file_util::CreateTemporaryFileInDir(parent_dir.path(), &child_file); - FilePath child_dir; - ASSERT_TRUE(file_util::CreateTemporaryDirInDir(parent_dir.path(), - FILE_PATH_LITERAL("child_dir"), &child_dir)); - - operation()->ReadDirectory(parent_dir.path()); - loop_.RunAllPending(); - EXPECT_EQ(kFileOperationStatusNotSet, mock_client_->status()); - EXPECT_EQ(2u, mock_client_->entries().size()); - EXPECT_EQ(current_request_id_, mock_client_->request_id()); - - for (size_t i = 0; i < mock_client_->entries().size(); ++i) { - if (mock_client_->entries()[i].is_directory) - EXPECT_EQ(child_dir.BaseName().value(), mock_client_->entries()[i].name); - else - EXPECT_EQ(child_file.BaseName().value(), mock_client_->entries()[i].name); - } -} - -TEST_F(ChromeFileSystemOperationTest, TestRemoveFailure) { - // Path doesn't exist. - FilePath nonexisting(base_.path().Append( - FILE_PATH_LITERAL("NonExistingDir"))); - file_util::EnsureEndsWithSeparator(&nonexisting); - - operation()->Remove(nonexisting); - loop_.RunAllPending(); - EXPECT_EQ(WebKit::WebFileErrorNotFound, mock_client_->status()); - EXPECT_EQ(current_request_id_, mock_client_->request_id()); - - // By spec recursive is always false. Non-empty dir should fail. - // parent_dir - // | | - // child_dir child_file - // Verify deleting parent_dir. - ScopedTempDir parent_dir; - ASSERT_TRUE(parent_dir.CreateUniqueTempDir()); - FilePath child_file; - file_util::CreateTemporaryFileInDir(parent_dir.path(), &child_file); - FilePath child_dir; - ASSERT_TRUE(file_util::CreateTemporaryDirInDir(parent_dir.path(), - FILE_PATH_LITERAL("child_dir"), &child_dir)); - - operation()->Remove(parent_dir.path()); - loop_.RunAllPending(); - EXPECT_EQ(WebKit::WebFileErrorInvalidModification, mock_client_->status()); - EXPECT_EQ(current_request_id_, mock_client_->request_id()); -} - -TEST_F(ChromeFileSystemOperationTest, TestRemoveSuccess) { - ScopedTempDir empty_dir; - ASSERT_TRUE(empty_dir.CreateUniqueTempDir()); - EXPECT_TRUE(file_util::DirectoryExists(empty_dir.path())); - - operation()->Remove(empty_dir.path()); - loop_.RunAllPending(); - EXPECT_EQ(kFileOperationSucceeded, mock_client_->status()); - EXPECT_FALSE(file_util::DirectoryExists(empty_dir.path())); - EXPECT_EQ(current_request_id_, mock_client_->request_id()); -} diff --git a/chrome/browser/file_system/file_system_dispatcher_host.cc b/chrome/browser/file_system/file_system_dispatcher_host.cc index 86555a2..385f2a4 100644 --- a/chrome/browser/file_system/file_system_dispatcher_host.cc +++ b/chrome/browser/file_system/file_system_dispatcher_host.cc @@ -10,13 +10,13 @@ #include "base/utf_string_conversions.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chrome_thread.h" +#include "chrome/browser/file_system/browser_file_system_callback_dispatcher.h" #include "chrome/browser/file_system/file_system_host_context.h" #include "chrome/browser/host_content_settings_map.h" #include "chrome/browser/renderer_host/browser_render_process_host.h" #include "chrome/common/render_messages.h" #include "chrome/common/render_messages_params.h" #include "googleurl/src/gurl.h" -#include "third_party/WebKit/WebKit/chromium/public/WebFileError.h" #include "webkit/glue/webkit_glue.h" // A class to hold an ongoing openFileSystem completion task. @@ -85,6 +85,9 @@ FileSystemDispatcherHost::FileSystemDispatcherHost( DCHECK(message_sender_); } +FileSystemDispatcherHost::~FileSystemDispatcherHost() { +} + void FileSystemDispatcherHost::Init(base::ProcessHandle process_handle) { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); DCHECK(!shutdown_); @@ -96,12 +99,6 @@ void FileSystemDispatcherHost::Init(base::ProcessHandle process_handle) { void FileSystemDispatcherHost::Shutdown() { message_sender_ = NULL; shutdown_ = true; - - // Drop all the operations. - for (OperationsMap::const_iterator iter(&operations_); - !iter.IsAtEnd(); iter.Advance()) { - operations_.Remove(iter.GetCurrentKey()); - } } bool FileSystemDispatcherHost::OnMessageReceived( @@ -182,11 +179,12 @@ void FileSystemDispatcherHost::OnReadMetadata( } void FileSystemDispatcherHost::OnCreate( - int request_id, const FilePath& path, bool exclusive, bool is_directory) { + int request_id, const FilePath& path, bool exclusive, + bool is_directory, bool recursive) { if (!CheckValidFileSystemPath(path, request_id)) return; if (is_directory) - GetNewOperation(request_id)->CreateDirectory(path, exclusive); + GetNewOperation(request_id)->CreateDirectory(path, exclusive, recursive); else GetNewOperation(request_id)->CreateFile(path, exclusive); } @@ -208,46 +206,6 @@ void FileSystemDispatcherHost::OnReadDirectory( GetNewOperation(request_id)->ReadDirectory(path); } -void FileSystemDispatcherHost::DidFail( - WebKit::WebFileError status, - fileapi::FileSystemOperation* operation) { - int request_id = - static_cast<ChromeFileSystemOperation*>(operation)->request_id(); - Send(new ViewMsg_FileSystem_DidFail(request_id, status)); - operations_.Remove(request_id); -} - -void FileSystemDispatcherHost::DidSucceed( - fileapi::FileSystemOperation* operation) { - int request_id = - static_cast<ChromeFileSystemOperation*>(operation)->request_id(); - Send(new ViewMsg_FileSystem_DidSucceed(request_id)); - operations_.Remove(request_id); -} - -void FileSystemDispatcherHost::DidReadMetadata( - const base::PlatformFileInfo& info, - fileapi::FileSystemOperation* operation) { - int request_id = - static_cast<ChromeFileSystemOperation*>(operation)->request_id(); - Send(new ViewMsg_FileSystem_DidReadMetadata(request_id, info)); - operations_.Remove(request_id); -} - -void FileSystemDispatcherHost::DidReadDirectory( - const std::vector<base::file_util_proxy::Entry>& entries, - bool has_more, - fileapi::FileSystemOperation* operation) { - int request_id = - static_cast<ChromeFileSystemOperation*>(operation)->request_id(); - ViewMsg_FileSystem_DidReadDirectory_Params params; - params.request_id = request_id; - params.entries = entries; - params.has_more = has_more; - Send(new ViewMsg_FileSystem_DidReadDirectory(params)); - operations_.Remove(request_id); -} - void FileSystemDispatcherHost::Send(IPC::Message* message) { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); if (!shutdown_ && message_sender_) @@ -262,16 +220,24 @@ bool FileSystemDispatcherHost::CheckValidFileSystemPath( // |path| is under the valid FileSystem root path for this host context. if (!context_->CheckValidFileSystemPath(path)) { Send(new ViewMsg_FileSystem_DidFail( - request_id, WebKit::WebFileErrorSecurity)); + request_id, base::PLATFORM_FILE_ERROR_SECURITY)); return false; } return true; } -ChromeFileSystemOperation* FileSystemDispatcherHost::GetNewOperation( +fileapi::FileSystemOperation* FileSystemDispatcherHost::GetNewOperation( int request_id) { - scoped_ptr<ChromeFileSystemOperation> operation( - new ChromeFileSystemOperation(request_id, this)); - operations_.AddWithID(operation.get(), request_id); - return operation.release(); + BrowserFileSystemCallbackDispatcher* dispatcher = + new BrowserFileSystemCallbackDispatcher(this, request_id); + fileapi::FileSystemOperation* operation = new fileapi::FileSystemOperation( + dispatcher, + ChromeThread::GetMessageLoopProxyForThread(ChromeThread::FILE)); + operations_.AddWithID(operation, request_id); + return operation; +} + +void FileSystemDispatcherHost::RemoveCompletedOperation(int request_id) { + DCHECK(operations_.Lookup(request_id)); + operations_.Remove(request_id); } diff --git a/chrome/browser/file_system/file_system_dispatcher_host.h b/chrome/browser/file_system/file_system_dispatcher_host.h index 8f21654..ac22255 100644 --- a/chrome/browser/file_system/file_system_dispatcher_host.h +++ b/chrome/browser/file_system/file_system_dispatcher_host.h @@ -13,9 +13,8 @@ #include "base/platform_file.h" #include "base/scoped_callback_factory.h" #include "base/ref_counted.h" -#include "chrome/browser/file_system/chrome_file_system_operation.h" #include "chrome/common/render_messages.h" -#include "webkit/fileapi/file_system_operation_client.h" +#include "webkit/fileapi/file_system_operation.h" class FileSystemHostContext; class HostContentSettingsMap; @@ -23,12 +22,12 @@ class Receiver; class ResourceMessageFilter; class FileSystemDispatcherHost - : public base::RefCountedThreadSafe<FileSystemDispatcherHost>, - public fileapi::FileSystemOperationClient { + : public base::RefCountedThreadSafe<FileSystemDispatcherHost> { public: FileSystemDispatcherHost(IPC::Message::Sender* sender, FileSystemHostContext* file_system_host_context, HostContentSettingsMap* host_content_settings_map); + ~FileSystemDispatcherHost(); void Init(base::ProcessHandle process_handle); void Shutdown(); @@ -46,25 +45,16 @@ class FileSystemDispatcherHost void OnCreate(int request_id, const FilePath& path, bool exclusive, - bool is_directory); + bool is_directory, + bool recursive); void OnExists(int request_id, const FilePath& path, bool is_directory); void OnReadDirectory(int request_id, const FilePath& path); void Send(IPC::Message* message); - - // FileSystemOperationClient methods. - virtual void DidFail(WebKit::WebFileError status, - fileapi::FileSystemOperation* operation); - virtual void DidSucceed(fileapi::FileSystemOperation* operation); - virtual void DidReadMetadata( - const base::PlatformFileInfo& info, - fileapi::FileSystemOperation* operation); - virtual void DidReadDirectory( - const std::vector<base::file_util_proxy::Entry>& entries, - bool has_more, fileapi::FileSystemOperation* operation); + void RemoveCompletedOperation(int request_id); private: - // Creates a new ChromeFileSystemOperation. - ChromeFileSystemOperation* GetNewOperation(int request_id); + // Creates a new FileSystemOperation. + fileapi::FileSystemOperation* GetNewOperation(int request_id); // Checks the validity of a given |path|. Returns true if the given |path| // is valid as a path for FileSystem API. Otherwise it sends back a @@ -85,7 +75,7 @@ class FileSystemDispatcherHost scoped_refptr<HostContentSettingsMap> host_content_settings_map_; // Keeps ongoing file system operations. - typedef IDMap<ChromeFileSystemOperation, IDMapOwnPointer> OperationsMap; + typedef IDMap<fileapi::FileSystemOperation, IDMapOwnPointer> OperationsMap; OperationsMap operations_; DISALLOW_COPY_AND_ASSIGN(FileSystemDispatcherHost); diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 839dc87..ca6dd5d 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -1527,8 +1527,8 @@ 'browser/file_path_watcher_win.cc', 'browser/file_select_helper.cc', 'browser/file_select_helper.h', - 'browser/file_system/chrome_file_system_operation.cc', - 'browser/file_system/chrome_file_system_operation.h', + 'browser/file_system/browser_file_system_callback_dispatcher.cc', + 'browser/file_system/browser_file_system_callback_dispatcher.h', 'browser/file_system/file_system_dispatcher_host.cc', 'browser/file_system/file_system_dispatcher_host.h', 'browser/file_system/file_system_host_context.cc', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 9bbe65a..28862b9 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1069,7 +1069,6 @@ 'browser/extensions/user_script_listener_unittest.cc', 'browser/extensions/user_script_master_unittest.cc', 'browser/file_path_watcher_unittest.cc', - 'browser/file_system/chrome_file_system_operation_unittest.cc', 'browser/file_system/file_system_host_context_unittest.cc', 'browser/find_backend_unittest.cc', 'browser/first_run/first_run_unittest.cc', diff --git a/chrome/common/file_system/file_system_dispatcher.cc b/chrome/common/file_system/file_system_dispatcher.cc index 89a2de4..8ae0c16 100644 --- a/chrome/common/file_system/file_system_dispatcher.cc +++ b/chrome/common/file_system/file_system_dispatcher.cc @@ -8,31 +8,20 @@ #include "chrome/common/child_thread.h" #include "chrome/common/render_messages.h" #include "chrome/common/render_messages_params.h" -#include "third_party/WebKit/WebKit/chromium/public/WebFileInfo.h" -#include "third_party/WebKit/WebKit/chromium/public/WebFileSystemEntry.h" -#include "third_party/WebKit/WebKit/chromium/public/WebFileSystemCallbacks.h" -#include "third_party/WebKit/WebKit/chromium/public/WebVector.h" #include "webkit/glue/webkit_glue.h" -using WebKit::WebFileError; -using WebKit::WebFileInfo; -using WebKit::WebFileSystemCallbacks; -using WebKit::WebFileSystemEntry; -using WebKit::WebVector; - FileSystemDispatcher::FileSystemDispatcher() { } FileSystemDispatcher::~FileSystemDispatcher() { // Make sure we fire all the remaining callbacks. - for (IDMap<WebFileSystemCallbacks>::iterator iter(&callbacks_); - !iter.IsAtEnd(); - iter.Advance()) { - int callbacks_id = iter.GetCurrentKey(); - WebFileSystemCallbacks* callbacks = iter.GetCurrentValue(); - DCHECK(callbacks); - callbacks_.Remove(callbacks_id); - callbacks->didFail(WebKit::WebFileErrorAbort); + for (IDMap<fileapi::FileSystemCallbackDispatcher, IDMapOwnPointer>::iterator + iter(&dispatchers_); !iter.IsAtEnd(); iter.Advance()) { + int request_id = iter.GetCurrentKey(); + fileapi::FileSystemCallbackDispatcher* dispatcher = iter.GetCurrentValue(); + DCHECK(dispatcher); + dispatcher->DidFail(base::PLATFORM_FILE_ERROR_ABORT); + dispatchers_.Remove(request_id); } } @@ -48,103 +37,101 @@ bool FileSystemDispatcher::OnMessageReceived(const IPC::Message& msg) { return handled; } -void FileSystemDispatcher::Move( - const string16& src_path, const string16& dest_path, - WebFileSystemCallbacks* callbacks) { - FilePath src_file_path = webkit_glue::WebStringToFilePath(src_path); - FilePath dest_file_path = webkit_glue::WebStringToFilePath(dest_path); - int request_id = callbacks_.Add(callbacks); - ChildThread::current()->Send(new ViewHostMsg_FileSystem_Move( - request_id, src_file_path, dest_file_path)); +bool FileSystemDispatcher::Move( + const FilePath& src_path, + const FilePath& dest_path, + fileapi::FileSystemCallbackDispatcher* dispatcher) { + int request_id = dispatchers_.Add(dispatcher); + return ChildThread::current()->Send(new ViewHostMsg_FileSystem_Move( + request_id, src_path, dest_path)); } -void FileSystemDispatcher::Copy( - const string16& src_path, const string16& dest_path, - WebFileSystemCallbacks* callbacks) { - FilePath src_file_path = webkit_glue::WebStringToFilePath(src_path); - FilePath dest_file_path = webkit_glue::WebStringToFilePath(dest_path); - int request_id = callbacks_.Add(callbacks); - ChildThread::current()->Send(new ViewHostMsg_FileSystem_Copy( - request_id, src_file_path, dest_file_path)); +bool FileSystemDispatcher::Copy( + const FilePath& src_path, + const FilePath& dest_path, + fileapi::FileSystemCallbackDispatcher* dispatcher) { + int request_id = dispatchers_.Add(dispatcher); + return ChildThread::current()->Send(new ViewHostMsg_FileSystem_Copy( + request_id, src_path, dest_path)); } -void FileSystemDispatcher::Remove( - const string16& path, WebFileSystemCallbacks* callbacks) { - FilePath file_path = webkit_glue::WebStringToFilePath(path); - int request_id = callbacks_.Add(callbacks); - ChildThread::current()->Send( - new ViewHostMsg_FileSystem_Remove(request_id, file_path)); +bool FileSystemDispatcher::Remove( + const FilePath& path, + fileapi::FileSystemCallbackDispatcher* dispatcher) { + int request_id = dispatchers_.Add(dispatcher); + return ChildThread::current()->Send( + new ViewHostMsg_FileSystem_Remove(request_id, path)); } -void FileSystemDispatcher::ReadMetadata( - const string16& path, WebFileSystemCallbacks* callbacks) { - FilePath file_path = webkit_glue::WebStringToFilePath(path); - int request_id = callbacks_.Add(callbacks); - ChildThread::current()->Send( - new ViewHostMsg_FileSystem_ReadMetadata(request_id, file_path)); +bool FileSystemDispatcher::ReadMetadata( + const FilePath& path, + fileapi::FileSystemCallbackDispatcher* dispatcher) { + int request_id = dispatchers_.Add(dispatcher); + return ChildThread::current()->Send( + new ViewHostMsg_FileSystem_ReadMetadata(request_id, path)); } -void FileSystemDispatcher::Create( - const string16& path, bool exclusive, bool is_directory, - WebFileSystemCallbacks* callbacks) { - FilePath file_path = webkit_glue::WebStringToFilePath(path); - int request_id = callbacks_.Add(callbacks); - ChildThread::current()->Send(new ViewHostMsg_FileSystem_Create( - request_id, file_path, exclusive, is_directory)); +bool FileSystemDispatcher::Create( + const FilePath& path, + bool exclusive, + bool is_directory, + bool recursive, + fileapi::FileSystemCallbackDispatcher* dispatcher) { + int request_id = dispatchers_.Add(dispatcher); + return ChildThread::current()->Send(new ViewHostMsg_FileSystem_Create( + request_id, path, exclusive, is_directory, recursive)); } -void FileSystemDispatcher::Exists( - const string16& path, bool is_directory, - WebFileSystemCallbacks* callbacks) { - FilePath file_path = webkit_glue::WebStringToFilePath(path); - int request_id = callbacks_.Add(callbacks); - ChildThread::current()->Send( - new ViewHostMsg_FileSystem_Exists(request_id, file_path, is_directory)); +bool FileSystemDispatcher::Exists( + const FilePath& path, + bool is_directory, + fileapi::FileSystemCallbackDispatcher* dispatcher) { + int request_id = dispatchers_.Add(dispatcher); + return ChildThread::current()->Send( + new ViewHostMsg_FileSystem_Exists(request_id, path, is_directory)); } -void FileSystemDispatcher::ReadDirectory( - const string16& path, WebFileSystemCallbacks* callbacks) { - FilePath file_path = webkit_glue::WebStringToFilePath(path); - int request_id = callbacks_.Add(callbacks); - ChildThread::current()->Send( - new ViewHostMsg_FileSystem_ReadDirectory(request_id, file_path)); +bool FileSystemDispatcher::ReadDirectory( + const FilePath& path, + fileapi::FileSystemCallbackDispatcher* dispatcher) { + int request_id = dispatchers_.Add(dispatcher); + return ChildThread::current()->Send( + new ViewHostMsg_FileSystem_ReadDirectory(request_id, path)); } void FileSystemDispatcher::DidSucceed(int request_id) { - WebFileSystemCallbacks* callbacks = callbacks_.Lookup(request_id); - DCHECK(callbacks); - callbacks_.Remove(request_id); - callbacks->didSucceed(); + fileapi::FileSystemCallbackDispatcher* dispatcher = + dispatchers_.Lookup(request_id); + DCHECK(dispatcher); + dispatcher->DidSucceed(); + dispatchers_.Remove(request_id); } -void FileSystemDispatcher::DidReadMetadata(int request_id, - const base::PlatformFileInfo& file_info) { - WebFileSystemCallbacks* callbacks = callbacks_.Lookup(request_id); - DCHECK(callbacks); - callbacks_.Remove(request_id); - WebFileInfo web_file_info; - web_file_info.modificationTime = file_info.last_modified.ToDoubleT(); - callbacks->didReadMetadata(web_file_info); +void FileSystemDispatcher::DidReadMetadata( + int request_id, const base::PlatformFileInfo& file_info) { + fileapi::FileSystemCallbackDispatcher* dispatcher = + dispatchers_.Lookup(request_id); + DCHECK(dispatcher); + dispatcher->DidReadMetadata(file_info); + dispatchers_.Remove(request_id); } void FileSystemDispatcher::DidReadDirectory( - const ViewMsg_FileSystem_DidReadDirectory_Params& params) { - WebFileSystemCallbacks* callbacks = callbacks_.Lookup(params.request_id); - DCHECK(callbacks); - if (!params.has_more) - callbacks_.Remove(params.request_id); - WebVector<WebFileSystemEntry> entries(params.entries.size()); - for (size_t i = 0; i < params.entries.size(); ++i) { - entries[i].name = webkit_glue::FilePathStringToWebString( - params.entries[i].name); - entries[i].isDirectory = params.entries[i].is_directory; - } - callbacks->didReadDirectory(entries, params.has_more); + int request_id, + const std::vector<base::file_util_proxy::Entry>& entries, + bool has_more) { + fileapi::FileSystemCallbackDispatcher* dispatcher = + dispatchers_.Lookup(request_id); + DCHECK(dispatcher); + dispatcher->DidReadDirectory(entries, has_more); + dispatchers_.Remove(request_id); } -void FileSystemDispatcher::DidFail(int request_id, WebFileError code) { - WebFileSystemCallbacks* callbacks = callbacks_.Lookup(request_id); - DCHECK(callbacks); - callbacks_.Remove(request_id); - callbacks->didFail(code); +void FileSystemDispatcher::DidFail( + int request_id, base::PlatformFileError error_code) { + fileapi::FileSystemCallbackDispatcher* dispatcher = + dispatchers_.Lookup(request_id); + DCHECK(dispatcher); + dispatcher->DidFail(error_code); + dispatchers_.Remove(request_id); } diff --git a/chrome/common/file_system/file_system_dispatcher.h b/chrome/common/file_system/file_system_dispatcher.h index 6fb9db5..8214b1c 100644 --- a/chrome/common/file_system/file_system_dispatcher.h +++ b/chrome/common/file_system/file_system_dispatcher.h @@ -8,24 +8,19 @@ #include <vector> #include "base/basictypes.h" +#include "base/file_util_proxy.h" #include "base/id_map.h" #include "base/nullable_string16.h" #include "googleurl/src/gurl.h" #include "ipc/ipc_channel.h" #include "ipc/ipc_message.h" -#include "third_party/WebKit/WebKit/chromium/public/WebFileError.h" - -namespace WebKit { -struct WebFileInfo; -class WebFileSystemCallbacks; -struct WebFileSystemEntry; -} +#include "webkit/fileapi/file_system_callback_dispatcher.h" namespace base { struct PlatformFileInfo; } -struct ViewMsg_FileSystem_DidReadDirectory_Params; +class FilePath; // Dispatches and sends file system related messages sent to/from a child // process from/to the main browser process. There is one instance @@ -37,45 +32,38 @@ class FileSystemDispatcher { bool OnMessageReceived(const IPC::Message& msg); - void Move( - const string16& src_path, - const string16& dest_path, - WebKit::WebFileSystemCallbacks* callbacks); - void Copy( - const string16& src_path, - const string16& dest_path, - WebKit::WebFileSystemCallbacks* callbacks); - void Remove( - const string16& path, - WebKit::WebFileSystemCallbacks* callbacks); - void ReadMetadata( - const string16& path, - WebKit::WebFileSystemCallbacks* callbacks); - void Create( - const string16& path, - bool exclusive, - bool for_directory, - WebKit::WebFileSystemCallbacks* callbacks); - void Exists( - const string16& path, - bool for_directory, - WebKit::WebFileSystemCallbacks* callbacks); - void ReadDirectory( - const string16& path, - WebKit::WebFileSystemCallbacks* callbacks); + bool Move(const FilePath& src_path, + const FilePath& dest_path, + fileapi::FileSystemCallbackDispatcher* dispatcher); + bool Copy(const FilePath& src_path, + const FilePath& dest_path, + fileapi::FileSystemCallbackDispatcher* dispatcher); + bool Remove(const FilePath& path, + fileapi::FileSystemCallbackDispatcher* dispatcher); + bool ReadMetadata(const FilePath& path, + fileapi::FileSystemCallbackDispatcher* dispatcher); + bool Create(const FilePath& path, + bool exclusive, + bool is_directory, + bool recursive, + fileapi::FileSystemCallbackDispatcher* dispatcher); + bool Exists(const FilePath& path, + bool for_directory, + fileapi::FileSystemCallbackDispatcher* dispatcher); + bool ReadDirectory(const FilePath& path, + fileapi::FileSystemCallbackDispatcher* dispatcher); private: void DidSucceed(int request_id); - void DidReadMetadata( - int request_id, - const base::PlatformFileInfo& file_info); + void DidReadMetadata(int request_id, + const base::PlatformFileInfo& file_info); void DidReadDirectory( - const ViewMsg_FileSystem_DidReadDirectory_Params& params); - void DidFail( int request_id, - WebKit::WebFileError); + const std::vector<base::file_util_proxy::Entry>& entries, + bool has_more); + void DidFail(int request_id, base::PlatformFileError error_code); - IDMap<WebKit::WebFileSystemCallbacks> callbacks_; + IDMap<fileapi::FileSystemCallbackDispatcher, IDMapOwnPointer> dispatchers_; DISALLOW_COPY_AND_ASSIGN(FileSystemDispatcher); }; diff --git a/chrome/common/file_system/webfilesystem_impl.cc b/chrome/common/file_system/webfilesystem_impl.cc index 49a07d6..546ed25 100644 --- a/chrome/common/file_system/webfilesystem_impl.cc +++ b/chrome/common/file_system/webfilesystem_impl.cc @@ -6,73 +6,164 @@ #include "chrome/common/file_system/file_system_dispatcher.h" #include "chrome/common/child_thread.h" +#include "third_party/WebKit/WebKit/chromium/public/WebFileInfo.h" +#include "third_party/WebKit/WebKit/chromium/public/WebFileSystemCallbacks.h" +#include "third_party/WebKit/WebKit/chromium/public/WebString.h" +#include "webkit/glue/webkit_glue.h" -using WebKit::WebString; +using WebKit::WebFileInfo; using WebKit::WebFileSystemCallbacks; +using WebKit::WebFileSystemEntry; +using WebKit::WebString; +using WebKit::WebVector; + +namespace { + +WebKit::WebFileError PlatformFileErrorToWebFileError( + base::PlatformFileError error_code) { + switch (error_code) { + case base::PLATFORM_FILE_ERROR_NOT_FOUND: + return WebKit::WebFileErrorNotFound; + case base::PLATFORM_FILE_ERROR_INVALID_OPERATION: + case base::PLATFORM_FILE_ERROR_EXISTS: + case base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY: + return WebKit::WebFileErrorInvalidModification; + case base::PLATFORM_FILE_ERROR_ACCESS_DENIED: + return WebKit::WebFileErrorNoModificationAllowed; + case base::PLATFORM_FILE_ERROR_FAILED: + return WebKit::WebFileErrorInvalidState; + case base::PLATFORM_FILE_ERROR_ABORT: + return WebKit::WebFileErrorAbort; + default: + return WebKit::WebFileErrorInvalidModification; + } +} + +class WebFileSystemCallbackDispatcherImpl + : public fileapi::FileSystemCallbackDispatcher { + public: + explicit WebFileSystemCallbackDispatcherImpl( + WebFileSystemCallbacks* callbacks) + : callbacks_(callbacks) { + DCHECK(callbacks_); + } + + virtual ~WebFileSystemCallbackDispatcherImpl() { + } + + // FileSystemCallbackDispatcher implementation + virtual void DidSucceed() { + callbacks_->didSucceed(); + } + + virtual void DidReadMetadata(const base::PlatformFileInfo& file_info) { + WebFileInfo web_file_info; + web_file_info.modificationTime = file_info.last_modified.ToDoubleT(); + callbacks_->didReadMetadata(web_file_info); + } + + virtual void DidReadDirectory( + const std::vector<base::file_util_proxy::Entry>& entries, bool has_more) { + WebVector<WebFileSystemEntry> file_system_entries(entries.size()); + for (size_t i = 0; i < entries.size(); i++) { + file_system_entries[i].name = + webkit_glue::FilePathStringToWebString(entries[i].name); + file_system_entries[i].isDirectory = entries[i].is_directory; + } + callbacks_->didReadDirectory(file_system_entries, has_more); + } + + virtual void DidOpenFileSystem(const string16&, const FilePath&) { + NOTREACHED(); + } + + virtual void DidFail(base::PlatformFileError error_code) { + callbacks_->didFail(PlatformFileErrorToWebFileError(error_code)); + } + + private: + WebFileSystemCallbacks* callbacks_; +}; + +} // namespace WebFileSystemImpl::WebFileSystemImpl() { } void WebFileSystemImpl::move(const WebString& src_path, - const WebString& dest_path, WebFileSystemCallbacks* callbacks) { + const WebString& dest_path, + WebFileSystemCallbacks* callbacks) { FileSystemDispatcher* dispatcher = ChildThread::current()->file_system_dispatcher(); - dispatcher->Move(src_path, dest_path, callbacks); + dispatcher->Move(webkit_glue::WebStringToFilePath(src_path), + webkit_glue::WebStringToFilePath(dest_path), + new WebFileSystemCallbackDispatcherImpl(callbacks)); } -void WebFileSystemImpl::copy(const WebKit::WebString& src_path, - const WebKit::WebString& dest_path, - WebKit::WebFileSystemCallbacks* callbacks) { +void WebFileSystemImpl::copy(const WebString& src_path, + const WebString& dest_path, + WebFileSystemCallbacks* callbacks) { FileSystemDispatcher* dispatcher = ChildThread::current()->file_system_dispatcher(); - dispatcher->Copy(src_path, dest_path, callbacks); + dispatcher->Copy(webkit_glue::WebStringToFilePath(src_path), + webkit_glue::WebStringToFilePath(dest_path), + new WebFileSystemCallbackDispatcherImpl(callbacks)); } void WebFileSystemImpl::remove(const WebString& path, - WebFileSystemCallbacks* callbacks) { + WebFileSystemCallbacks* callbacks) { FileSystemDispatcher* dispatcher = ChildThread::current()->file_system_dispatcher(); - dispatcher->Remove(path, callbacks); + dispatcher->Remove(webkit_glue::WebStringToFilePath(path), + new WebFileSystemCallbackDispatcherImpl(callbacks)); } void WebFileSystemImpl::readMetadata(const WebString& path, - WebFileSystemCallbacks* callbacks) { + WebFileSystemCallbacks* callbacks) { FileSystemDispatcher* dispatcher = ChildThread::current()->file_system_dispatcher(); - dispatcher->ReadMetadata(path, callbacks); + dispatcher->ReadMetadata(webkit_glue::WebStringToFilePath(path), + new WebFileSystemCallbackDispatcherImpl(callbacks)); } void WebFileSystemImpl::createFile(const WebString& path, - bool exclusive, WebFileSystemCallbacks* callbacks) { + bool exclusive, + WebFileSystemCallbacks* callbacks) { FileSystemDispatcher* dispatcher = ChildThread::current()->file_system_dispatcher(); - dispatcher->Create(path, exclusive, false, callbacks); + dispatcher->Create(webkit_glue::WebStringToFilePath(path), exclusive, false, + false, new WebFileSystemCallbackDispatcherImpl(callbacks)); } void WebFileSystemImpl::createDirectory(const WebString& path, - bool exclusive, WebFileSystemCallbacks* callbacks) { + bool exclusive, + WebFileSystemCallbacks* callbacks) { FileSystemDispatcher* dispatcher = ChildThread::current()->file_system_dispatcher(); - dispatcher->Create(path, exclusive, true, callbacks); + dispatcher->Create(webkit_glue::WebStringToFilePath(path), exclusive, true, + false, new WebFileSystemCallbackDispatcherImpl(callbacks)); } void WebFileSystemImpl::fileExists(const WebString& path, - WebFileSystemCallbacks* callbacks) { + WebFileSystemCallbacks* callbacks) { FileSystemDispatcher* dispatcher = ChildThread::current()->file_system_dispatcher(); - dispatcher->Exists(path, false, callbacks); + dispatcher->Exists(webkit_glue::WebStringToFilePath(path), false, + new WebFileSystemCallbackDispatcherImpl(callbacks)); } void WebFileSystemImpl::directoryExists(const WebString& path, - WebFileSystemCallbacks* callbacks) { + WebFileSystemCallbacks* callbacks) { FileSystemDispatcher* dispatcher = ChildThread::current()->file_system_dispatcher(); - dispatcher->Exists(path, true, callbacks); + dispatcher->Exists(webkit_glue::WebStringToFilePath(path), true, + new WebFileSystemCallbackDispatcherImpl(callbacks)); } void WebFileSystemImpl::readDirectory(const WebString& path, - WebFileSystemCallbacks* callbacks) { + WebFileSystemCallbacks* callbacks) { FileSystemDispatcher* dispatcher = ChildThread::current()->file_system_dispatcher(); - dispatcher->ReadDirectory(path, callbacks); + dispatcher->ReadDirectory(webkit_glue::WebStringToFilePath(path), + new WebFileSystemCallbackDispatcherImpl(callbacks)); } diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h index 8d7a973..4fcb1e5 100644 --- a/chrome/common/render_messages.h +++ b/chrome/common/render_messages.h @@ -106,7 +106,6 @@ struct ViewMsg_ExtensionsUpdated_Params; struct ViewMsg_DeviceOrientationUpdated_Params; struct ViewHostMsg_DomMessage_Params; struct ViewHostMsg_OpenFileSystemRequest_Params; -struct ViewMsg_FileSystem_DidReadDirectory_Params; struct ViewHostMsg_AccessibilityNotification_Params; // Values that may be OR'd together to form the 'flags' parameter of the diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index 070123d..f391223 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -47,6 +47,12 @@ class SkBitmap; struct ThumbnailScore; class WebCursor; +namespace base { +namespace file_util_proxy { +struct Entry; +} +} + namespace IPC { struct ChannelHandle; class Message; @@ -1035,11 +1041,14 @@ IPC_BEGIN_MESSAGES(View) IPC_MESSAGE_CONTROL2(ViewMsg_FileSystem_DidReadMetadata, int /* request_id */, base::PlatformFileInfo) - IPC_MESSAGE_CONTROL1(ViewMsg_FileSystem_DidReadDirectory, - ViewMsg_FileSystem_DidReadDirectory_Params) + IPC_MESSAGE_CONTROL3(ViewMsg_FileSystem_DidReadDirectory, + int /* request_id */, + std::vector<base::file_util_proxy::Entry> /* entries */, + bool /* has_more */) + IPC_MESSAGE_CONTROL2(ViewMsg_FileSystem_DidFail, int /* request_id */, - WebKit::WebFileError /* error_code */) + base::PlatformFileError /* error_code */) // The response to ViewHostMsg_AsyncOpenFile. IPC_MESSAGE_ROUTED3(ViewMsg_AsyncOpenFile_ACK, @@ -2816,11 +2825,12 @@ IPC_BEGIN_MESSAGES(ViewHost) FilePath /* path */) // WebFileSystem::create() message. - IPC_MESSAGE_CONTROL4(ViewHostMsg_FileSystem_Create, + IPC_MESSAGE_CONTROL5(ViewHostMsg_FileSystem_Create, int /* request_id */, FilePath /* path */, bool /* exclusive */, - bool /* is_directory */) + bool /* is_directory */, + bool /* recursive */) // WebFileSystem::exists() messages. IPC_MESSAGE_CONTROL3(ViewHostMsg_FileSystem_Exists, diff --git a/chrome/common/render_messages_params.cc b/chrome/common/render_messages_params.cc index 325de2f..4fd83a3 100644 --- a/chrome/common/render_messages_params.cc +++ b/chrome/common/render_messages_params.cc @@ -325,16 +325,6 @@ ViewHostMsg_OpenFileSystemRequest_Params:: ~ViewHostMsg_OpenFileSystemRequest_Params() { } -ViewMsg_FileSystem_DidReadDirectory_Params:: - ViewMsg_FileSystem_DidReadDirectory_Params() - : request_id(0), - has_more(false) { -} - -ViewMsg_FileSystem_DidReadDirectory_Params:: - ~ViewMsg_FileSystem_DidReadDirectory_Params() { -} - namespace IPC { // Self contained templates which are only used inside serializing Params @@ -1809,36 +1799,6 @@ void ParamTraits<ViewHostMsg_OpenFileSystemRequest_Params>::Log( l->append(")"); } -void ParamTraits<ViewMsg_FileSystem_DidReadDirectory_Params>::Write( - Message* m, - const param_type& p) { - WriteParam(m, p.request_id); - WriteParam(m, p.entries); - WriteParam(m, p.has_more); -} - -bool ParamTraits<ViewMsg_FileSystem_DidReadDirectory_Params>::Read( - const Message* m, - void** iter, - param_type* p) { - return - ReadParam(m, iter, &p->request_id) && - ReadParam(m, iter, &p->entries) && - ReadParam(m, iter, &p->has_more); -} - -void ParamTraits<ViewMsg_FileSystem_DidReadDirectory_Params>::Log( - const param_type& p, - std::string* l) { - l->append("("); - LogParam(p.request_id, l); - l->append(", "); - LogParam(p.entries, l); - l->append(", "); - LogParam(p.has_more, l); - l->append(")"); -} - void ParamTraits<base::file_util_proxy::Entry>::Write( Message* m, const param_type& p) { diff --git a/chrome/common/render_messages_params.h b/chrome/common/render_messages_params.h index 4847695..70f9825 100644 --- a/chrome/common/render_messages_params.h +++ b/chrome/common/render_messages_params.h @@ -964,20 +964,6 @@ struct ViewHostMsg_OpenFileSystemRequest_Params { int64 requested_size; }; -struct ViewMsg_FileSystem_DidReadDirectory_Params { - ViewMsg_FileSystem_DidReadDirectory_Params(); - ~ViewMsg_FileSystem_DidReadDirectory_Params(); - - // The response should have this id. - int request_id; - - // A vector of directory entries. - std::vector<base::file_util_proxy::Entry> entries; - - // Indicates if there will be more entries. - bool has_more; -}; - struct ViewHostMsg_AccessibilityNotification_Params { enum NotificationType { // The node checked state has changed. @@ -1259,14 +1245,6 @@ struct ParamTraits<ViewHostMsg_OpenFileSystemRequest_Params> { }; template <> -struct ParamTraits<ViewMsg_FileSystem_DidReadDirectory_Params> { - typedef ViewMsg_FileSystem_DidReadDirectory_Params param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, void** iter, param_type* p); - static void Log(const param_type& p, std::string* l); -}; - -template <> struct ParamTraits<base::file_util_proxy::Entry> { typedef base::file_util_proxy::Entry param_type; static void Write(Message* m, const param_type& p); diff --git a/webkit/fileapi/file_system_callback_dispatcher.h b/webkit/fileapi/file_system_callback_dispatcher.h new file mode 100644 index 0000000..37f22c23 --- /dev/null +++ b/webkit/fileapi/file_system_callback_dispatcher.h @@ -0,0 +1,49 @@ +// 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. + +#ifndef WEBKIT_FILEAPI_FILE_SYSTEM_CALLBACK_DISPATCHER_H_ +#define WEBKIT_FILEAPI_FILE_SYSTEM_CALLBACK_DISPATCHER_H_ + +#include <vector> + +#include "base/file_util_proxy.h" +#include "base/string16.h" + +namespace fileapi { + +// This class mirrors the callbacks in +// third_party/WebKit/WebKit/chromium/public/WebFileSystemCallbacks.h, +// but uses chromium types. +class FileSystemCallbackDispatcher { + public: + // Callback for various operations that don't require return values. + virtual void DidSucceed() = 0; + + // Callback to report information for a file. + virtual void DidReadMetadata(const base::PlatformFileInfo& file_info) = 0; + + // Callback to report the contents of a directory. If the contents of + // the given directory are reported in one batch, then |entries| will have + // the list of all files/directories in the given directory, |has_more| will + // be false, and this callback will be called only once. If the contents of + // the given directory are reported in multiple chunks, then this callback + // will be called multiple times, |entries| will have only a subset of + // all contents (the subsets reported in any two calls are disjoint), and + // |has_more| will be true, except for the last chunk. + virtual void DidReadDirectory( + const std::vector<base::file_util_proxy::Entry>& entries, + bool has_more) = 0; + + // Callback for opening a file system. Called with a name and root path for + // the FileSystem when the request is accepted. Used by WebFileSystem API. + virtual void DidOpenFileSystem(const string16& name, + const FilePath& root_path) = 0; + + // Called with an error code when a requested operation has failed. + virtual void DidFail(base::PlatformFileError error_code) = 0; +}; + +} // namespace fileapi + +#endif // WEBKIT_FILEAPI_FILE_SYSTEM_CALLBACK_DISPATCHER_H_ diff --git a/webkit/fileapi/file_system_operation.cc b/webkit/fileapi/file_system_operation.cc index 90eabad..dba9881 100644 --- a/webkit/fileapi/file_system_operation.cc +++ b/webkit/fileapi/file_system_operation.cc @@ -4,44 +4,32 @@ #include "webkit/fileapi/file_system_operation.h" -#include "webkit/fileapi/file_system_operation_client.h" -#include "third_party/WebKit/WebKit/chromium/public/WebFileError.h" - -namespace { -// Utility method for error conversions. -WebKit::WebFileError PlatformFileErrorToWebFileError( - base::PlatformFileError rv) { - switch (rv) { - case base::PLATFORM_FILE_ERROR_NOT_FOUND: - return WebKit::WebFileErrorNotFound; - case base::PLATFORM_FILE_ERROR_INVALID_OPERATION: - case base::PLATFORM_FILE_ERROR_EXISTS: - case base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY: - return WebKit::WebFileErrorInvalidModification; - case base::PLATFORM_FILE_ERROR_ACCESS_DENIED: - return WebKit::WebFileErrorNoModificationAllowed; - default: - return WebKit::WebFileErrorInvalidModification; - } -} -} // namespace +#include "webkit/fileapi/file_system_callback_dispatcher.h" namespace fileapi { FileSystemOperation::FileSystemOperation( - FileSystemOperationClient* client, + FileSystemCallbackDispatcher* dispatcher, scoped_refptr<base::MessageLoopProxy> proxy) : proxy_(proxy), - client_(client), - callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), - operation_pending_(false) { - DCHECK(client_); + dispatcher_(dispatcher), + callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { + DCHECK(dispatcher); +#ifndef NDEBUG + operation_pending_ = false; +#endif +} + +FileSystemOperation::~FileSystemOperation() { } void FileSystemOperation::CreateFile(const FilePath& path, bool exclusive) { +#ifndef NDEBUG DCHECK(!operation_pending_); operation_pending_ = true; +#endif + base::FileUtilProxy::CreateOrOpen( proxy_, path, base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_READ, callback_factory_.NewCallback( @@ -50,18 +38,25 @@ void FileSystemOperation::CreateFile(const FilePath& path, } void FileSystemOperation::CreateDirectory(const FilePath& path, - bool exclusive) { + bool exclusive, + bool recursive) { +#ifndef NDEBUG DCHECK(!operation_pending_); operation_pending_ = true; - base::FileUtilProxy::CreateDirectory(proxy_, path, exclusive, - false /* recursive */, callback_factory_.NewCallback( +#endif + + base::FileUtilProxy::CreateDirectory( + proxy_, path, exclusive, recursive, callback_factory_.NewCallback( &FileSystemOperation::DidFinishFileOperation)); } void FileSystemOperation::Copy(const FilePath& src_path, const FilePath& dest_path) { +#ifndef NDEBUG DCHECK(!operation_pending_); operation_pending_ = true; +#endif + base::FileUtilProxy::Copy(proxy_, src_path, dest_path, callback_factory_.NewCallback( &FileSystemOperation::DidFinishFileOperation)); @@ -69,45 +64,63 @@ void FileSystemOperation::Copy(const FilePath& src_path, void FileSystemOperation::Move(const FilePath& src_path, const FilePath& dest_path) { +#ifndef NDEBUG DCHECK(!operation_pending_); operation_pending_ = true; +#endif + base::FileUtilProxy::Move(proxy_, src_path, dest_path, callback_factory_.NewCallback( &FileSystemOperation::DidFinishFileOperation)); } void FileSystemOperation::DirectoryExists(const FilePath& path) { +#ifndef NDEBUG DCHECK(!operation_pending_); operation_pending_ = true; +#endif + base::FileUtilProxy::GetFileInfo(proxy_, path, callback_factory_.NewCallback( &FileSystemOperation::DidDirectoryExists)); } void FileSystemOperation::FileExists(const FilePath& path) { +#ifndef NDEBUG DCHECK(!operation_pending_); operation_pending_ = true; +#endif + base::FileUtilProxy::GetFileInfo(proxy_, path, callback_factory_.NewCallback( &FileSystemOperation::DidFileExists)); } void FileSystemOperation::GetMetadata(const FilePath& path) { +#ifndef NDEBUG DCHECK(!operation_pending_); operation_pending_ = true; +#endif + base::FileUtilProxy::GetFileInfo(proxy_, path, callback_factory_.NewCallback( &FileSystemOperation::DidGetMetadata)); } void FileSystemOperation::ReadDirectory(const FilePath& path) { +#ifndef NDEBUG DCHECK(!operation_pending_); operation_pending_ = true; +#endif + base::FileUtilProxy::ReadDirectory(proxy_, path, callback_factory_.NewCallback( &FileSystemOperation::DidReadDirectory)); } void FileSystemOperation::Remove(const FilePath& path) { +#ifndef NDEBUG DCHECK(!operation_pending_); operation_pending_ = true; +#endif + base::FileUtilProxy::Delete(proxy_, path, callback_factory_.NewCallback( &FileSystemOperation::DidFinishFileOperation)); } @@ -126,17 +139,17 @@ void FileSystemOperation::DidCreateFileNonExclusive( // Suppress the already exists error and report success. if (rv == base::PLATFORM_FILE_OK || rv == base::PLATFORM_FILE_ERROR_EXISTS) - client_->DidSucceed(this); + dispatcher_->DidSucceed(); else - client_->DidFail(PlatformFileErrorToWebFileError(rv), this); + dispatcher_->DidFail(rv); } void FileSystemOperation::DidFinishFileOperation( base::PlatformFileError rv) { if (rv == base::PLATFORM_FILE_OK) - client_->DidSucceed(this); + dispatcher_->DidSucceed(); else - client_->DidFail(PlatformFileErrorToWebFileError(rv), this); + dispatcher_->DidFail(rv); } void FileSystemOperation::DidDirectoryExists( @@ -144,14 +157,11 @@ void FileSystemOperation::DidDirectoryExists( const base::PlatformFileInfo& file_info) { if (rv == base::PLATFORM_FILE_OK) { if (file_info.is_directory) - client_->DidSucceed(this); + dispatcher_->DidSucceed(); else - client_->DidFail(WebKit::WebFileErrorInvalidState, - this); - } else { - // Something else went wrong. - client_->DidFail(PlatformFileErrorToWebFileError(rv), this); - } + dispatcher_->DidFail(base::PLATFORM_FILE_ERROR_FAILED); + } else + dispatcher_->DidFail(rv); } void FileSystemOperation::DidFileExists( @@ -159,34 +169,29 @@ void FileSystemOperation::DidFileExists( const base::PlatformFileInfo& file_info) { if (rv == base::PLATFORM_FILE_OK) { if (file_info.is_directory) - client_->DidFail(WebKit::WebFileErrorInvalidState, - this); + dispatcher_->DidFail(base::PLATFORM_FILE_ERROR_FAILED); else - client_->DidSucceed(this); - } else { - // Something else went wrong. - client_->DidFail(PlatformFileErrorToWebFileError(rv), this); - } + dispatcher_->DidSucceed(); + } else + dispatcher_->DidFail(rv); } void FileSystemOperation::DidGetMetadata( base::PlatformFileError rv, const base::PlatformFileInfo& file_info) { if (rv == base::PLATFORM_FILE_OK) - client_->DidReadMetadata(file_info, this); + dispatcher_->DidReadMetadata(file_info); else - client_->DidFail(PlatformFileErrorToWebFileError(rv), this); + dispatcher_->DidFail(rv); } void FileSystemOperation::DidReadDirectory( base::PlatformFileError rv, const std::vector<base::file_util_proxy::Entry>& entries) { if (rv == base::PLATFORM_FILE_OK) - client_->DidReadDirectory( - entries, false /* has_more */ , this); + dispatcher_->DidReadDirectory(entries, false /* has_more */); else - client_->DidFail(PlatformFileErrorToWebFileError(rv), this); + dispatcher_->DidFail(rv); } } // namespace fileapi - diff --git a/webkit/fileapi/file_system_operation.h b/webkit/fileapi/file_system_operation.h index 9e0fed9..5df4d4d 100644 --- a/webkit/fileapi/file_system_operation.h +++ b/webkit/fileapi/file_system_operation.h @@ -13,10 +13,11 @@ #include "base/platform_file.h" #include "base/ref_counted.h" #include "base/scoped_callback_factory.h" +#include "base/scoped_ptr.h" namespace fileapi { -class FileSystemOperationClient; +class FileSystemCallbackDispatcher; // This class is designed to serve one-time file system operation per instance. // Only one method(CreateFile, CreateDirectory, Copy, Move, DirectoryExists, @@ -24,15 +25,16 @@ class FileSystemOperationClient; // this object and it should be called no more than once. class FileSystemOperation { public: - FileSystemOperation( - FileSystemOperationClient* client, - scoped_refptr<base::MessageLoopProxy> proxy); + FileSystemOperation(FileSystemCallbackDispatcher* dispatcher, + scoped_refptr<base::MessageLoopProxy> proxy); + ~FileSystemOperation(); void CreateFile(const FilePath& path, bool exclusive); void CreateDirectory(const FilePath& path, - bool exclusive); + bool exclusive, + bool recursive); void Copy(const FilePath& src_path, const FilePath& dest_path); @@ -82,13 +84,14 @@ class FileSystemOperation { base::PlatformFileError rv, const std::vector<base::file_util_proxy::Entry>& entries); - // Not owned. - FileSystemOperationClient* client_; + scoped_ptr<FileSystemCallbackDispatcher> dispatcher_; base::ScopedCallbackFactory<FileSystemOperation> callback_factory_; +#ifndef NDEBUG // A flag to make sure we call operation only once per instance. bool operation_pending_; +#endif DISALLOW_COPY_AND_ASSIGN(FileSystemOperation); }; @@ -96,4 +99,3 @@ class FileSystemOperation { } // namespace fileapi #endif // WEBKIT_FILEAPI_FILE_SYSTEM_OPERATION_H_ - diff --git a/webkit/fileapi/file_system_operation_client.h b/webkit/fileapi/file_system_operation_client.h deleted file mode 100644 index b126d4e..0000000 --- a/webkit/fileapi/file_system_operation_client.h +++ /dev/null @@ -1,39 +0,0 @@ -// 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. - -#ifndef WEBKIT_FILEAPI_FILE_SYSTEM_OPERATION_CLIENT_H_ -#define WEBKIT_FILEAPI_FILE_SYSTEM_OPERATION_CLIENT_H_ - -#include <vector> - -#include "base/file_util_proxy.h" -#include "third_party/WebKit/WebKit/chromium/public/WebFileError.h" - -namespace fileapi { - -class FileSystemOperation; - -// Interface for client of FileSystemOperation. -class FileSystemOperationClient { - public: - virtual ~FileSystemOperationClient() {} - - virtual void DidFail( - WebKit::WebFileError status, - FileSystemOperation* operation) = 0; - - virtual void DidSucceed(FileSystemOperation* operation) = 0; - - // Info about the file entry such as modification date and size. - virtual void DidReadMetadata(const base::PlatformFileInfo& info, - FileSystemOperation* operation) = 0; - - virtual void DidReadDirectory( - const std::vector<base::file_util_proxy::Entry>& entries, - bool has_more, FileSystemOperation* operation) = 0; -}; - -} // namespace fileapi - -#endif // WEBKIT_FILEAPI_FILE_SYSTEM_OPERATION_CLIENT_H_ diff --git a/webkit/fileapi/file_system_operation_unittest.cc b/webkit/fileapi/file_system_operation_unittest.cc new file mode 100644 index 0000000..1d0855c --- /dev/null +++ b/webkit/fileapi/file_system_operation_unittest.cc @@ -0,0 +1,555 @@ +// 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/file_system_operation.h" + +#include "base/logging.h" +#include "base/message_loop.h" +#include "base/scoped_ptr.h" +#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_operation.h" + +const int kInvalidRequestId = -1; +const int kFileOperationStatusNotSet = 0; +const int kFileOperationSucceeded = 1; + +static int last_request_id = -1; + +bool FileExists(FilePath path) { + return file_util::PathExists(path) && !file_util::DirectoryExists(path); +} + +class MockDispatcher : public fileapi::FileSystemCallbackDispatcher { + public: + MockDispatcher(int request_id) + : status_(kFileOperationStatusNotSet), + request_id_(request_id) { + } + + virtual void DidFail(base::PlatformFileError status) { + status_ = status; + } + + virtual void DidSucceed() { + status_ = kFileOperationSucceeded; + } + + virtual void DidReadMetadata(const base::PlatformFileInfo& info) { + info_ = info; + status_ = kFileOperationSucceeded; + } + + virtual void DidReadDirectory( + const std::vector<base::file_util_proxy::Entry>& entries, + bool /* has_more */) { + entries_ = entries; + } + + virtual void DidOpenFileSystem(const string16&, const FilePath&) { + NOTREACHED(); + } + + // Helpers for testing. + int status() const { return status_; } + int request_id() const { return request_id_; } + const base::PlatformFileInfo& info() const { return info_; } + const std::vector<base::file_util_proxy::Entry>& entries() const { + return entries_; + } + + private: + int status_; + int request_id_; + base::PlatformFileInfo info_; + std::vector<base::file_util_proxy::Entry> entries_; +}; + +class FileSystemOperationTest : public testing::Test { + public: + FileSystemOperationTest() + : request_id_(kInvalidRequestId), + operation_(NULL) { + base_.CreateUniqueTempDir(); + EXPECT_TRUE(base_.IsValid()); + } + + fileapi::FileSystemOperation* operation() { + request_id_ = ++last_request_id; + mock_dispatcher_ = new MockDispatcher(request_id_); + operation_.reset(new fileapi::FileSystemOperation( + mock_dispatcher_, base::MessageLoopProxy::CreateForCurrentThread())); + return operation_.get(); + } + + protected: + // Common temp base for all non-existing file/dir path test cases. + // This is in case a dir on test machine exists. It's better to + // create temp and then create non-existing file paths under it. + ScopedTempDir base_; + + int request_id_; + scoped_ptr<fileapi::FileSystemOperation> operation_; + + // Owned by |operation_|. + MockDispatcher* mock_dispatcher_; + + DISALLOW_COPY_AND_ASSIGN(FileSystemOperationTest); +}; + +TEST_F(FileSystemOperationTest, TestMoveFailureSrcDoesntExist) { + FilePath src(base_.path().Append(FILE_PATH_LITERAL("a"))); + FilePath dest(base_.path().Append(FILE_PATH_LITERAL("b"))); + operation()->Move(src, dest); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, mock_dispatcher_->status()); + EXPECT_EQ(request_id_, mock_dispatcher_->request_id()); +} + + +TEST_F(FileSystemOperationTest, TestMoveFailureContainsPath) { + ScopedTempDir dir_under_base; + dir_under_base.CreateUniqueTempDirUnderPath(base_.path()); + operation()->Move(base_.path(), dir_under_base.path()); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(base::PLATFORM_FILE_ERROR_INVALID_OPERATION, + mock_dispatcher_->status()); + EXPECT_EQ(request_id_, mock_dispatcher_->request_id()); +} + +TEST_F(FileSystemOperationTest, TestMoveFailureSrcDirExistsDestFile) { + // Src exists and is dir. Dest is a file. + ScopedTempDir dest_dir; + ASSERT_TRUE(dest_dir.CreateUniqueTempDir()); + FilePath dest_file; + file_util::CreateTemporaryFileInDir(dest_dir.path(), &dest_file); + + operation()->Move(base_.path(), dest_file); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(base::PLATFORM_FILE_ERROR_EXISTS, mock_dispatcher_->status()); + EXPECT_EQ(request_id_, mock_dispatcher_->request_id()); +} + +TEST_F(FileSystemOperationTest, TestMoveFailureDestParentDoesntExist) { + // Dest. parent path does not exist. + ScopedTempDir src_dir; + ASSERT_TRUE(src_dir.CreateUniqueTempDir()); + FilePath nonexisting_file = base_.path().Append( + FILE_PATH_LITERAL("NonexistingDir")).Append( + FILE_PATH_LITERAL("NonexistingFile"));; + + operation()->Move(src_dir.path(), nonexisting_file); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, mock_dispatcher_->status()); + EXPECT_EQ(request_id_, mock_dispatcher_->request_id()); +} + +TEST_F(FileSystemOperationTest, TestMoveSuccessSrcFileAndOverwrite) { + ScopedTempDir src_dir; + ASSERT_TRUE(src_dir.CreateUniqueTempDir()); + FilePath src_file; + file_util::CreateTemporaryFileInDir(src_dir.path(), &src_file); + + ScopedTempDir dest_dir; + ASSERT_TRUE(dest_dir.CreateUniqueTempDir()); + FilePath dest_file; + file_util::CreateTemporaryFileInDir(dest_dir.path(), &dest_file); + + operation()->Move(src_file, dest_file); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(kFileOperationSucceeded, mock_dispatcher_->status()); + EXPECT_TRUE(FileExists(dest_file)); + EXPECT_EQ(request_id_, mock_dispatcher_->request_id()); +} + +TEST_F(FileSystemOperationTest, TestMoveSuccessSrcFileAndNew) { + ScopedTempDir src_dir; + ASSERT_TRUE(src_dir.CreateUniqueTempDir()); + FilePath src_file; + file_util::CreateTemporaryFileInDir(src_dir.path(), &src_file); + + ScopedTempDir dest_dir; + ASSERT_TRUE(dest_dir.CreateUniqueTempDir()); + FilePath dest_file(dest_dir.path().Append(FILE_PATH_LITERAL("NewFile"))); + + operation()->Move(src_file, dest_file); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(kFileOperationSucceeded, mock_dispatcher_->status()); + EXPECT_TRUE(FileExists(dest_file)); + EXPECT_EQ(request_id_, mock_dispatcher_->request_id()); +} + +TEST_F(FileSystemOperationTest, TestCopyFailureSrcDoesntExist) { + FilePath src(base_.path().Append(FILE_PATH_LITERAL("a"))); + FilePath dest(base_.path().Append(FILE_PATH_LITERAL("b"))); + operation()->Copy(src, dest); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, mock_dispatcher_->status()); + EXPECT_EQ(request_id_, mock_dispatcher_->request_id()); +} + +TEST_F(FileSystemOperationTest, TestCopyFailureContainsPath) { + FilePath file_under_base = base_.path().Append(FILE_PATH_LITERAL("b")); + operation()->Copy(base_.path(), file_under_base); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(base::PLATFORM_FILE_ERROR_FAILED, mock_dispatcher_->status()); + EXPECT_EQ(request_id_, mock_dispatcher_->request_id()); +} + +TEST_F(FileSystemOperationTest, TestCopyFailureSrcDirExistsDestFile) { + // Src exists and is dir. Dest is a file. + ScopedTempDir dir; + ASSERT_TRUE(dir.CreateUniqueTempDir()); + FilePath dest_file; + file_util::CreateTemporaryFileInDir(dir.path(), &dest_file); + + operation()->Copy(base_.path(), dest_file); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY, + mock_dispatcher_->status()); + EXPECT_EQ(request_id_, mock_dispatcher_->request_id()); +} + +TEST_F(FileSystemOperationTest, TestCopyFailureDestParentDoesntExist) { + // Dest. parent path does not exist. + ScopedTempDir dir; + ASSERT_TRUE(dir.CreateUniqueTempDir()); + FilePath src_dir = dir.path(); + + FilePath nonexisting(base_.path().Append(FILE_PATH_LITERAL("DontExistDir"))); + file_util::EnsureEndsWithSeparator(&nonexisting); + FilePath nonexisting_file = nonexisting.Append( + FILE_PATH_LITERAL("DontExistFile")); + + operation()->Copy(src_dir, nonexisting_file); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, mock_dispatcher_->status()); + EXPECT_EQ(request_id_, mock_dispatcher_->request_id()); +} + +TEST_F(FileSystemOperationTest, TestCopySuccessSrcFileAndOverwrite) { + ScopedTempDir src_dir; + ASSERT_TRUE(src_dir.CreateUniqueTempDir()); + FilePath src_file; + file_util::CreateTemporaryFileInDir(src_dir.path(), &src_file); + + ScopedTempDir dest_dir; + ASSERT_TRUE(dest_dir.CreateUniqueTempDir()); + FilePath dest_file; + file_util::CreateTemporaryFileInDir(dest_dir.path(), &dest_file); + + operation()->Copy(src_file, dest_file); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(kFileOperationSucceeded, mock_dispatcher_->status()); + EXPECT_TRUE(FileExists(dest_file)); + EXPECT_EQ(request_id_, mock_dispatcher_->request_id()); +} + +TEST_F(FileSystemOperationTest, TestCopySuccessSrcFileAndNew) { + ScopedTempDir src_dir; + ASSERT_TRUE(src_dir.CreateUniqueTempDir()); + FilePath src_file; + file_util::CreateTemporaryFileInDir(src_dir.path(), &src_file); + + ScopedTempDir dest_dir; + ASSERT_TRUE(dest_dir.CreateUniqueTempDir()); + FilePath dest_file(dest_dir.path().Append(FILE_PATH_LITERAL("NewFile"))); + + operation()->Copy(src_file, dest_file); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(kFileOperationSucceeded, mock_dispatcher_->status()); + EXPECT_TRUE(FileExists(dest_file)); + EXPECT_EQ(request_id_, mock_dispatcher_->request_id()); +} + +TEST_F(FileSystemOperationTest, TestCopySuccessSrcDir) { + ScopedTempDir src_dir; + ASSERT_TRUE(src_dir.CreateUniqueTempDir()); + + ScopedTempDir dest_dir; + ASSERT_TRUE(dest_dir.CreateUniqueTempDir()); + + operation()->Copy(src_dir.path(), dest_dir.path()); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(kFileOperationSucceeded, mock_dispatcher_->status()); + EXPECT_EQ(request_id_, mock_dispatcher_->request_id()); +} + +TEST_F(FileSystemOperationTest, TestCopyDestParentExistsSuccess) { + ScopedTempDir src_dir; + ASSERT_TRUE(src_dir.CreateUniqueTempDir()); + FilePath src_file; + file_util::CreateTemporaryFileInDir(src_dir.path(), &src_file); + + ScopedTempDir dest_dir; + ASSERT_TRUE(dest_dir.CreateUniqueTempDir()); + + operation()->Copy(src_file, dest_dir.path()); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(kFileOperationSucceeded, mock_dispatcher_->status()); + EXPECT_EQ(request_id_, mock_dispatcher_->request_id()); + + FilePath src_filename(src_file.BaseName()); + EXPECT_TRUE(FileExists(dest_dir.path().Append(src_filename))); +} + +TEST_F(FileSystemOperationTest, TestCreateFileFailure) { + // Already existing file and exclusive true. + ScopedTempDir dir; + ASSERT_TRUE(dir.CreateUniqueTempDir()); + FilePath file; + + file_util::CreateTemporaryFileInDir(dir.path(), &file); + operation()->CreateFile(file, true); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(base::PLATFORM_FILE_ERROR_EXISTS, mock_dispatcher_->status()); + EXPECT_EQ(request_id_, mock_dispatcher_->request_id()); +} + +TEST_F(FileSystemOperationTest, TestCreateFileSuccessFileExists) { + // Already existing file and exclusive false. + ScopedTempDir dir; + ASSERT_TRUE(dir.CreateUniqueTempDir()); + FilePath file; + file_util::CreateTemporaryFileInDir(dir.path(), &file); + + operation()->CreateFile(file, false); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(kFileOperationSucceeded, mock_dispatcher_->status()); + EXPECT_TRUE(FileExists(file)); + EXPECT_EQ(request_id_, mock_dispatcher_->request_id()); +} + +TEST_F(FileSystemOperationTest, TestCreateFileSuccessExclusive) { + // File doesn't exist but exclusive is true. + ScopedTempDir dir; + ASSERT_TRUE(dir.CreateUniqueTempDir()); + FilePath file = dir.path().Append(FILE_PATH_LITERAL("FileDoesntExist")); + operation()->CreateFile(file, true); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(kFileOperationSucceeded, mock_dispatcher_->status()); + EXPECT_TRUE(FileExists(file)); + EXPECT_EQ(request_id_, mock_dispatcher_->request_id()); +} + +TEST_F(FileSystemOperationTest, TestCreateFileSuccessFileDoesntExist) { + // Non existing file. + ScopedTempDir dir; + ASSERT_TRUE(dir.CreateUniqueTempDir()); + FilePath file = dir.path().Append(FILE_PATH_LITERAL("FileDoesntExist")); + operation()->CreateFile(file, false); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(kFileOperationSucceeded, mock_dispatcher_->status()); + EXPECT_EQ(request_id_, mock_dispatcher_->request_id()); +} + +TEST_F(FileSystemOperationTest, + TestCreateDirFailureDestParentDoesntExist) { + // Dest. parent path does not exist. + FilePath nonexisting(base_.path().Append( + FILE_PATH_LITERAL("DirDoesntExist"))); + file_util::EnsureEndsWithSeparator(&nonexisting); + FilePath nonexisting_file = nonexisting.Append( + FILE_PATH_LITERAL("FileDoesntExist")); + operation()->CreateDirectory(nonexisting_file, false, false); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, mock_dispatcher_->status()); + EXPECT_EQ(request_id_, mock_dispatcher_->request_id()); +} + +TEST_F(FileSystemOperationTest, TestCreateDirFailureDirExists) { + // Exclusive and dir existing at path. + operation()->CreateDirectory(base_.path(), true, false); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(base::PLATFORM_FILE_ERROR_EXISTS, mock_dispatcher_->status()); + EXPECT_EQ(request_id_, mock_dispatcher_->request_id()); +} + +TEST_F(FileSystemOperationTest, TestCreateDirFailureFileExists) { + // Exclusive true and file existing at path. + ScopedTempDir dir; + ASSERT_TRUE(dir.CreateUniqueTempDir()); + FilePath file; + file_util::CreateTemporaryFileInDir(dir.path(), &file); + operation()->CreateDirectory(file, true, false); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(base::PLATFORM_FILE_ERROR_EXISTS, mock_dispatcher_->status()); + EXPECT_EQ(request_id_, mock_dispatcher_->request_id()); +} + +TEST_F(FileSystemOperationTest, TestCreateDirSuccess) { + // Dir exists and exclusive is false. + ScopedTempDir dir; + ASSERT_TRUE(dir.CreateUniqueTempDir()); + operation()->CreateDirectory(dir.path(), false, false); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(kFileOperationSucceeded, mock_dispatcher_->status()); + EXPECT_EQ(request_id_, mock_dispatcher_->request_id()); + + // Dir doesn't exist. + FilePath nonexisting_dir_path(FILE_PATH_LITERAL("nonexistingdir")); + operation()->CreateDirectory(nonexisting_dir_path, false, false); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(kFileOperationSucceeded, mock_dispatcher_->status()); + EXPECT_TRUE(file_util::DirectoryExists(nonexisting_dir_path)); + EXPECT_EQ(request_id_, mock_dispatcher_->request_id()); +} + +TEST_F(FileSystemOperationTest, TestCreateDirSuccessExclusive) { + // Dir doesn't exist. + ScopedTempDir dir; + ASSERT_TRUE(dir.CreateUniqueTempDir()); + FilePath nonexisting_dir_path(dir.path().Append( + FILE_PATH_LITERAL("nonexistingdir"))); + + operation()->CreateDirectory(nonexisting_dir_path, true, false); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(kFileOperationSucceeded, mock_dispatcher_->status()); + EXPECT_TRUE(file_util::DirectoryExists(nonexisting_dir_path)); + EXPECT_EQ(request_id_, mock_dispatcher_->request_id()); +} + +TEST_F(FileSystemOperationTest, TestExistsAndMetadataFailure) { + FilePath nonexisting_dir_path(base_.path().Append( + FILE_PATH_LITERAL("nonexistingdir"))); + operation()->GetMetadata(nonexisting_dir_path); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, mock_dispatcher_->status()); + + operation()->FileExists(nonexisting_dir_path); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, mock_dispatcher_->status()); + EXPECT_EQ(request_id_, mock_dispatcher_->request_id()); + + file_util::EnsureEndsWithSeparator(&nonexisting_dir_path); + operation()->DirectoryExists(nonexisting_dir_path); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, mock_dispatcher_->status()); + EXPECT_EQ(request_id_, mock_dispatcher_->request_id()); +} + +TEST_F(FileSystemOperationTest, TestExistsAndMetadataSuccess) { + ScopedTempDir dir; + ASSERT_TRUE(dir.CreateUniqueTempDir()); + + operation()->DirectoryExists(dir.path()); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(kFileOperationSucceeded, mock_dispatcher_->status()); + EXPECT_EQ(request_id_, mock_dispatcher_->request_id()); + + operation()->GetMetadata(dir.path()); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(kFileOperationSucceeded, mock_dispatcher_->status()); + EXPECT_TRUE(mock_dispatcher_->info().is_directory); + EXPECT_EQ(request_id_, mock_dispatcher_->request_id()); + + FilePath file; + file_util::CreateTemporaryFileInDir(dir.path(), &file); + operation()->FileExists(file); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(kFileOperationSucceeded, mock_dispatcher_->status()); + EXPECT_EQ(request_id_, mock_dispatcher_->request_id()); + + operation()->GetMetadata(file); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(kFileOperationSucceeded, mock_dispatcher_->status()); + EXPECT_FALSE(mock_dispatcher_->info().is_directory); + EXPECT_EQ(request_id_, mock_dispatcher_->request_id()); +} + +TEST_F(FileSystemOperationTest, TestReadDirFailure) { + // Path doesn't exists + FilePath nonexisting_dir_path(base_.path().Append( + FILE_PATH_LITERAL("NonExistingDir"))); + file_util::EnsureEndsWithSeparator(&nonexisting_dir_path); + operation()->ReadDirectory(nonexisting_dir_path); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, mock_dispatcher_->status()); + EXPECT_EQ(request_id_, mock_dispatcher_->request_id()); + + // File exists. + ScopedTempDir dir; + ASSERT_TRUE(dir.CreateUniqueTempDir()); + FilePath file; + file_util::CreateTemporaryFileInDir(dir.path(), &file); + operation()->ReadDirectory(file); + MessageLoop::current()->RunAllPending(); + // TODO(kkanetkar) crbug.com/54309 to change the error code. + EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, mock_dispatcher_->status()); + EXPECT_EQ(request_id_, mock_dispatcher_->request_id()); +} + +TEST_F(FileSystemOperationTest, TestReadDirSuccess) { + // parent_dir + // | | + // child_dir child_file + // Verify reading parent_dir. + ScopedTempDir parent_dir; + ASSERT_TRUE(parent_dir.CreateUniqueTempDir()); + FilePath child_file; + file_util::CreateTemporaryFileInDir(parent_dir.path(), &child_file); + FilePath child_dir; + ASSERT_TRUE(file_util::CreateTemporaryDirInDir( + parent_dir.path(), FILE_PATH_LITERAL("child_dir"), &child_dir)); + + operation()->ReadDirectory(parent_dir.path()); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(kFileOperationStatusNotSet, mock_dispatcher_->status()); + EXPECT_EQ(2u, mock_dispatcher_->entries().size()); + EXPECT_EQ(request_id_, mock_dispatcher_->request_id()); + + for (size_t i = 0; i < mock_dispatcher_->entries().size(); ++i) { + if (mock_dispatcher_->entries()[i].is_directory) { + EXPECT_EQ(child_dir.BaseName().value(), + mock_dispatcher_->entries()[i].name); + } else { + EXPECT_EQ(child_file.BaseName().value(), + mock_dispatcher_->entries()[i].name); + } + } +} + +TEST_F(FileSystemOperationTest, TestRemoveFailure) { + // Path doesn't exist. + FilePath nonexisting(base_.path().Append( + FILE_PATH_LITERAL("NonExistingDir"))); + file_util::EnsureEndsWithSeparator(&nonexisting); + + operation()->Remove(nonexisting); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, mock_dispatcher_->status()); + EXPECT_EQ(request_id_, mock_dispatcher_->request_id()); + + // By spec recursive is always false. Non-empty dir should fail. + // parent_dir + // | | + // child_dir child_file + // Verify deleting parent_dir. + ScopedTempDir parent_dir; + ASSERT_TRUE(parent_dir.CreateUniqueTempDir()); + FilePath child_file; + file_util::CreateTemporaryFileInDir(parent_dir.path(), &child_file); + FilePath child_dir; + ASSERT_TRUE(file_util::CreateTemporaryDirInDir( + parent_dir.path(), FILE_PATH_LITERAL("child_dir"), &child_dir)); + + operation()->Remove(parent_dir.path()); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(base::PLATFORM_FILE_ERROR_INVALID_OPERATION, + mock_dispatcher_->status()); + EXPECT_EQ(request_id_, mock_dispatcher_->request_id()); +} + +TEST_F(FileSystemOperationTest, TestRemoveSuccess) { + ScopedTempDir empty_dir; + ASSERT_TRUE(empty_dir.CreateUniqueTempDir()); + EXPECT_TRUE(file_util::DirectoryExists(empty_dir.path())); + + operation()->Remove(empty_dir.path()); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(kFileOperationSucceeded, mock_dispatcher_->status()); + EXPECT_FALSE(file_util::DirectoryExists(empty_dir.path())); + EXPECT_EQ(request_id_, mock_dispatcher_->request_id()); +} diff --git a/webkit/fileapi/webkit_fileapi.gypi b/webkit/fileapi/webkit_fileapi.gypi index cce29cc..37c75cb 100644 --- a/webkit/fileapi/webkit_fileapi.gypi +++ b/webkit/fileapi/webkit_fileapi.gypi @@ -14,9 +14,9 @@ '<(DEPTH)/net/net.gyp:net', ], 'sources': [ + 'file_system_callback_dispatcher.h', 'file_system_operation.cc', 'file_system_operation.h', - 'file_system_operation_client.h', ], 'conditions': [ ['inside_chromium_build==0', { diff --git a/webkit/tools/test_shell/simple_file_system.cc b/webkit/tools/test_shell/simple_file_system.cc index a5524db..0b76758 100644 --- a/webkit/tools/test_shell/simple_file_system.cc +++ b/webkit/tools/test_shell/simple_file_system.cc @@ -10,23 +10,101 @@ #include "third_party/WebKit/WebKit/chromium/public/WebFileInfo.h" #include "third_party/WebKit/WebKit/chromium/public/WebFileSystemEntry.h" #include "third_party/WebKit/WebKit/chromium/public/WebVector.h" +#include "webkit/fileapi/file_system_callback_dispatcher.h" #include "webkit/glue/webkit_glue.h" +using WebKit::WebFileInfo; using WebKit::WebFileSystemCallbacks; +using WebKit::WebFileSystemEntry; using WebKit::WebString; +using WebKit::WebVector; + +namespace { + +WebKit::WebFileError PlatformFileErrorToWebFileError( + base::PlatformFileError error_code) { + switch (error_code) { + case base::PLATFORM_FILE_ERROR_NOT_FOUND: + return WebKit::WebFileErrorNotFound; + case base::PLATFORM_FILE_ERROR_INVALID_OPERATION: + case base::PLATFORM_FILE_ERROR_EXISTS: + case base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY: + return WebKit::WebFileErrorInvalidModification; + case base::PLATFORM_FILE_ERROR_ACCESS_DENIED: + return WebKit::WebFileErrorNoModificationAllowed; + case base::PLATFORM_FILE_ERROR_FAILED: + return WebKit::WebFileErrorInvalidState; + case base::PLATFORM_FILE_ERROR_ABORT: + return WebKit::WebFileErrorAbort; + default: + return WebKit::WebFileErrorInvalidModification; + } +} + +class TestShellFileSystemCallbackDispatcher + : public fileapi::FileSystemCallbackDispatcher { + public: + TestShellFileSystemCallbackDispatcher( + SimpleFileSystem* file_system, + WebFileSystemCallbacks* callbacks) + : file_system_(file_system), + callbacks_(callbacks), + request_id_(-1) { + } + + void set_request_id(int request_id) { request_id_ = request_id; } + + virtual void DidSucceed() { + callbacks_->didSucceed(); + file_system_->RemoveCompletedOperation(request_id_); + } + + virtual void DidReadMetadata(const base::PlatformFileInfo& info) { + WebFileInfo web_file_info; + web_file_info.modificationTime = info.last_modified.ToDoubleT(); + callbacks_->didReadMetadata(web_file_info); + file_system_->RemoveCompletedOperation(request_id_); + } + + virtual void DidReadDirectory( + const std::vector<base::file_util_proxy::Entry>& entries, + bool has_more) { + std::vector<WebFileSystemEntry> web_entries_vector; + for (std::vector<base::file_util_proxy::Entry>::const_iterator it = + entries.begin(); it != entries.end(); ++it) { + WebFileSystemEntry entry; + entry.name = webkit_glue::FilePathStringToWebString(it->name); + entry.isDirectory = it->is_directory; + web_entries_vector.push_back(entry); + } + WebVector<WebKit::WebFileSystemEntry> web_entries = + web_entries_vector; + callbacks_->didReadDirectory(web_entries, has_more); + file_system_->RemoveCompletedOperation(request_id_); + } + + virtual void DidOpenFileSystem(const string16&, const FilePath&) { + NOTREACHED(); + } -TestShellFileSystemOperation::TestShellFileSystemOperation( - fileapi::FileSystemOperationClient* client, - scoped_refptr<base::MessageLoopProxy> proxy, - WebFileSystemCallbacks* callbacks) - : fileapi::FileSystemOperation(client, proxy), callbacks_(callbacks) { } + virtual void DidFail(base::PlatformFileError error_code) { + callbacks_->didFail(PlatformFileErrorToWebFileError(error_code)); + file_system_->RemoveCompletedOperation(request_id_); + } + + private: + SimpleFileSystem* file_system_; + WebFileSystemCallbacks* callbacks_; + int request_id_; +}; + +} // namespace SimpleFileSystem::~SimpleFileSystem() { // Drop all the operations. for (OperationsMap::const_iterator iter(&operations_); - !iter.IsAtEnd(); iter.Advance()) { + !iter.IsAtEnd(); iter.Advance()) operations_.Remove(iter.GetCurrentKey()); - } } void SimpleFileSystem::move( @@ -72,7 +150,7 @@ void SimpleFileSystem::createDirectory( const WebString& path, bool exclusive, WebFileSystemCallbacks* callbacks) { FilePath filepath(webkit_glue::WebStringToFilePath(path)); - GetNewOperation(callbacks)->CreateDirectory(filepath, exclusive); + GetNewOperation(callbacks)->CreateDirectory(filepath, exclusive, false); } void SimpleFileSystem::fileExists( @@ -96,65 +174,18 @@ void SimpleFileSystem::readDirectory( GetNewOperation(callbacks)->ReadDirectory(filepath); } -void SimpleFileSystem::DidFail(WebKit::WebFileError status, - fileapi::FileSystemOperation* operation) { - WebFileSystemCallbacks* callbacks = - static_cast<TestShellFileSystemOperation*>(operation)->callbacks(); - callbacks->didFail(status); - RemoveOperation(operation); -} - -void SimpleFileSystem::DidSucceed(fileapi::FileSystemOperation* operation) { - WebFileSystemCallbacks* callbacks = - static_cast<TestShellFileSystemOperation*>(operation)->callbacks(); - callbacks->didSucceed(); - RemoveOperation(operation); -} - -void SimpleFileSystem::DidReadMetadata( - const base::PlatformFileInfo& info, - fileapi::FileSystemOperation* operation) { - WebFileSystemCallbacks* callbacks = - static_cast<TestShellFileSystemOperation*>(operation)->callbacks(); - WebKit::WebFileInfo web_file_info; - web_file_info.modificationTime = info.last_modified.ToDoubleT(); - callbacks->didReadMetadata(web_file_info); - RemoveOperation(operation); -} - -void SimpleFileSystem::DidReadDirectory( - const std::vector<base::file_util_proxy::Entry>& entries, - bool has_more, fileapi::FileSystemOperation* operation) { - WebFileSystemCallbacks* callbacks = - static_cast<TestShellFileSystemOperation*>(operation)->callbacks(); - std::vector<WebKit::WebFileSystemEntry> web_entries_vector; - for (std::vector<base::file_util_proxy::Entry>::const_iterator it = - entries.begin(); it != entries.end(); ++it) { - WebKit::WebFileSystemEntry entry; - entry.name = webkit_glue::FilePathStringToWebString(it->name); - entry.isDirectory = it->is_directory; - web_entries_vector.push_back(entry); - } - WebKit::WebVector<WebKit::WebFileSystemEntry> web_entries = - web_entries_vector; - callbacks->didReadDirectory(web_entries, false); - RemoveOperation(operation); -} - -TestShellFileSystemOperation* SimpleFileSystem::GetNewOperation( +fileapi::FileSystemOperation* SimpleFileSystem::GetNewOperation( WebFileSystemCallbacks* callbacks) { - scoped_ptr<TestShellFileSystemOperation> operation( - new TestShellFileSystemOperation( - this, - base::MessageLoopProxy::CreateForCurrentThread(), callbacks)); - int32 request_id = operations_.Add(operation.get()); - operation->set_request_id(request_id); - return operation.release(); + // This pointer will be owned by |operation|. + TestShellFileSystemCallbackDispatcher* dispatcher = + new TestShellFileSystemCallbackDispatcher(this, callbacks); + fileapi::FileSystemOperation* operation = new fileapi::FileSystemOperation( + dispatcher, base::MessageLoopProxy::CreateForCurrentThread()); + int32 request_id = operations_.Add(operation); + dispatcher->set_request_id(request_id); + return operation; } -void SimpleFileSystem::RemoveOperation( - fileapi::FileSystemOperation* operation) { - int request_id = static_cast<TestShellFileSystemOperation*>( - operation)->request_id(); +void SimpleFileSystem::RemoveCompletedOperation(int request_id) { operations_.Remove(request_id); } diff --git a/webkit/tools/test_shell/simple_file_system.h b/webkit/tools/test_shell/simple_file_system.h index 947f804..db13d9c 100644 --- a/webkit/tools/test_shell/simple_file_system.h +++ b/webkit/tools/test_shell/simple_file_system.h @@ -8,84 +8,48 @@ #include <vector> #include "base/file_util_proxy.h" #include "base/id_map.h" -#include "base/message_loop_proxy.h" -#include "base/platform_file.h" #include "third_party/WebKit/WebKit/chromium/public/WebFileSystem.h" #include "third_party/WebKit/WebKit/chromium/public/WebFileSystemCallbacks.h" #include "webkit/fileapi/file_system_operation.h" -#include "webkit/fileapi/file_system_operation_client.h" -class TestShellFileSystemOperation : public fileapi::FileSystemOperation { - public: - TestShellFileSystemOperation( - fileapi::FileSystemOperationClient* client, - scoped_refptr<base::MessageLoopProxy> proxy, - WebKit::WebFileSystemCallbacks* callbacks); - - WebKit::WebFileSystemCallbacks* callbacks() { return callbacks_; } - - void set_request_id(int request_id) { request_id_ = request_id; } - int request_id() { return request_id_; } - - private: - // Not owned. - WebKit::WebFileSystemCallbacks* callbacks_; - - // Just for IDMap of operations. - int request_id_; - - DISALLOW_COPY_AND_ASSIGN(TestShellFileSystemOperation); -}; - -class SimpleFileSystem - : public WebKit::WebFileSystem, - public fileapi::FileSystemOperationClient { +class SimpleFileSystem : public WebKit::WebFileSystem { public: SimpleFileSystem() {} virtual ~SimpleFileSystem(); + void RemoveCompletedOperation(int request_id); + // WebKit::WebFileSystem methods. virtual void move(const WebKit::WebString& src_path, - const WebKit::WebString& dest_path, - WebKit::WebFileSystemCallbacks* callbacks); + const WebKit::WebString& dest_path, + WebKit::WebFileSystemCallbacks* callbacks); virtual void copy(const WebKit::WebString& src_path, - const WebKit::WebString& dest_path, - WebKit::WebFileSystemCallbacks* callbacks); + const WebKit::WebString& dest_path, + WebKit::WebFileSystemCallbacks* callbacks); virtual void remove(const WebKit::WebString& path, - WebKit::WebFileSystemCallbacks* callbacks); + WebKit::WebFileSystemCallbacks* callbacks); virtual void readMetadata(const WebKit::WebString& path, - WebKit::WebFileSystemCallbacks* callbacks); - virtual void createFile(const WebKit::WebString& path, bool exclusive, - WebKit::WebFileSystemCallbacks* callbacks); - virtual void createDirectory(const WebKit::WebString& path, bool exclusive, - WebKit::WebFileSystemCallbacks* callbacks); + WebKit::WebFileSystemCallbacks* callbacks); + virtual void createFile(const WebKit::WebString& path, + bool exclusive, + WebKit::WebFileSystemCallbacks* callbacks); + virtual void createDirectory(const WebKit::WebString& path, + bool exclusive, + WebKit::WebFileSystemCallbacks* callbacks); virtual void fileExists(const WebKit::WebString& path, - WebKit::WebFileSystemCallbacks* callbacks); + WebKit::WebFileSystemCallbacks* callbacks); virtual void directoryExists(const WebKit::WebString& path, - WebKit::WebFileSystemCallbacks* callbacks); + WebKit::WebFileSystemCallbacks* callbacks); virtual void readDirectory(const WebKit::WebString& path, - WebKit::WebFileSystemCallbacks* callbacks); - - // FileSystemOperationClient methods. - virtual void DidFail(WebKit::WebFileError status, - fileapi::FileSystemOperation* operation); - virtual void DidSucceed(fileapi::FileSystemOperation* operation); - virtual void DidReadMetadata( - const base::PlatformFileInfo& info, - fileapi::FileSystemOperation* operation); - virtual void DidReadDirectory( - const std::vector<base::file_util_proxy::Entry>& entries, - bool has_more, fileapi::FileSystemOperation* operation); + WebKit::WebFileSystemCallbacks* callbacks); private: // Helpers. - TestShellFileSystemOperation* GetNewOperation( + fileapi::FileSystemOperation* GetNewOperation( WebKit::WebFileSystemCallbacks* callbacks); - void RemoveOperation(fileapi::FileSystemOperation* operation); - // Keeps ongoing file system operations. - typedef IDMap<TestShellFileSystemOperation, IDMapOwnPointer> OperationsMap; + typedef IDMap<fileapi::FileSystemOperation, IDMapOwnPointer> OperationsMap; OperationsMap operations_; DISALLOW_COPY_AND_ASSIGN(SimpleFileSystem); diff --git a/webkit/tools/test_shell/test_shell.gypi b/webkit/tools/test_shell/test_shell.gypi index 490c134..3f23600 100644 --- a/webkit/tools/test_shell/test_shell.gypi +++ b/webkit/tools/test_shell/test_shell.gypi @@ -374,6 +374,7 @@ '../../database/database_tracker_unittest.cc', '../../database/database_util_unittest.cc', '../../database/quota_table_unittest.cc', + '../../fileapi/file_system_operation_unittest.cc', '../../glue/bookmarklet_unittest.cc', '../../glue/context_menu_unittest.cc', '../../glue/cpp_bound_class_unittest.cc', |