| Index: webkit/database/vfs_backend.cc
|
| ===================================================================
|
| --- webkit/database/vfs_backend.cc (revision 0)
|
| +++ webkit/database/vfs_backend.cc (working copy)
|
| @@ -2,12 +2,8 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| -#include "chrome/browser/renderer_host/database_dispatcher_host.h"
|
| +#include "webkit/database/vfs_backend.h"
|
|
|
| -#if defined(OS_WIN)
|
| -#include <windows.h>
|
| -#endif
|
| -
|
| #if defined(USE_SYSTEM_SQLITE)
|
| #include <sqlite3.h>
|
| #else
|
| @@ -16,74 +12,27 @@
|
|
|
| #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"
|
|
|
| -#if defined(OS_POSIX)
|
| -#include "base/file_descriptor_posix.h"
|
| -#endif
|
| +namespace webkit_database {
|
|
|
| -const int kNumDeleteRetries = 5;
|
| -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
|
| -};
|
| -
|
| -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?
|
| -};
|
| -
|
| -// Scheduled by the file Thread on the IO thread.
|
| -// Sends back to the renderer process the given message.
|
| -static void SendMessage(ResourceMessageFilter* sender,
|
| - IPC::Message* message) {
|
| - sender->Send(message);
|
| -
|
| - // Every time we get a DB-related message, we AddRef() the resource
|
| - // message filterto make sure it doesn't get destroyed before we have
|
| - // a chance to send the reply back. So we need to Release() is here
|
| - // and allow it to be destroyed if needed.
|
| - sender->Release();
|
| -}
|
| -
|
| -// Make sure the flags used to open a DB file are consistent.
|
| -static bool OpenFileFlagsAreConsistent(const OpenFileParams& params) {
|
| +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 ((params.file_name == params.db_dir) &&
|
| - (!(params.desired_flags & SQLITE_OPEN_DELETEONCLOSE) ||
|
| - !(params.desired_flags & SQLITE_OPEN_CREATE))) {
|
| + if ((file_name == db_dir) &&
|
| + (!(desired_flags & SQLITE_OPEN_DELETEONCLOSE) ||
|
| + !(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;
|
| + 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)) {
|
| @@ -127,153 +76,101 @@
|
| 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
|
| -// corresponding renderer process with the file handle.
|
| -static void DatabaseOpenFile(MessageLoop* io_thread_message_loop,
|
| - const OpenFileParams& params,
|
| - int32 message_id,
|
| - ResourceMessageFilter* sender) {
|
| - base::PlatformFile target_handle = base::kInvalidPlatformFileValue;
|
| -#if defined(OS_POSIX)
|
| - base::PlatformFile target_dir_handle = base::kInvalidPlatformFileValue;
|
| -#endif
|
| -
|
| +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(params) &&
|
| - file_util::CreateDirectory(params.db_dir)) {
|
| + if (OpenFileFlagsAreConsistent(file_name, db_dir, desired_flags) &&
|
| + file_util::CreateDirectory(db_dir)) {
|
| int flags = 0;
|
| flags |= base::PLATFORM_FILE_READ;
|
| - if (params.desired_flags & SQLITE_OPEN_READWRITE) {
|
| + if (desired_flags & SQLITE_OPEN_READWRITE) {
|
| flags |= base::PLATFORM_FILE_WRITE;
|
| }
|
|
|
| - if (!(params.desired_flags & SQLITE_OPEN_MAIN_DB)) {
|
| + if (!(desired_flags & SQLITE_OPEN_MAIN_DB)) {
|
| flags |= base::PLATFORM_FILE_EXCLUSIVE_READ |
|
| base::PLATFORM_FILE_EXCLUSIVE_WRITE;
|
| }
|
|
|
| - if (params.desired_flags & SQLITE_OPEN_CREATE) {
|
| + if (desired_flags & SQLITE_OPEN_CREATE) {
|
| flags |= base::PLATFORM_FILE_OPEN_ALWAYS;
|
| } else {
|
| flags |= base::PLATFORM_FILE_OPEN;
|
| }
|
|
|
| - if (params.desired_flags & SQLITE_OPEN_EXCLUSIVE) {
|
| + if (desired_flags & SQLITE_OPEN_EXCLUSIVE) {
|
| flags |= base::PLATFORM_FILE_EXCLUSIVE_READ |
|
| base::PLATFORM_FILE_EXCLUSIVE_WRITE;
|
| }
|
|
|
| - if (params.desired_flags & SQLITE_OPEN_DELETEONCLOSE) {
|
| + 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 file_name;
|
| - if (params.file_name == params.db_dir) {
|
| - if (!file_util::CreateTemporaryFileInDir(params.db_dir, &file_name)) {
|
| - file_name = FilePath();
|
| + FilePath db_file_name;
|
| + if (file_name == db_dir) {
|
| + if (!file_util::CreateTemporaryFileInDir(db_dir, &db_file_name)) {
|
| + db_file_name = FilePath();
|
| }
|
| } else {
|
| - file_name = params.file_name;
|
| + db_file_name = 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));
|
| + (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,
|
| - params.handle, &target_handle, 0, false,
|
| + 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;
|
| + *target_handle = INVALID_HANDLE_VALUE;
|
| }
|
| #elif defined(OS_POSIX)
|
| - target_handle = file_handle;
|
| + *target_handle = file_handle;
|
|
|
| - int file_type = params.desired_flags & 0x00007F00;
|
| - bool creating_new_file = (params.desired_flags & SQLITE_OPEN_CREATE);
|
| + 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(
|
| - params.db_dir.ToWStringHack(),
|
| + *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;
|
| + if (*target_dir_handle == base::kInvalidPlatformFileValue) {
|
| + base::ClosePlatformFile(*target_handle);
|
| + *target_handle = base::kInvalidPlatformFileValue;
|
| }
|
| }
|
| #endif
|
| }
|
| }
|
| -
|
| - ViewMsg_DatabaseOpenFileResponse_Params response_params;
|
| -#if defined(OS_WIN)
|
| - response_params.file_handle = target_handle;
|
| -#elif defined(OS_POSIX)
|
| - 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)));
|
| }
|
|
|
| -// Scheduled by the IO thread on the file thread.
|
| -// Deletes the given database file, then schedules
|
| -// a task on the IO thread's message loop to send an IPC back to
|
| -// corresponding renderer process with the error code.
|
| -static void DatabaseDeleteFile(
|
| - MessageLoop* io_thread_message_loop,
|
| - const DeleteFileParams& params,
|
| - int32 message_id,
|
| - int reschedule_count,
|
| - ResourceMessageFilter* sender) {
|
| - // Return an error if the file could not be deleted
|
| - // after kNumDeleteRetries times.
|
| - if (!reschedule_count) {
|
| - io_thread_message_loop->PostTask(FROM_HERE,
|
| - NewRunnableFunction(SendMessage, sender,
|
| - new ViewMsg_DatabaseDeleteFileResponse(
|
| - message_id, SQLITE_IOERR_DELETE)));
|
| - return;
|
| +int VfsBackend::DeleteFile(
|
| + const FilePath& file_name, const FilePath& db_dir, bool sync_dir) {
|
| + if (!file_util::PathExists(file_name)) {
|
| + return SQLITE_OK;
|
| }
|
| -
|
| - // 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 (!file_util::Delete(file_name, false)) {
|
| + return SQLITE_IOERR_DELETE;
|
| }
|
|
|
| -
|
| - // If the file could not be deleted, try again.
|
| - if (!file_util::Delete(params.file_name, false)) {
|
| - MessageLoop::current()->PostDelayedTask(FROM_HERE,
|
| - NewRunnableFunction(DatabaseDeleteFile, io_thread_message_loop,
|
| - params, message_id, reschedule_count - 1, sender),
|
| - kDelayDeleteRetryMs);
|
| - 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) {
|
| + if (sync_dir) {
|
| base::PlatformFile dir_fd = base::CreatePlatformFile(
|
| - params.db_dir.ToWStringHack(), base::PLATFORM_FILE_READ, NULL);
|
| + db_dir.ToWStringHack(), base::PLATFORM_FILE_READ, NULL);
|
| if (dir_fd == base::kInvalidPlatformFileValue) {
|
| error_code = SQLITE_CANTOPEN;
|
| } else {
|
| @@ -284,23 +181,12 @@
|
| }
|
| }
|
| #endif
|
| -
|
| - io_thread_message_loop->PostTask(FROM_HERE,
|
| - NewRunnableFunction(SendMessage, sender,
|
| - new ViewMsg_DatabaseDeleteFileResponse(message_id, error_code)));
|
| + return error_code;
|
| }
|
|
|
| -// Scheduled by the IO thread on the file thread.
|
| -// Gets the attributes of the given database file, then schedules
|
| -// a task on the IO thread's message loop to send an IPC back to
|
| -// corresponding renderer process.
|
| -static void DatabaseGetFileAttributes(
|
| - MessageLoop* io_thread_message_loop,
|
| - const FilePath& file_name,
|
| - int32 message_id,
|
| - ResourceMessageFilter* sender) {
|
| +uint32 VfsBackend::GetFileAttributes(const FilePath& file_name) {
|
| #if defined(OS_WIN)
|
| - uint32 attributes = GetFileAttributes(file_name.value().c_str());
|
| + uint32 attributes = ::GetFileAttributes(file_name.value().c_str());
|
| #elif defined(OS_POSIX)
|
| uint32 attributes = 0;
|
| if (!access(file_name.value().c_str(), R_OK)) {
|
| @@ -313,163 +199,12 @@
|
| attributes = -1;
|
| }
|
| #endif
|
| -
|
| - io_thread_message_loop->PostTask(FROM_HERE,
|
| - NewRunnableFunction(SendMessage, sender,
|
| - new ViewMsg_DatabaseGetFileAttributesResponse(
|
| - message_id, attributes)));
|
| + return attributes;
|
| }
|
|
|
| -// Scheduled by the IO thread on the file thread.
|
| -// Gets the size of the given file, then schedules a task
|
| -// on the IO thread's message loop to send an IPC back to
|
| -// the corresponding renderer process.
|
| -static void DatabaseGetFileSize(
|
| - MessageLoop* io_thread_message_loop,
|
| - const FilePath& file_name,
|
| - int32 message_id,
|
| - ResourceMessageFilter* sender) {
|
| +int64 VfsBackend::GetFileSize(const FilePath& file_name) {
|
| int64 size = 0;
|
| - if (!file_util::GetFileSize(file_name, &size)) {
|
| - size = 0;
|
| - }
|
| -
|
| - io_thread_message_loop->PostTask(FROM_HERE,
|
| - NewRunnableFunction(SendMessage, sender,
|
| - new ViewMsg_DatabaseGetFileSizeResponse(message_id, size)));
|
| + return (file_util::GetFileSize(file_name, &size) ? size : 0);
|
| }
|
|
|
| -} // namespace
|
| -
|
| -DatabaseDispatcherHost::DatabaseDispatcherHost(
|
| - const FilePath& profile_path,
|
| - ResourceMessageFilter* resource_message_filter)
|
| - : profile_path_(profile_path),
|
| - resource_message_filter_(resource_message_filter),
|
| - file_thread_message_loop_(
|
| - g_browser_process->file_thread()->message_loop()) {
|
| -}
|
| -
|
| -DatabaseDispatcherHost::~DatabaseDispatcherHost() {
|
| -}
|
| -
|
| -bool DatabaseDispatcherHost::IsDBMessage(const IPC::Message& message) {
|
| - switch (message.type()) {
|
| - case ViewHostMsg_DatabaseOpenFile::ID:
|
| - case ViewHostMsg_DatabaseDeleteFile::ID:
|
| - case ViewHostMsg_DatabaseGetFileAttributes::ID:
|
| - case ViewHostMsg_DatabaseGetFileSize::ID:
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -bool DatabaseDispatcherHost::OnMessageReceived(
|
| - const IPC::Message& message, bool* message_was_ok) {
|
| - if (!IsDBMessage(message)) {
|
| - return false;
|
| - }
|
| - *message_was_ok = true;
|
| -
|
| - bool handled = true;
|
| - IPC_BEGIN_MESSAGE_MAP_EX(DatabaseDispatcherHost, message, *message_was_ok)
|
| - IPC_MESSAGE_HANDLER(ViewHostMsg_DatabaseOpenFile, OnDatabaseOpenFile);
|
| - IPC_MESSAGE_HANDLER(ViewHostMsg_DatabaseDeleteFile, OnDatabaseDeleteFile);
|
| - IPC_MESSAGE_HANDLER(ViewHostMsg_DatabaseGetFileAttributes,
|
| - OnDatabaseGetFileAttributes);
|
| - IPC_MESSAGE_HANDLER(ViewHostMsg_DatabaseGetFileSize,
|
| - OnDatabaseGetFileSize);
|
| - IPC_MESSAGE_UNHANDLED(handled = false)
|
| - IPC_END_MESSAGE_MAP_EX()
|
| - return handled;
|
| -}
|
| -
|
| -FilePath DatabaseDispatcherHost::GetDBDir() {
|
| - return profile_path_.Append(FILE_PATH_LITERAL("databases"));
|
| -}
|
| -
|
| -FilePath DatabaseDispatcherHost::GetDBFileFullPath(const FilePath& file_name) {
|
| - // Do not allow '\', '/' and ':' in file names.
|
| - FilePath::StringType file = file_name.value();
|
| - if ((file.find('\\') != std::wstring::npos) ||
|
| - (file.find('/') != std::wstring::npos) ||
|
| - (file.find(':') != std::wstring::npos)) {
|
| - return FilePath();
|
| - }
|
| - return GetDBDir().Append(file_name);
|
| -}
|
| -
|
| -void DatabaseDispatcherHost::OnDatabaseOpenFile(
|
| - const FilePath& file_name, int desired_flags,
|
| - int32 message_id) {
|
| - FilePath db_file_name = GetDBFileFullPath(file_name);
|
| -
|
| - if (db_file_name.empty()) {
|
| - ViewMsg_DatabaseOpenFileResponse_Params response_params;
|
| -#if defined(OS_WIN)
|
| - response_params.file_handle = base::kInvalidPlatformFileValue;
|
| -#elif defined(OS_POSIX)
|
| - response_params.file_handle =
|
| - base::FileDescriptor(base::kInvalidPlatformFileValue, true);
|
| - response_params.dir_handle =
|
| - base::FileDescriptor(base::kInvalidPlatformFileValue, true);
|
| -#endif
|
| - resource_message_filter_->Send(new ViewMsg_DatabaseOpenFileResponse(
|
| - message_id, response_params));
|
| - return;
|
| - }
|
| -
|
| - OpenFileParams params = { GetDBDir(), db_file_name, desired_flags,
|
| - resource_message_filter_->handle() };
|
| - resource_message_filter_->AddRef();
|
| - file_thread_message_loop_->PostTask(FROM_HERE,
|
| - NewRunnableFunction(DatabaseOpenFile, MessageLoop::current(),
|
| - params, message_id, resource_message_filter_));
|
| -}
|
| -
|
| -void DatabaseDispatcherHost::OnDatabaseDeleteFile(
|
| - const FilePath& file_name, const bool& sync_dir, int32 message_id) {
|
| - FilePath db_file_name = GetDBFileFullPath(file_name);
|
| - if (db_file_name.empty()) {
|
| - resource_message_filter_->Send(new ViewMsg_DatabaseDeleteFileResponse(
|
| - message_id, SQLITE_IOERR_DELETE));
|
| - return;
|
| - }
|
| -
|
| - DeleteFileParams params = { GetDBDir(), db_file_name, sync_dir };
|
| - resource_message_filter_->AddRef();
|
| - file_thread_message_loop_->PostTask(FROM_HERE,
|
| - NewRunnableFunction(DatabaseDeleteFile, MessageLoop::current(),
|
| - params, message_id, kNumDeleteRetries, resource_message_filter_));
|
| -}
|
| -
|
| -void DatabaseDispatcherHost::OnDatabaseGetFileAttributes(
|
| - const FilePath& file_name, int32 message_id) {
|
| - FilePath db_file_name = GetDBFileFullPath(file_name);
|
| - if (db_file_name.empty()) {
|
| - resource_message_filter_->Send(
|
| - new ViewMsg_DatabaseGetFileAttributesResponse(
|
| - message_id, -1));
|
| - return;
|
| - }
|
| -
|
| - resource_message_filter_->AddRef();
|
| - file_thread_message_loop_->PostTask(FROM_HERE,
|
| - NewRunnableFunction(DatabaseGetFileAttributes, MessageLoop::current(),
|
| - db_file_name, message_id, resource_message_filter_));
|
| -}
|
| -
|
| -void DatabaseDispatcherHost::OnDatabaseGetFileSize(
|
| - const FilePath& file_name, int32 message_id) {
|
| - FilePath db_file_name = GetDBFileFullPath(file_name);
|
| - if (db_file_name.empty()) {
|
| - resource_message_filter_->Send(new ViewMsg_DatabaseGetFileSizeResponse(
|
| - message_id, 0));
|
| - return;
|
| - }
|
| -
|
| - resource_message_filter_->AddRef();
|
| - file_thread_message_loop_->PostTask(FROM_HERE,
|
| - NewRunnableFunction(DatabaseGetFileSize, MessageLoop::current(),
|
| - db_file_name, message_id, resource_message_filter_));
|
| -}
|
| +} // namespace database
|
|
|