[email protected] | da34ae0 | 2009-09-22 20:41:20 | [diff] [blame] | 1 | // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "webkit/database/vfs_backend.h" |
| 6 | |
| 7 | #if defined(USE_SYSTEM_SQLITE) |
| 8 | #include <sqlite3.h> |
| 9 | #else |
| 10 | #include "third_party/sqlite/preprocessed/sqlite3.h" |
| 11 | #endif |
| 12 | |
| 13 | #include "base/file_path.h" |
| 14 | #include "base/file_util.h" |
[email protected] | da34ae0 | 2009-09-22 20:41:20 | [diff] [blame] | 15 | |
| 16 | namespace webkit_database { |
| 17 | |
[email protected] | b5be3f53 | 2009-10-24 01:28:39 | [diff] [blame^] | 18 | bool VfsBackend::OpenFileFlagsAreConsistent(const FilePath& file_name, |
| 19 | const FilePath& db_dir, |
| 20 | int desired_flags) { |
[email protected] | da34ae0 | 2009-09-22 20:41:20 | [diff] [blame] | 21 | // Is this a request for a temp file? |
| 22 | // We should be able to delete temp files when they're closed |
| 23 | // and create them as needed |
| 24 | if ((file_name == db_dir) && |
| 25 | (!(desired_flags & SQLITE_OPEN_DELETEONCLOSE) || |
| 26 | !(desired_flags & SQLITE_OPEN_CREATE))) { |
| 27 | return false; |
| 28 | } |
| 29 | |
| 30 | const int file_type = desired_flags & 0x00007F00; |
| 31 | const bool is_exclusive = (desired_flags & SQLITE_OPEN_EXCLUSIVE) != 0; |
| 32 | const bool is_delete = (desired_flags & SQLITE_OPEN_DELETEONCLOSE) != 0; |
| 33 | const bool is_create = (desired_flags & SQLITE_OPEN_CREATE) != 0; |
| 34 | const bool is_read_only = (desired_flags & SQLITE_OPEN_READONLY) != 0; |
| 35 | const bool is_read_write = (desired_flags & SQLITE_OPEN_READWRITE) != 0; |
| 36 | |
[email protected] | b5be3f53 | 2009-10-24 01:28:39 | [diff] [blame^] | 37 | // All files should be opened either read-write or read-only, but not both. |
| 38 | if (is_read_only == is_read_write) |
[email protected] | da34ae0 | 2009-09-22 20:41:20 | [diff] [blame] | 39 | return false; |
[email protected] | da34ae0 | 2009-09-22 20:41:20 | [diff] [blame] | 40 | |
[email protected] | b5be3f53 | 2009-10-24 01:28:39 | [diff] [blame^] | 41 | // If a new file is created, it must also be writable. |
| 42 | if (is_create && !is_read_write) |
[email protected] | da34ae0 | 2009-09-22 20:41:20 | [diff] [blame] | 43 | return false; |
[email protected] | da34ae0 | 2009-09-22 20:41:20 | [diff] [blame] | 44 | |
[email protected] | b5be3f53 | 2009-10-24 01:28:39 | [diff] [blame^] | 45 | // If we're accessing an existing file, we cannot give exclusive access, and |
| 46 | // we can't delete it. |
| 47 | if ((is_exclusive || is_delete) && !is_create) |
[email protected] | da34ae0 | 2009-09-22 20:41:20 | [diff] [blame] | 48 | return false; |
[email protected] | da34ae0 | 2009-09-22 20:41:20 | [diff] [blame] | 49 | |
| 50 | // The main DB, main journal and master journal cannot be auto-deleted. |
[email protected] | b5be3f53 | 2009-10-24 01:28:39 | [diff] [blame^] | 51 | if (is_delete && ((file_type == SQLITE_OPEN_MAIN_DB) || |
| 52 | (file_type == SQLITE_OPEN_MAIN_JOURNAL) || |
| 53 | (file_type == SQLITE_OPEN_MASTER_JOURNAL))) { |
[email protected] | da34ae0 | 2009-09-22 20:41:20 | [diff] [blame] | 54 | return false; |
| 55 | } |
| 56 | |
| 57 | // Make sure we're opening the DB directory or that a file type is set. |
[email protected] | b5be3f53 | 2009-10-24 01:28:39 | [diff] [blame^] | 58 | return (file_type == SQLITE_OPEN_MAIN_DB) || |
| 59 | (file_type == SQLITE_OPEN_TEMP_DB) || |
| 60 | (file_type == SQLITE_OPEN_MAIN_JOURNAL) || |
| 61 | (file_type == SQLITE_OPEN_TEMP_JOURNAL) || |
| 62 | (file_type == SQLITE_OPEN_SUBJOURNAL) || |
| 63 | (file_type == SQLITE_OPEN_MASTER_JOURNAL) || |
| 64 | (file_type == SQLITE_OPEN_TRANSIENT_DB); |
[email protected] | da34ae0 | 2009-09-22 20:41:20 | [diff] [blame] | 65 | } |
| 66 | |
[email protected] | b5be3f53 | 2009-10-24 01:28:39 | [diff] [blame^] | 67 | void VfsBackend::OpenFile(const FilePath& file_name, |
| 68 | const FilePath& db_dir, |
| 69 | int desired_flags, |
| 70 | base::ProcessHandle handle, |
| 71 | base::PlatformFile* target_handle, |
| 72 | base::PlatformFile* target_dir_handle) { |
[email protected] | da34ae0 | 2009-09-22 20:41:20 | [diff] [blame] | 73 | // Verify the flags for consistency and create the database |
| 74 | // directory if it doesn't exist. |
| 75 | if (OpenFileFlagsAreConsistent(file_name, db_dir, desired_flags) && |
| 76 | file_util::CreateDirectory(db_dir)) { |
| 77 | int flags = 0; |
| 78 | flags |= base::PLATFORM_FILE_READ; |
[email protected] | b5be3f53 | 2009-10-24 01:28:39 | [diff] [blame^] | 79 | if (desired_flags & SQLITE_OPEN_READWRITE) |
[email protected] | da34ae0 | 2009-09-22 20:41:20 | [diff] [blame] | 80 | flags |= base::PLATFORM_FILE_WRITE; |
[email protected] | da34ae0 | 2009-09-22 20:41:20 | [diff] [blame] | 81 | |
| 82 | if (!(desired_flags & SQLITE_OPEN_MAIN_DB)) { |
| 83 | flags |= base::PLATFORM_FILE_EXCLUSIVE_READ | |
| 84 | base::PLATFORM_FILE_EXCLUSIVE_WRITE; |
| 85 | } |
| 86 | |
[email protected] | b5be3f53 | 2009-10-24 01:28:39 | [diff] [blame^] | 87 | flags |= ((desired_flags & SQLITE_OPEN_CREATE) ? |
| 88 | base::PLATFORM_FILE_OPEN_ALWAYS : base::PLATFORM_FILE_OPEN); |
[email protected] | da34ae0 | 2009-09-22 20:41:20 | [diff] [blame] | 89 | |
| 90 | if (desired_flags & SQLITE_OPEN_EXCLUSIVE) { |
| 91 | flags |= base::PLATFORM_FILE_EXCLUSIVE_READ | |
| 92 | base::PLATFORM_FILE_EXCLUSIVE_WRITE; |
| 93 | } |
| 94 | |
| 95 | if (desired_flags & SQLITE_OPEN_DELETEONCLOSE) { |
| 96 | flags |= base::PLATFORM_FILE_TEMPORARY | base::PLATFORM_FILE_HIDDEN | |
| 97 | base::PLATFORM_FILE_DELETE_ON_CLOSE; |
| 98 | } |
| 99 | |
| 100 | // If this is a request for a handle to a temp file, get a unique file name |
| 101 | FilePath db_file_name; |
| 102 | if (file_name == db_dir) { |
[email protected] | b5be3f53 | 2009-10-24 01:28:39 | [diff] [blame^] | 103 | if (!file_util::CreateTemporaryFileInDir(db_dir, &db_file_name)) |
[email protected] | da34ae0 | 2009-09-22 20:41:20 | [diff] [blame] | 104 | db_file_name = FilePath(); |
[email protected] | da34ae0 | 2009-09-22 20:41:20 | [diff] [blame] | 105 | } else { |
| 106 | db_file_name = file_name; |
| 107 | } |
| 108 | |
| 109 | // Try to open/create the DB file. |
[email protected] | b5be3f53 | 2009-10-24 01:28:39 | [diff] [blame^] | 110 | base::PlatformFile file_handle = (db_file_name.empty() ? |
| 111 | base::kInvalidPlatformFileValue : |
[email protected] | da34ae0 | 2009-09-22 20:41:20 | [diff] [blame] | 112 | base::CreatePlatformFile(db_file_name.ToWStringHack(), flags, NULL)); |
| 113 | if (file_handle != base::kInvalidPlatformFileValue) { |
| 114 | #if defined(OS_WIN) |
| 115 | // Duplicate the file handle. |
| 116 | if (!DuplicateHandle(GetCurrentProcess(), file_handle, |
| 117 | handle, target_handle, 0, false, |
| 118 | DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { |
| 119 | // file_handle is closed whether or not DuplicateHandle succeeds. |
| 120 | *target_handle = INVALID_HANDLE_VALUE; |
| 121 | } |
| 122 | #elif defined(OS_POSIX) |
| 123 | *target_handle = file_handle; |
| 124 | |
| 125 | int file_type = desired_flags & 0x00007F00; |
| 126 | bool creating_new_file = (desired_flags & SQLITE_OPEN_CREATE); |
| 127 | if (creating_new_file && ((file_type == SQLITE_OPEN_MASTER_JOURNAL) || |
| 128 | (file_type == SQLITE_OPEN_MAIN_JOURNAL))) { |
| 129 | // We return a handle to the containing directory because on POSIX |
| 130 | // systems the VFS might want to fsync it after changing a file. |
| 131 | // By returning it here, we avoid an extra IPC call. |
| 132 | *target_dir_handle = base::CreatePlatformFile( |
| 133 | db_dir.ToWStringHack(), |
| 134 | base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ, NULL); |
| 135 | if (*target_dir_handle == base::kInvalidPlatformFileValue) { |
| 136 | base::ClosePlatformFile(*target_handle); |
| 137 | *target_handle = base::kInvalidPlatformFileValue; |
| 138 | } |
| 139 | } |
| 140 | #endif |
| 141 | } |
| 142 | } |
| 143 | } |
| 144 | |
[email protected] | b5be3f53 | 2009-10-24 01:28:39 | [diff] [blame^] | 145 | int VfsBackend::DeleteFile(const FilePath& file_name, |
| 146 | const FilePath& db_dir, |
| 147 | bool sync_dir) { |
| 148 | if (!file_util::PathExists(file_name)) |
[email protected] | da34ae0 | 2009-09-22 20:41:20 | [diff] [blame] | 149 | return SQLITE_OK; |
[email protected] | b5be3f53 | 2009-10-24 01:28:39 | [diff] [blame^] | 150 | if (!file_util::Delete(file_name, false)) |
[email protected] | da34ae0 | 2009-09-22 20:41:20 | [diff] [blame] | 151 | return SQLITE_IOERR_DELETE; |
[email protected] | da34ae0 | 2009-09-22 20:41:20 | [diff] [blame] | 152 | |
| 153 | int error_code = SQLITE_OK; |
| 154 | #if defined(OS_POSIX) |
| 155 | if (sync_dir) { |
| 156 | base::PlatformFile dir_fd = base::CreatePlatformFile( |
| 157 | db_dir.ToWStringHack(), base::PLATFORM_FILE_READ, NULL); |
| 158 | if (dir_fd == base::kInvalidPlatformFileValue) { |
| 159 | error_code = SQLITE_CANTOPEN; |
| 160 | } else { |
[email protected] | b5be3f53 | 2009-10-24 01:28:39 | [diff] [blame^] | 161 | if (fsync(dir_fd)) |
[email protected] | da34ae0 | 2009-09-22 20:41:20 | [diff] [blame] | 162 | error_code = SQLITE_IOERR_DIR_FSYNC; |
[email protected] | da34ae0 | 2009-09-22 20:41:20 | [diff] [blame] | 163 | base::ClosePlatformFile(dir_fd); |
| 164 | } |
| 165 | } |
| 166 | #endif |
| 167 | return error_code; |
| 168 | } |
| 169 | |
| 170 | uint32 VfsBackend::GetFileAttributes(const FilePath& file_name) { |
| 171 | #if defined(OS_WIN) |
| 172 | uint32 attributes = ::GetFileAttributes(file_name.value().c_str()); |
| 173 | #elif defined(OS_POSIX) |
| 174 | uint32 attributes = 0; |
[email protected] | b5be3f53 | 2009-10-24 01:28:39 | [diff] [blame^] | 175 | if (!access(file_name.value().c_str(), R_OK)) |
[email protected] | da34ae0 | 2009-09-22 20:41:20 | [diff] [blame] | 176 | attributes |= static_cast<uint32>(R_OK); |
[email protected] | b5be3f53 | 2009-10-24 01:28:39 | [diff] [blame^] | 177 | if (!access(file_name.value().c_str(), W_OK)) |
[email protected] | da34ae0 | 2009-09-22 20:41:20 | [diff] [blame] | 178 | attributes |= static_cast<uint32>(W_OK); |
[email protected] | b5be3f53 | 2009-10-24 01:28:39 | [diff] [blame^] | 179 | if (!attributes) |
[email protected] | da34ae0 | 2009-09-22 20:41:20 | [diff] [blame] | 180 | attributes = -1; |
[email protected] | da34ae0 | 2009-09-22 20:41:20 | [diff] [blame] | 181 | #endif |
| 182 | return attributes; |
| 183 | } |
| 184 | |
| 185 | int64 VfsBackend::GetFileSize(const FilePath& file_name) { |
| 186 | int64 size = 0; |
| 187 | return (file_util::GetFileSize(file_name, &size) ? size : 0); |
| 188 | } |
| 189 | |
[email protected] | b5be3f53 | 2009-10-24 01:28:39 | [diff] [blame^] | 190 | } // namespace webkit_database |