diff options
author | dumi@chromium.org <dumi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-22 20:41:20 +0000 |
---|---|---|
committer | dumi@chromium.org <dumi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-22 20:41:20 +0000 |
commit | da34ae09d568bf23b586b49f9ee13d730a3d71c9 (patch) | |
tree | 51177ece300917952d5a1d3c1a32ece5fe70aa0e | |
parent | 35eea2e6ac7a392b22efe089c7c2675be4142237 (diff) | |
download | chromium_src-da34ae09d568bf23b586b49f9ee13d730a3d71c9.zip chromium_src-da34ae09d568bf23b586b49f9ee13d730a3d71c9.tar.gz chromium_src-da34ae09d568bf23b586b49f9ee13d730a3d71c9.tar.bz2 |
Refactor the DB code to make it accessible from test_shell.
BUG=21442
TEST=none
Review URL: http://codereview.chromium.org/203074
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@26855 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/DEPS | 1 | ||||
-rw-r--r-- | chrome/browser/renderer_host/database_dispatcher_host.cc | 236 | ||||
-rw-r--r-- | chrome/chrome.gyp | 1 | ||||
-rw-r--r-- | webkit/DEPS | 1 | ||||
-rw-r--r-- | webkit/database/vfs_backend.cc | 210 | ||||
-rw-r--r-- | webkit/database/vfs_backend.h | 33 | ||||
-rw-r--r-- | webkit/tools/test_shell/layout_test_controller.cc | 11 | ||||
-rw-r--r-- | webkit/tools/test_shell/layout_test_controller.h | 3 | ||||
-rw-r--r-- | webkit/tools/test_shell/simple_database_system.cc | 107 | ||||
-rw-r--r-- | webkit/tools/test_shell/simple_database_system.h | 38 | ||||
-rw-r--r-- | webkit/tools/test_shell/test_shell.cc | 1 | ||||
-rw-r--r-- | webkit/tools/test_shell/test_shell.gyp | 3 | ||||
-rw-r--r-- | webkit/tools/test_shell/test_shell_webkit_init.h | 40 | ||||
-rw-r--r-- | webkit/webkit.gyp | 13 |
14 files changed, 482 insertions, 216 deletions
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS index 1137607..e550294 100644 --- a/chrome/browser/DEPS +++ b/chrome/browser/DEPS @@ -8,6 +8,7 @@ include_rules = [ "+grit", # For generated headers "+sandbox/src", "+skia/include", + "+webkit/database", "+webkit/default_plugin", "+webkit/glue", # Defines some types that are marshalled over IPC. "+xib_localizers", # For generated mac localization helpers diff --git a/chrome/browser/renderer_host/database_dispatcher_host.cc b/chrome/browser/renderer_host/database_dispatcher_host.cc index c0ab282..8623a87 100644 --- a/chrome/browser/renderer_host/database_dispatcher_host.cc +++ b/chrome/browser/renderer_host/database_dispatcher_host.cc @@ -14,39 +14,39 @@ #include "third_party/sqlite/preprocessed/sqlite3.h" #endif -#include "base/file_path.h" -#include "base/file_util.h" #include "base/message_loop.h" #include "base/platform_file.h" #include "base/process.h" -#include "base/scoped_ptr.h" #include "base/task.h" #include "base/thread.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/renderer_host/resource_message_filter.h" #include "chrome/common/render_messages.h" #include "ipc/ipc_message.h" +#include "webkit/database/vfs_backend.h" #if defined(OS_POSIX) #include "base/file_descriptor_posix.h" #endif -const int kNumDeleteRetries = 5; +using webkit_database::VfsBackend; + +const int kNumDeleteRetries = 3; const int kDelayDeleteRetryMs = 100; namespace { struct OpenFileParams { - FilePath db_dir; // directory where all DB files are stored - FilePath file_name; // DB file - int desired_flags; // flags to be used to open the file - base::ProcessHandle handle; // the handle of the renderer process + FilePath db_dir; + FilePath file_name; + int desired_flags; + base::ProcessHandle handle; }; struct DeleteFileParams { - FilePath db_dir; // directory where all DB files are stored - FilePath file_name; // DB file - bool sync_dir; // sync DB directory after the file is deleted? + FilePath db_dir; + FilePath file_name; + bool sync_dir; }; // Scheduled by the file Thread on the IO thread. @@ -62,71 +62,6 @@ static void SendMessage(ResourceMessageFilter* sender, sender->Release(); } -// Make sure the flags used to open a DB file are consistent. -static bool OpenFileFlagsAreConsistent(const OpenFileParams& params) { - // Is this a request for a temp file? - // We should be able to delete temp files when they're closed - // and create them as needed - if ((params.file_name == params.db_dir) && - (!(params.desired_flags & SQLITE_OPEN_DELETEONCLOSE) || - !(params.desired_flags & SQLITE_OPEN_CREATE))) { - return false; - } - - const int file_type = params.desired_flags & 0x00007F00; - const bool is_exclusive = - (params.desired_flags & SQLITE_OPEN_EXCLUSIVE) != 0; - const bool is_delete = - (params.desired_flags & SQLITE_OPEN_DELETEONCLOSE) != 0; - const bool is_create = - (params.desired_flags & SQLITE_OPEN_CREATE) != 0; - const bool is_read_only = - (params.desired_flags & SQLITE_OPEN_READONLY) != 0; - const bool is_read_write = - (params.desired_flags & SQLITE_OPEN_READWRITE) != 0; - - // All files should be opened either read-write or read-only. - if (!(is_read_only ^ is_read_write)) { - return false; - } - - // If a new file is created, it must also be writtable. - if (is_create && !is_read_write) { - return false; - } - - // We must be able to create a new file, if exclusive access is desired. - if (is_exclusive && !is_create) { - return false; - } - - // We cannot delete the files that we expect to already exist. - if (is_delete && !is_create) { - return false; - } - - // The main DB, main journal and master journal cannot be auto-deleted. - if (((file_type == SQLITE_OPEN_MAIN_DB) || - (file_type == SQLITE_OPEN_MAIN_JOURNAL) || - (file_type == SQLITE_OPEN_MASTER_JOURNAL)) && - is_delete) { - return false; - } - - // Make sure we're opening the DB directory or that a file type is set. - if ((file_type != SQLITE_OPEN_MAIN_DB) && - (file_type != SQLITE_OPEN_TEMP_DB) && - (file_type != SQLITE_OPEN_MAIN_JOURNAL) && - (file_type != SQLITE_OPEN_TEMP_JOURNAL) && - (file_type != SQLITE_OPEN_SUBJOURNAL) && - (file_type != SQLITE_OPEN_MASTER_JOURNAL) && - (file_type != SQLITE_OPEN_TRANSIENT_DB)) { - return false; - } - - return true; -} - // Scheduled by the IO thread on the file thread. // Opens the given database file, then schedules // a task on the IO thread's message loop to send an IPC back to @@ -136,85 +71,10 @@ static void DatabaseOpenFile(MessageLoop* io_thread_message_loop, int32 message_id, ResourceMessageFilter* sender) { base::PlatformFile target_handle = base::kInvalidPlatformFileValue; -#if defined(OS_POSIX) base::PlatformFile target_dir_handle = base::kInvalidPlatformFileValue; -#endif - - // Verify the flags for consistency and create the database - // directory if it doesn't exist. - if (OpenFileFlagsAreConsistent(params) && - file_util::CreateDirectory(params.db_dir)) { - int flags = 0; - flags |= base::PLATFORM_FILE_READ; - if (params.desired_flags & SQLITE_OPEN_READWRITE) { - flags |= base::PLATFORM_FILE_WRITE; - } - - if (!(params.desired_flags & SQLITE_OPEN_MAIN_DB)) { - flags |= base::PLATFORM_FILE_EXCLUSIVE_READ | - base::PLATFORM_FILE_EXCLUSIVE_WRITE; - } - - if (params.desired_flags & SQLITE_OPEN_CREATE) { - flags |= base::PLATFORM_FILE_OPEN_ALWAYS; - } else { - flags |= base::PLATFORM_FILE_OPEN; - } - - if (params.desired_flags & SQLITE_OPEN_EXCLUSIVE) { - flags |= base::PLATFORM_FILE_EXCLUSIVE_READ | - base::PLATFORM_FILE_EXCLUSIVE_WRITE; - } - - if (params.desired_flags & SQLITE_OPEN_DELETEONCLOSE) { - flags |= base::PLATFORM_FILE_TEMPORARY | base::PLATFORM_FILE_HIDDEN | - base::PLATFORM_FILE_DELETE_ON_CLOSE; - } - - // If this is a request for a handle to a temp file, get a unique file name - FilePath file_name; - if (params.file_name == params.db_dir) { - if (!file_util::CreateTemporaryFileInDir(params.db_dir, &file_name)) { - file_name = FilePath(); - } - } else { - file_name = params.file_name; - } - - // Try to open/create the DB file. - base::PlatformFile file_handle = - (file_name.empty() ? base::kInvalidPlatformFileValue : - base::CreatePlatformFile(file_name.ToWStringHack(), flags, NULL)); - if (file_handle != base::kInvalidPlatformFileValue) { -#if defined(OS_WIN) - // Duplicate the file handle. - if (!DuplicateHandle(GetCurrentProcess(), file_handle, - params.handle, &target_handle, 0, false, - DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { - // file_handle is closed whether or not DuplicateHandle succeeds. - target_handle = INVALID_HANDLE_VALUE; - } -#elif defined(OS_POSIX) - target_handle = file_handle; - - int file_type = params.desired_flags & 0x00007F00; - bool creating_new_file = (params.desired_flags & SQLITE_OPEN_CREATE); - if (creating_new_file && ((file_type == SQLITE_OPEN_MASTER_JOURNAL) || - (file_type == SQLITE_OPEN_MAIN_JOURNAL))) { - // We return a handle to the containing directory because on POSIX - // systems the VFS might want to fsync it after changing a file. - // By returning it here, we avoid an extra IPC call. - target_dir_handle = base::CreatePlatformFile( - params.db_dir.ToWStringHack(), - base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ, NULL); - if (target_dir_handle == base::kInvalidPlatformFileValue) { - base::ClosePlatformFile(target_handle); - target_handle = base::kInvalidPlatformFileValue; - } - } -#endif - } - } + VfsBackend::OpenFile( + params.file_name, params.db_dir, params.desired_flags, + params.handle, &target_handle, &target_dir_handle); ViewMsg_DatabaseOpenFileResponse_Params response_params; #if defined(OS_WIN) @@ -223,7 +83,6 @@ static void DatabaseOpenFile(MessageLoop* io_thread_message_loop, response_params.file_handle = base::FileDescriptor(target_handle, true); response_params.dir_handle = base::FileDescriptor(target_dir_handle, true); #endif - io_thread_message_loop->PostTask(FROM_HERE, NewRunnableFunction(SendMessage, sender, new ViewMsg_DatabaseOpenFileResponse(message_id, response_params))); @@ -249,17 +108,10 @@ static void DatabaseDeleteFile( return; } - // If the file does not exist, we're done. - if (!file_util::PathExists(params.file_name)) { - io_thread_message_loop->PostTask(FROM_HERE, - NewRunnableFunction(SendMessage, sender, - new ViewMsg_DatabaseDeleteFileResponse(message_id, SQLITE_OK))); - return; - } - - - // If the file could not be deleted, try again. - if (!file_util::Delete(params.file_name, false)) { + int error_code = VfsBackend::DeleteFile( + params.file_name, params.db_dir, params.sync_dir); + if (error_code == SQLITE_IOERR_DELETE) { + // If the file could not be deleted, try again. MessageLoop::current()->PostDelayedTask(FROM_HERE, NewRunnableFunction(DatabaseDeleteFile, io_thread_message_loop, params, message_id, reschedule_count - 1, sender), @@ -267,24 +119,6 @@ static void DatabaseDeleteFile( return; } - // File existed and it was successfully deleted - int error_code = SQLITE_OK; -#if defined(OS_POSIX) - // sync the DB directory if needed - if (params.sync_dir) { - base::PlatformFile dir_fd = base::CreatePlatformFile( - params.db_dir.ToWStringHack(), base::PLATFORM_FILE_READ, NULL); - if (dir_fd == base::kInvalidPlatformFileValue) { - error_code = SQLITE_CANTOPEN; - } else { - if (fsync(dir_fd)) { - error_code = SQLITE_IOERR_DIR_FSYNC; - } - base::ClosePlatformFile(dir_fd); - } - } -#endif - io_thread_message_loop->PostTask(FROM_HERE, NewRunnableFunction(SendMessage, sender, new ViewMsg_DatabaseDeleteFileResponse(message_id, error_code))); @@ -299,21 +133,7 @@ static void DatabaseGetFileAttributes( const FilePath& file_name, int32 message_id, ResourceMessageFilter* sender) { -#if defined(OS_WIN) - uint32 attributes = GetFileAttributes(file_name.value().c_str()); -#elif defined(OS_POSIX) - uint32 attributes = 0; - if (!access(file_name.value().c_str(), R_OK)) { - attributes |= static_cast<uint32>(R_OK); - } - if (!access(file_name.value().c_str(), W_OK)) { - attributes |= static_cast<uint32>(W_OK); - } - if (!attributes) { - attributes = -1; - } -#endif - + uint32 attributes = VfsBackend::GetFileAttributes(file_name); io_thread_message_loop->PostTask(FROM_HERE, NewRunnableFunction(SendMessage, sender, new ViewMsg_DatabaseGetFileAttributesResponse( @@ -329,11 +149,7 @@ static void DatabaseGetFileSize( const FilePath& file_name, int32 message_id, ResourceMessageFilter* sender) { - int64 size = 0; - if (!file_util::GetFileSize(file_name, &size)) { - size = 0; - } - + int64 size = VfsBackend::GetFileSize(file_name); io_thread_message_loop->PostTask(FROM_HERE, NewRunnableFunction(SendMessage, sender, new ViewMsg_DatabaseGetFileSizeResponse(message_id, size))); @@ -419,8 +235,11 @@ void DatabaseDispatcherHost::OnDatabaseOpenFile( return; } - OpenFileParams params = { GetDBDir(), db_file_name, desired_flags, - resource_message_filter_->handle() }; + OpenFileParams params; + params.db_dir = GetDBDir(); + params.file_name = db_file_name; + params.desired_flags = desired_flags; + params.handle = resource_message_filter_->handle(); resource_message_filter_->AddRef(); file_thread_message_loop_->PostTask(FROM_HERE, NewRunnableFunction(DatabaseOpenFile, MessageLoop::current(), @@ -436,7 +255,10 @@ void DatabaseDispatcherHost::OnDatabaseDeleteFile( return; } - DeleteFileParams params = { GetDBDir(), db_file_name, sync_dir }; + DeleteFileParams params; + params.db_dir = GetDBDir(); + params.file_name = db_file_name; + params.sync_dir = sync_dir; resource_message_filter_->AddRef(); file_thread_message_loop_->PostTask(FROM_HERE, NewRunnableFunction(DatabaseDeleteFile, MessageLoop::current(), diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index ef7a8b9..b5491cf 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -681,6 +681,7 @@ '../third_party/libxml/libxml.gyp:libxml', '../third_party/npapi/npapi.gyp:npapi', '../third_party/hunspell/hunspell.gyp:hunspell', + '../webkit/webkit.gyp:database', '../webkit/webkit.gyp:glue', ], 'include_dirs': [ diff --git a/webkit/DEPS b/webkit/DEPS index 74ee587..15f1b46 100644 --- a/webkit/DEPS +++ b/webkit/DEPS @@ -11,6 +11,7 @@ include_rules = [ # For bridge/c/c_utility.h in npruntime_util.cc "+bridge", "+grit", # For generated headers + "+third_party/sqlite", # TODO(brettw) - review these; move up if it's ok, or remove the dependency "+net/base", diff --git a/webkit/database/vfs_backend.cc b/webkit/database/vfs_backend.cc new file mode 100644 index 0000000..cc06215 --- /dev/null +++ b/webkit/database/vfs_backend.cc @@ -0,0 +1,210 @@ +// Copyright (c) 2009 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/database/vfs_backend.h" + +#if defined(USE_SYSTEM_SQLITE) +#include <sqlite3.h> +#else +#include "third_party/sqlite/preprocessed/sqlite3.h" +#endif + +#include "base/file_path.h" +#include "base/file_util.h" +#include "base/process.h" + +namespace webkit_database { + +bool VfsBackend::OpenFileFlagsAreConsistent( + const FilePath& file_name, const FilePath& db_dir, int desired_flags) { + // Is this a request for a temp file? + // We should be able to delete temp files when they're closed + // and create them as needed + if ((file_name == db_dir) && + (!(desired_flags & SQLITE_OPEN_DELETEONCLOSE) || + !(desired_flags & SQLITE_OPEN_CREATE))) { + return false; + } + + const int file_type = desired_flags & 0x00007F00; + const bool is_exclusive = (desired_flags & SQLITE_OPEN_EXCLUSIVE) != 0; + const bool is_delete = (desired_flags & SQLITE_OPEN_DELETEONCLOSE) != 0; + const bool is_create = (desired_flags & SQLITE_OPEN_CREATE) != 0; + const bool is_read_only = (desired_flags & SQLITE_OPEN_READONLY) != 0; + const bool is_read_write = (desired_flags & SQLITE_OPEN_READWRITE) != 0; + + // All files should be opened either read-write or read-only. + if (!(is_read_only ^ is_read_write)) { + return false; + } + + // If a new file is created, it must also be writtable. + if (is_create && !is_read_write) { + return false; + } + + // We must be able to create a new file, if exclusive access is desired. + if (is_exclusive && !is_create) { + return false; + } + + // We cannot delete the files that we expect to already exist. + if (is_delete && !is_create) { + return false; + } + + // The main DB, main journal and master journal cannot be auto-deleted. + if (((file_type == SQLITE_OPEN_MAIN_DB) || + (file_type == SQLITE_OPEN_MAIN_JOURNAL) || + (file_type == SQLITE_OPEN_MASTER_JOURNAL)) && + is_delete) { + return false; + } + + // Make sure we're opening the DB directory or that a file type is set. + if ((file_type != SQLITE_OPEN_MAIN_DB) && + (file_type != SQLITE_OPEN_TEMP_DB) && + (file_type != SQLITE_OPEN_MAIN_JOURNAL) && + (file_type != SQLITE_OPEN_TEMP_JOURNAL) && + (file_type != SQLITE_OPEN_SUBJOURNAL) && + (file_type != SQLITE_OPEN_MASTER_JOURNAL) && + (file_type != SQLITE_OPEN_TRANSIENT_DB)) { + return false; + } + + return true; +} + +void VfsBackend::OpenFile( + const FilePath& file_name, const FilePath& db_dir, int desired_flags, + base::ProcessHandle handle, base::PlatformFile* target_handle, + base::PlatformFile* target_dir_handle) { + // Verify the flags for consistency and create the database + // directory if it doesn't exist. + if (OpenFileFlagsAreConsistent(file_name, db_dir, desired_flags) && + file_util::CreateDirectory(db_dir)) { + int flags = 0; + flags |= base::PLATFORM_FILE_READ; + if (desired_flags & SQLITE_OPEN_READWRITE) { + flags |= base::PLATFORM_FILE_WRITE; + } + + if (!(desired_flags & SQLITE_OPEN_MAIN_DB)) { + flags |= base::PLATFORM_FILE_EXCLUSIVE_READ | + base::PLATFORM_FILE_EXCLUSIVE_WRITE; + } + + if (desired_flags & SQLITE_OPEN_CREATE) { + flags |= base::PLATFORM_FILE_OPEN_ALWAYS; + } else { + flags |= base::PLATFORM_FILE_OPEN; + } + + if (desired_flags & SQLITE_OPEN_EXCLUSIVE) { + flags |= base::PLATFORM_FILE_EXCLUSIVE_READ | + base::PLATFORM_FILE_EXCLUSIVE_WRITE; + } + + if (desired_flags & SQLITE_OPEN_DELETEONCLOSE) { + flags |= base::PLATFORM_FILE_TEMPORARY | base::PLATFORM_FILE_HIDDEN | + base::PLATFORM_FILE_DELETE_ON_CLOSE; + } + + // If this is a request for a handle to a temp file, get a unique file name + FilePath db_file_name; + if (file_name == db_dir) { + if (!file_util::CreateTemporaryFileInDir(db_dir, &db_file_name)) { + db_file_name = FilePath(); + } + } else { + db_file_name = file_name; + } + + // Try to open/create the DB file. + base::PlatformFile file_handle = + (db_file_name.empty() ? base::kInvalidPlatformFileValue : + base::CreatePlatformFile(db_file_name.ToWStringHack(), flags, NULL)); + if (file_handle != base::kInvalidPlatformFileValue) { +#if defined(OS_WIN) + // Duplicate the file handle. + if (!DuplicateHandle(GetCurrentProcess(), file_handle, + handle, target_handle, 0, false, + DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { + // file_handle is closed whether or not DuplicateHandle succeeds. + *target_handle = INVALID_HANDLE_VALUE; + } +#elif defined(OS_POSIX) + *target_handle = file_handle; + + int file_type = desired_flags & 0x00007F00; + bool creating_new_file = (desired_flags & SQLITE_OPEN_CREATE); + if (creating_new_file && ((file_type == SQLITE_OPEN_MASTER_JOURNAL) || + (file_type == SQLITE_OPEN_MAIN_JOURNAL))) { + // We return a handle to the containing directory because on POSIX + // systems the VFS might want to fsync it after changing a file. + // By returning it here, we avoid an extra IPC call. + *target_dir_handle = base::CreatePlatformFile( + db_dir.ToWStringHack(), + base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ, NULL); + if (*target_dir_handle == base::kInvalidPlatformFileValue) { + base::ClosePlatformFile(*target_handle); + *target_handle = base::kInvalidPlatformFileValue; + } + } +#endif + } + } +} + +int VfsBackend::DeleteFile( + const FilePath& file_name, const FilePath& db_dir, bool sync_dir) { + if (!file_util::PathExists(file_name)) { + return SQLITE_OK; + } + if (!file_util::Delete(file_name, false)) { + return SQLITE_IOERR_DELETE; + } + + int error_code = SQLITE_OK; +#if defined(OS_POSIX) + if (sync_dir) { + base::PlatformFile dir_fd = base::CreatePlatformFile( + db_dir.ToWStringHack(), base::PLATFORM_FILE_READ, NULL); + if (dir_fd == base::kInvalidPlatformFileValue) { + error_code = SQLITE_CANTOPEN; + } else { + if (fsync(dir_fd)) { + error_code = SQLITE_IOERR_DIR_FSYNC; + } + base::ClosePlatformFile(dir_fd); + } + } +#endif + return error_code; +} + +uint32 VfsBackend::GetFileAttributes(const FilePath& file_name) { +#if defined(OS_WIN) + uint32 attributes = ::GetFileAttributes(file_name.value().c_str()); +#elif defined(OS_POSIX) + uint32 attributes = 0; + if (!access(file_name.value().c_str(), R_OK)) { + attributes |= static_cast<uint32>(R_OK); + } + if (!access(file_name.value().c_str(), W_OK)) { + attributes |= static_cast<uint32>(W_OK); + } + if (!attributes) { + attributes = -1; + } +#endif + return attributes; +} + +int64 VfsBackend::GetFileSize(const FilePath& file_name) { + int64 size = 0; + return (file_util::GetFileSize(file_name, &size) ? size : 0); +} + +} // namespace database diff --git a/webkit/database/vfs_backend.h b/webkit/database/vfs_backend.h new file mode 100644 index 0000000..536ffd8 --- /dev/null +++ b/webkit/database/vfs_backend.h @@ -0,0 +1,33 @@ +// Copyright (c) 2009 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_DATABASE_VFS_BACKEND_H_ +#define WEBKIT_DATABASE_VFS_BACKEND_H_ + +#include "base/platform_file.h" +#include "base/process.h" + +class FilePath; + +namespace webkit_database { + +class VfsBackend { + public: + static void OpenFile( + const FilePath& file_name, const FilePath& db_dir, int desired_flags, + base::ProcessHandle handle, base::PlatformFile* target_handle, + base::PlatformFile* target_dir_handle); + static int DeleteFile( + const FilePath& file_name, const FilePath& db_dir, bool sync_dir); + static uint32 GetFileAttributes(const FilePath& file_name); + static int64 GetFileSize(const FilePath& file_name); + + private: + static bool OpenFileFlagsAreConsistent( + const FilePath& file_name, const FilePath& db_dir, int desired_flags); +}; + +} // namespace webkit_database + +#endif // WEBKIT_DATABASE_VFS_BACKEND_H_ diff --git a/webkit/tools/test_shell/layout_test_controller.cc b/webkit/tools/test_shell/layout_test_controller.cc index dada6c4..2d0746e 100644 --- a/webkit/tools/test_shell/layout_test_controller.cc +++ b/webkit/tools/test_shell/layout_test_controller.cc @@ -22,6 +22,7 @@ #include "webkit/glue/dom_operations.h" #include "webkit/glue/webpreferences.h" #include "webkit/glue/webview.h" +#include "webkit/tools/test_shell/simple_database_system.h" #include "webkit/tools/test_shell/simple_resource_loader_bridge.h" #include "webkit/tools/test_shell/test_navigation_controller.h" #include "webkit/tools/test_shell/test_shell.h" @@ -125,6 +126,7 @@ LayoutTestController::LayoutTestController(TestShell* shell) { BindMethod("waitForPolicyDelegate", &LayoutTestController::waitForPolicyDelegate); BindMethod("setWillSendRequestReturnsNullOnRedirect", &LayoutTestController::setWillSendRequestReturnsNullOnRedirect); BindMethod("whiteListAccessFromOrigin", &LayoutTestController::whiteListAccessFromOrigin); + BindMethod("clearAllDatabases", &LayoutTestController::clearAllDatabases); // The following are stubs. BindMethod("dumpAsWebArchive", &LayoutTestController::dumpAsWebArchive); @@ -946,8 +948,7 @@ void LayoutTestController::fallbackMethod( } void LayoutTestController::whiteListAccessFromOrigin( - const CppArgumentList& args, CppVariant* result) -{ + const CppArgumentList& args, CppVariant* result) { result->SetNull(); if (args.size() != 4 || !args[0].isString() || !args[1].isString() || @@ -964,6 +965,12 @@ void LayoutTestController::whiteListAccessFromOrigin( args[3].ToBoolean()); } +void LayoutTestController::clearAllDatabases( + const CppArgumentList& args, CppVariant* result) { + result->SetNull(); + SimpleDatabaseSystem::GetInstance()->ClearAllDatabases(); +} + void LayoutTestController::LogErrorToConsole(const std::string& text) { shell_->delegate()->didAddMessageToConsole( WebConsoleMessage(WebConsoleMessage::LevelError, diff --git a/webkit/tools/test_shell/layout_test_controller.h b/webkit/tools/test_shell/layout_test_controller.h index 51c5e8c..5b65653 100644 --- a/webkit/tools/test_shell/layout_test_controller.h +++ b/webkit/tools/test_shell/layout_test_controller.h @@ -197,6 +197,9 @@ class LayoutTestController : public CppBoundClass { // Allows layout tests to call SecurityOrigin::whiteListAccessFromOrigin(). void whiteListAccessFromOrigin(const CppArgumentList& args, CppVariant* result); + // Clears all databases. + void clearAllDatabases(const CppArgumentList& args, CppVariant* result); + public: // The following methods are not exposed to JavaScript. void SetWorkQueueFrozen(bool frozen) { work_queue_.set_frozen(frozen); } diff --git a/webkit/tools/test_shell/simple_database_system.cc b/webkit/tools/test_shell/simple_database_system.cc new file mode 100644 index 0000000..ab98e1a --- /dev/null +++ b/webkit/tools/test_shell/simple_database_system.cc @@ -0,0 +1,107 @@ +// Copyright (c) 2009 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/tools/test_shell/simple_database_system.h" + +#if defined(USE_SYSTEM_SQLITE) +#include <sqlite3.h> +#else +#include "third_party/sqlite/preprocessed/sqlite3.h" +#endif + +#include "base/file_util.h" +#include "base/platform_thread.h" +#include "base/process_util.h" +#include "webkit/database/vfs_backend.h" +#include "webkit/glue/webkit_glue.h" + +using webkit_database::VfsBackend; + +SimpleDatabaseSystem* SimpleDatabaseSystem::instance_ = NULL; + +SimpleDatabaseSystem* SimpleDatabaseSystem::GetInstance() { + DCHECK(instance_); + return instance_; +} + +SimpleDatabaseSystem::SimpleDatabaseSystem() + : hack_main_db_handle_(base::kInvalidPlatformFileValue) { + temp_dir_.CreateUniqueTempDir(); + DCHECK(!instance_); + instance_ = this; +} + +SimpleDatabaseSystem::~SimpleDatabaseSystem() { + base::ClosePlatformFile(hack_main_db_handle_); + instance_ = NULL; +} + +base::PlatformFile SimpleDatabaseSystem::OpenFile( + const FilePath& file_name, int desired_flags, + base::PlatformFile* dir_handle) { + base::PlatformFile file_handle = base::kInvalidPlatformFileValue; + VfsBackend::OpenFile(GetDBFileFullPath(file_name), GetDBDir(), desired_flags, + base::GetCurrentProcessHandle(), &file_handle, + dir_handle); + + // HACK: Currently, the DB object that keeps track of the main database + // (DatabaseTracker) is a singleton that is declared as a static variable + // in a function, so it gets destroyed at the very end of the program. + // Because of that, we have a handle opened to the main DB file until the + // very end of the program, which prevents temp_dir_'s destructor from + // deleting the database directory. + // + // We will properly solve this problem when we reimplement DatabaseTracker. + // For now, however, we are going to take advantage of the fact that in order + // to do anything related to DBs, we have to call openDatabase() first, which + // opens a handle to the main DB before opening handles to any other DB files. + // We are going to cache the first file handle we get, and we are going to + // manually close it in the destructor. + if (hack_main_db_handle_ == base::kInvalidPlatformFileValue) { + hack_main_db_handle_ = file_handle; + } + + return file_handle; +} + +int SimpleDatabaseSystem::DeleteFile( + const FilePath& file_name, bool sync_dir) { + // We try to delete the file multiple times, because that's what the default + // VFS does (apparently deleting a file can sometimes fail on Windows). + // We sleep for 10ms between retries for the same reason. + const int kNumDeleteRetries = 3; + int num_retries = 0; + int error_code = SQLITE_OK; + do { + error_code = VfsBackend::DeleteFile( + GetDBFileFullPath(file_name), GetDBDir(), sync_dir); + } while ((++num_retries < kNumDeleteRetries) && + (error_code == SQLITE_IOERR_DELETE) && + (PlatformThread::Sleep(10), 1)); + + return error_code; +} + +long SimpleDatabaseSystem::GetFileAttributes( + const FilePath& file_name) { + return VfsBackend::GetFileAttributes(GetDBFileFullPath(file_name)); +} + +long long SimpleDatabaseSystem::GetFileSize( + const FilePath& file_name) { + return VfsBackend::GetFileSize(GetDBFileFullPath(file_name)); +} + +void SimpleDatabaseSystem::ClearAllDatabases() { + // TODO(dumi): implement this once we refactor DatabaseTracker + //file_util::Delete(GetDBDir(), true); +} + +FilePath SimpleDatabaseSystem::GetDBDir() { + return temp_dir_.path().Append(FILE_PATH_LITERAL("databases")); +} + +FilePath SimpleDatabaseSystem::GetDBFileFullPath(const FilePath& file_name) { + return GetDBDir().Append(file_name); +} diff --git a/webkit/tools/test_shell/simple_database_system.h b/webkit/tools/test_shell/simple_database_system.h new file mode 100644 index 0000000..cf8c997 --- /dev/null +++ b/webkit/tools/test_shell/simple_database_system.h @@ -0,0 +1,38 @@ +// Copyright (c) 2009 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_TOOLS_TEST_SHELL_SIMPLE_DATABASE_SYSTEM_H_ +#define WEBKIT_TOOLS_TEST_SHELL_SIMPLE_DATABASE_SYSTEM_H_ + +#include "base/file_path.h" +#include "base/platform_file.h" +#include "base/scoped_temp_dir.h" + +class SimpleDatabaseSystem { + public: + static SimpleDatabaseSystem* GetInstance(); + SimpleDatabaseSystem(); + ~SimpleDatabaseSystem(); + + base::PlatformFile OpenFile( + const FilePath& file_name, int desired_flags, + base::PlatformFile* dir_handle); + int DeleteFile(const FilePath& file_name, bool sync_dir); + long GetFileAttributes(const FilePath& file_name); + long long GetFileSize(const FilePath& file_name); + void ClearAllDatabases(); + + private: + FilePath GetDBDir(); + FilePath GetDBFileFullPath(const FilePath& file_name); + + static SimpleDatabaseSystem* instance_; + + ScopedTempDir temp_dir_; + + // HACK: see OpenFile's implementation + base::PlatformFile hack_main_db_handle_; +}; + +#endif // WEBKIT_TOOLS_TEST_SHELL_SIMPLE_DATABASE_SYSTEM_H_ diff --git a/webkit/tools/test_shell/test_shell.cc b/webkit/tools/test_shell/test_shell.cc index 3912d0a..8a7e85c 100644 --- a/webkit/tools/test_shell/test_shell.cc +++ b/webkit/tools/test_shell/test_shell.cc @@ -423,6 +423,7 @@ void TestShell::ResetWebPreferences() { web_prefs_->local_storage_enabled = true; web_prefs_->session_storage_enabled = true; web_prefs_->application_cache_enabled = false; + web_prefs_->databases_enabled = true; // LayoutTests were written with Safari Mac in mind which does not allow // tabbing to links by default. web_prefs_->tabs_to_links = false; diff --git a/webkit/tools/test_shell/test_shell.gyp b/webkit/tools/test_shell/test_shell.gyp index 3df81da..cc497eb 100644 --- a/webkit/tools/test_shell/test_shell.gyp +++ b/webkit/tools/test_shell/test_shell.gyp @@ -35,6 +35,7 @@ '../../../testing/gtest.gyp:gtest', '../../../third_party/npapi/npapi.gyp:npapi', '../../webkit.gyp:appcache', + '../../webkit.gyp:database', '../../webkit.gyp:glue', '../../webkit.gyp:webkit', '../../webkit.gyp:inspector_resources', @@ -63,6 +64,8 @@ 'simple_appcache_system.cc', 'simple_appcache_system.h', 'simple_clipboard_impl.cc', + 'simple_database_system.cc', + 'simple_database_system.h', 'simple_resource_loader_bridge.cc', 'simple_resource_loader_bridge.h', 'test_navigation_controller.cc', diff --git a/webkit/tools/test_shell/test_shell_webkit_init.h b/webkit/tools/test_shell/test_shell_webkit_init.h index cc25ec7..3bf3fad 100644 --- a/webkit/tools/test_shell/test_shell_webkit_init.h +++ b/webkit/tools/test_shell/test_shell_webkit_init.h @@ -18,14 +18,16 @@ #include "webkit/api/public/WebString.h" #include "webkit/api/public/WebURL.h" #include "webkit/appcache/web_application_cache_host_impl.h" +#include "webkit/database/vfs_backend.h" +#include "webkit/extensions/v8/gears_extension.h" +#include "webkit/extensions/v8/interval_extension.h" #include "webkit/glue/simple_webmimeregistry_impl.h" #include "webkit/glue/webclipboard_impl.h" #include "webkit/glue/webkit_glue.h" #include "webkit/glue/webkitclient_impl.h" -#include "webkit/extensions/v8/gears_extension.h" -#include "webkit/extensions/v8/interval_extension.h" #include "webkit/tools/test_shell/mock_webclipboard_impl.h" #include "webkit/tools/test_shell/simple_appcache_system.h" +#include "webkit/tools/test_shell/simple_database_system.h" #include "webkit/tools/test_shell/simple_resource_loader_bridge.h" #include "v8/include/v8.h" @@ -91,14 +93,37 @@ class TestShellWebKitInit : public webkit_glue::WebKitClientImpl { } virtual bool sandboxEnabled() { - return false; + return true; + } + + virtual base::PlatformFile databaseOpenFile( + const WebKit::WebString& file_name, int desired_flags, + base::PlatformFile* dir_handle) { + return SimpleDatabaseSystem::GetInstance()->OpenFile( + webkit_glue::WebStringToFilePath(file_name), + desired_flags, dir_handle); + } + + virtual int databaseDeleteFile(const WebKit::WebString& file_name, + bool sync_dir) { + return SimpleDatabaseSystem::GetInstance()->DeleteFile( + webkit_glue::WebStringToFilePath(file_name), sync_dir); + } + + virtual long databaseGetFileAttributes(const WebKit::WebString& file_name) { + return SimpleDatabaseSystem::GetInstance()->GetFileAttributes( + webkit_glue::WebStringToFilePath(file_name)); + } + + virtual long long databaseGetFileSize(const WebKit::WebString& file_name) { + return SimpleDatabaseSystem::GetInstance()->GetFileSize( + webkit_glue::WebStringToFilePath(file_name)); } - virtual bool getFileSize(const WebKit::WebString& path, - long long& result) { + virtual bool getFileSize(const WebKit::WebString& path, long long& result) { return file_util::GetFileSize( - FilePath(webkit_glue::WebStringToFilePathString(path)), - reinterpret_cast<int64*>(&result)); + webkit_glue::WebStringToFilePath(path), + reinterpret_cast<int64*>(&result)); } virtual unsigned long long visitedLinkHash(const char* canonicalURL, @@ -185,6 +210,7 @@ class TestShellWebKitInit : public webkit_glue::WebKitClientImpl { webkit_glue::WebClipboardImpl real_clipboard_; ScopedTempDir appcache_dir_; SimpleAppCacheSystem appcache_system_; + SimpleDatabaseSystem database_system_; #if defined(OS_WIN) WebKit::WebThemeEngine* active_theme_engine_; diff --git a/webkit/webkit.gyp b/webkit/webkit.gyp index 59b3e51..a0d73fe 100644 --- a/webkit/webkit.gyp +++ b/webkit/webkit.gyp @@ -349,6 +349,19 @@ ], }, { + 'target_name': 'database', + 'type': '<(library)', + 'msvs_guid': '1DA00DDD-44E5-4C56-B2CC-414FB0164492', + 'dependencies': [ + '../base/base.gyp:base', + '../third_party/sqlite/sqlite.gyp:sqlite', + ], + 'sources': [ + 'database/vfs_backend.cc', + 'database/vfs_backend.h', + ], + }, + { 'target_name': 'glue', 'type': '<(library)', 'msvs_guid': 'C66B126D-0ECE-4CA2-B6DC-FA780AFBBF09', |