diff options
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/renderer_host/database_dispatcher_host.cc | 210 | ||||
-rw-r--r-- | chrome/browser/renderer_host/database_dispatcher_host.h | 2 | ||||
-rw-r--r-- | chrome/common/db_message_filter.cc | 4 | ||||
-rw-r--r-- | chrome/common/render_messages.h | 41 | ||||
-rw-r--r-- | chrome/common/render_messages_internal.h | 13 | ||||
-rw-r--r-- | chrome/renderer/renderer_webkitclient_impl.cc | 52 | ||||
-rw-r--r-- | chrome/renderer/renderer_webkitclient_impl.h | 6 |
7 files changed, 285 insertions, 43 deletions
diff --git a/chrome/browser/renderer_host/database_dispatcher_host.cc b/chrome/browser/renderer_host/database_dispatcher_host.cc index abf55fb..1dcf93b 100644 --- a/chrome/browser/renderer_host/database_dispatcher_host.cc +++ b/chrome/browser/renderer_host/database_dispatcher_host.cc @@ -27,6 +27,10 @@ #include "chrome/common/render_messages.h" #include "ipc/ipc_message.h" +#if defined(OS_POSIX) +#include "base/file_descriptor_posix.h" +#endif + const int kNumDeleteRetries = 5; const int kDelayDeleteRetryMs = 100; @@ -39,6 +43,12 @@ struct OpenFileParams { 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, @@ -52,6 +62,66 @@ 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) { + if (params.file_name == params.db_dir) { + return (params.desired_flags == SQLITE_OPEN_READONLY); + } + + 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 @@ -61,8 +131,14 @@ static void DatabaseOpenFile(MessageLoop* io_thread_message_loop, int32 message_id, ResourceMessageFilter* sender) { base::PlatformFile target_handle = base::kInvalidPlatformFileValue; - // Create the database directory if it doesn't exist. - if (file_util::CreateDirectory(params.db_dir)) { +#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) { @@ -80,16 +156,21 @@ static void DatabaseOpenFile(MessageLoop* io_thread_message_loop, 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; } // Try to open/create the DB file. -#if defined(OS_WIN) base::PlatformFile file_handle = - base::CreatePlatformFile(params.file_name.value(), flags, NULL); + base::CreatePlatformFile(params.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, @@ -97,13 +178,39 @@ static void DatabaseOpenFile(MessageLoop* io_thread_message_loop, // 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 + } } - io_thread_message_loop->PostTask(FROM_HERE, - NewRunnableFunction(SendMessage, sender, - new ViewMsg_DatabaseOpenFileResponse(message_id, target_handle))); + ViewMsg_DatabaseOpenFileResponse_Params response_params = +#if defined(OS_WIN) + { target_handle }; +#elif defined(OS_POSIX) + { base::FileDescriptor(target_handle, true), + 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. @@ -112,22 +219,59 @@ static void DatabaseOpenFile(MessageLoop* io_thread_message_loop, // corresponding renderer process with the error code. static void DatabaseDeleteFile( MessageLoop* io_thread_message_loop, - const FilePath& file_name, + const DeleteFileParams& params, int32 message_id, int reschedule_count, ResourceMessageFilter* sender) { - if (reschedule_count > 0 && file_util::PathExists(file_name) && - !file_util::Delete(file_name, false)) { - MessageLoop::current()->PostDelayedTask(FROM_HERE, - NewRunnableFunction(DatabaseDeleteFile, io_thread_message_loop, - file_name, message_id, reschedule_count - 1, sender), - kDelayDeleteRetryMs); - } else { + // 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, reschedule_count > 0))); + message_id, SQLITE_IOERR_DELETE))); + 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)) { + 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) { + 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))); } // Scheduled by the IO thread on the file thread. @@ -141,8 +285,17 @@ static void DatabaseGetFileAttributes( ResourceMessageFilter* sender) { #if defined(OS_WIN) uint32 attributes = GetFileAttributes(file_name.value().c_str()); -#else - uint32 attributes = -1L; +#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 io_thread_message_loop->PostTask(FROM_HERE, @@ -232,16 +385,22 @@ FilePath DatabaseDispatcherHost::GetDBFileFullPath(const FilePath& file_name) { void DatabaseDispatcherHost::OnDatabaseOpenFile( const FilePath& file_name, int desired_flags, int32 message_id) { - FilePath db_dir = GetDBDir(); FilePath db_file_name = GetDBFileFullPath(file_name); if (db_file_name.empty()) { + ViewMsg_DatabaseOpenFileResponse_Params response_params = +#if defined(OS_WIN) + { base::kInvalidPlatformFileValue }; +#elif defined(OS_POSIX) + { base::FileDescriptor(base::kInvalidPlatformFileValue, true), + base::FileDescriptor(base::kInvalidPlatformFileValue, true) }; +#endif resource_message_filter_->Send(new ViewMsg_DatabaseOpenFileResponse( - message_id, base::kInvalidPlatformFileValue)); + message_id, response_params)); return; } - OpenFileParams params = { db_dir, db_file_name, desired_flags, + OpenFileParams params = { GetDBDir(), db_file_name, desired_flags, resource_message_filter_->handle() }; resource_message_filter_->AddRef(); file_thread_message_loop_->PostTask(FROM_HERE, @@ -250,18 +409,19 @@ void DatabaseDispatcherHost::OnDatabaseOpenFile( } void DatabaseDispatcherHost::OnDatabaseDeleteFile( - const FilePath& file_name, int32 message_id) { + 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, false)); + 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(), - db_file_name, message_id, kNumDeleteRetries, resource_message_filter_)); + params, message_id, kNumDeleteRetries, resource_message_filter_)); } void DatabaseDispatcherHost::OnDatabaseGetFileAttributes( diff --git a/chrome/browser/renderer_host/database_dispatcher_host.h b/chrome/browser/renderer_host/database_dispatcher_host.h index 90dc00d..3f5302d 100644 --- a/chrome/browser/renderer_host/database_dispatcher_host.h +++ b/chrome/browser/renderer_host/database_dispatcher_host.h @@ -28,7 +28,7 @@ class DatabaseDispatcherHost { void OnDatabaseOpenFile(const FilePath& file_name, int desired_flags, int32 message_id); // Processes the request to delete the given DB file. - void OnDatabaseDeleteFile(const FilePath& file_name, + void OnDatabaseDeleteFile(const FilePath& file_name, const bool& sync_dir, int32 message_id); // Processes the request to return the attributes of the given DB file. void OnDatabaseGetFileAttributes(const FilePath& file_name, diff --git a/chrome/common/db_message_filter.cc b/chrome/common/db_message_filter.cc index cba4aea..396ca7c 100644 --- a/chrome/common/db_message_filter.cc +++ b/chrome/common/db_message_filter.cc @@ -75,9 +75,9 @@ bool DBMessageFilter::OnMessageReceived(const IPC::Message& message) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(DBMessageFilter, message) IPC_MESSAGE_HANDLER(ViewMsg_DatabaseOpenFileResponse, - OnResponse<base::PlatformFile>) + OnResponse<ViewMsg_DatabaseOpenFileResponse_Params>) IPC_MESSAGE_HANDLER(ViewMsg_DatabaseDeleteFileResponse, - OnResponse<bool>) + OnResponse<int>) IPC_MESSAGE_HANDLER(ViewMsg_DatabaseGetFileAttributesResponse, OnResponse<uint32>) IPC_MESSAGE_HANDLER(ViewMsg_DatabaseGetFileSizeResponse, diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h index aeda43d..4e80223 100644 --- a/chrome/common/render_messages.h +++ b/chrome/common/render_messages.h @@ -46,7 +46,12 @@ #include "webkit/glue/webpreferences.h" #include "webkit/glue/webview_delegate.h" +#if defined(OS_WIN) +#include "base/platform_file.h" +#endif + #if defined(OS_POSIX) +#include "base/file_descriptor_posix.h" #include "third_party/skia/include/core/SkBitmap.h" #endif @@ -387,6 +392,15 @@ struct ViewMsg_PrintPages_Params { std::vector<int> pages; }; +struct ViewMsg_DatabaseOpenFileResponse_Params { +#if defined(OS_WIN) + base::PlatformFile file_handle; // DB file handle +#elif defined(OS_POSIX) + base::FileDescriptor file_handle; // DB file handle + base::FileDescriptor dir_handle; // DB directory handle +#endif +}; + // Parameters to describe a rendered page. struct ViewHostMsg_DidPrintPage_Params { // A shared memory handle to the EMF data. This data can be quite large so a @@ -1853,6 +1867,33 @@ struct ParamTraits<ViewMsg_AudioStreamState> { }; template <> +struct ParamTraits<ViewMsg_DatabaseOpenFileResponse_Params> { + typedef ViewMsg_DatabaseOpenFileResponse_Params param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.file_handle); +#if defined(OS_POSIX) + WriteParam(m, p.dir_handle); +#endif + } + static bool Read(const Message* m, void** iter, param_type* p) { + return ReadParam(m, iter, &p->file_handle) +#if defined(OS_POSIX) + && ReadParam(m, iter, &p->dir_handle) +#endif + ; + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.file_handle, l); +#if defined(OS_POSIX) + l->append(L", "); + LogParam(p.dir_handle, l); +#endif + l->append(L")"); + } +}; + +template <> struct ParamTraits<appcache::Status> { typedef appcache::Status param_type; static void Write(Message* m, const param_type& p) { diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index 679b5c1..4b74407 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -31,6 +31,10 @@ #include "webkit/glue/webcursor.h" #include "webkit/glue/webplugin.h" +#if defined(OS_POSIX) +#include "base/file_descriptor_posix.h" +#endif + // TODO(mpcomplete): rename ViewMsg and ViewHostMsg to something that makes // more sense with our current design. @@ -660,12 +664,12 @@ IPC_BEGIN_MESSAGES(View) // Returns a file handle IPC_MESSAGE_CONTROL2(ViewMsg_DatabaseOpenFileResponse, int32 /* the ID of the message we're replying to */, - base::PlatformFile /* the HANDLE/fd of the DB file */) + ViewMsg_DatabaseOpenFileResponse_Params) - // Returns the error code returned by a call to DeleteFile() + // Returns a SQLite error code IPC_MESSAGE_CONTROL2(ViewMsg_DatabaseDeleteFileResponse, int32 /* the ID of the message we're replying to */, - bool /* whether or not the DB file was deleted */) + int /* SQLite error code */) // Returns the attributes of a file IPC_MESSAGE_CONTROL2(ViewMsg_DatabaseGetFileAttributesResponse, @@ -1679,8 +1683,9 @@ IPC_BEGIN_MESSAGES(ViewHost) int32 /* a unique message ID */) // Asks the browser process to delete a DB file - IPC_MESSAGE_CONTROL2(ViewHostMsg_DatabaseDeleteFile, + IPC_MESSAGE_CONTROL3(ViewHostMsg_DatabaseDeleteFile, FilePath /* the name of the file */, + bool /* whether or not to sync the directory */, int32 /* a unique message ID */) // Asks the browser process to return the attributes of a DB file diff --git a/chrome/renderer/renderer_webkitclient_impl.cc b/chrome/renderer/renderer_webkitclient_impl.cc index 4ae32a34..b6f3228 100644 --- a/chrome/renderer/renderer_webkitclient_impl.cc +++ b/chrome/renderer/renderer_webkitclient_impl.cc @@ -4,6 +4,12 @@ #include "chrome/renderer/renderer_webkitclient_impl.h" +#if defined(USE_SYSTEM_SQLITE) +#include <sqlite3.h> +#else +#include "third_party/sqlite/preprocessed/sqlite3.h" +#endif + #include "base/command_line.h" #include "base/file_path.h" #include "base/platform_file.h" @@ -27,6 +33,10 @@ #include "chrome/renderer/renderer_sandbox_support_linux.h" #endif +#if defined(OS_POSIX) +#include "base/file_descriptor_posix.h" +#endif + using WebKit::WebApplicationCacheHost; using WebKit::WebApplicationCacheHostClient; using WebKit::WebStorageArea; @@ -226,24 +236,48 @@ WebString RendererWebKitClientImpl::SandboxSupport::getFontFamilyForCharacters( //------------------------------------------------------------------------------ base::PlatformFile RendererWebKitClientImpl::databaseOpenFile( - const WebString& file_name, int desired_flags) { + const WebString& file_name, int desired_flags, + base::PlatformFile* dir_handle) { DBMessageFilter* db_message_filter = DBMessageFilter::GetInstance(); int message_id = db_message_filter->GetUniqueID(); - return db_message_filter->SendAndWait( - new ViewHostMsg_DatabaseOpenFile( - FilePath(webkit_glue::WebStringToFilePathString(file_name)), - desired_flags, message_id), - message_id, base::kInvalidPlatformFileValue); + + ViewMsg_DatabaseOpenFileResponse_Params default_response = +#if defined(OS_WIN) + { base::kInvalidPlatformFileValue }; +#elif defined(OS_POSIX) + { base::FileDescriptor(base::kInvalidPlatformFileValue, true), + base::FileDescriptor(base::kInvalidPlatformFileValue, true) }; +#endif + + ViewMsg_DatabaseOpenFileResponse_Params result = + db_message_filter->SendAndWait( + new ViewHostMsg_DatabaseOpenFile( + FilePath(webkit_glue::WebStringToFilePathString(file_name)), + desired_flags, message_id), + message_id, default_response); + +#if defined(OS_WIN) + if (dir_handle) { + *dir_handle = base::kInvalidPlatformFileValue; + } + return result.file_handle; +#elif defined(OS_POSIX) + if (dir_handle) { + *dir_handle = result.dir_handle.fd; + } + return result.file_handle.fd; +#endif } -bool RendererWebKitClientImpl::databaseDeleteFile(const WebString& file_name) { +int RendererWebKitClientImpl::databaseDeleteFile( + const WebString& file_name, bool sync_dir) { DBMessageFilter* db_message_filter = DBMessageFilter::GetInstance(); int message_id = db_message_filter->GetUniqueID(); return db_message_filter->SendAndWait( new ViewHostMsg_DatabaseDeleteFile( - FilePath(webkit_glue::WebStringToFilePathString(file_name)), + FilePath(webkit_glue::WebStringToFilePathString(file_name)), sync_dir, message_id), - message_id, false); + message_id, SQLITE_IOERR_DELETE); } long RendererWebKitClientImpl::databaseGetFileAttributes( diff --git a/chrome/renderer/renderer_webkitclient_impl.h b/chrome/renderer/renderer_webkitclient_impl.h index 633f3cd..d610458 100644 --- a/chrome/renderer/renderer_webkitclient_impl.h +++ b/chrome/renderer/renderer_webkitclient_impl.h @@ -44,8 +44,10 @@ class RendererWebKitClientImpl : public webkit_glue::WebKitClientImpl { virtual WebKit::WebStorageNamespace* createSessionStorageNamespace(); virtual base::PlatformFile databaseOpenFile( - const WebKit::WebString& file_name, int desired_flags); - virtual bool databaseDeleteFile(const WebKit::WebString& file_name); + const WebKit::WebString& file_name, int desired_flags, + base::PlatformFile* dir_handle); + virtual int databaseDeleteFile(const WebKit::WebString& file_name, + bool sync_dir); virtual long databaseGetFileAttributes(const WebKit::WebString& file_name); virtual long long databaseGetFileSize(const WebKit::WebString& file_name); virtual WebKit::WebApplicationCacheHost* createApplicationCacheHost( |