blob: 8d84dbdfc1e01acdf122440691e462cd5173246a [file] [log] [blame]
[email protected]da34ae02009-09-22 20:41:201// 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]da34ae02009-09-22 20:41:2015
16namespace webkit_database {
17
[email protected]b5be3f532009-10-24 01:28:3918bool VfsBackend::OpenFileFlagsAreConsistent(const FilePath& file_name,
19 const FilePath& db_dir,
20 int desired_flags) {
[email protected]da34ae02009-09-22 20:41:2021 // 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]b5be3f532009-10-24 01:28:3937 // All files should be opened either read-write or read-only, but not both.
38 if (is_read_only == is_read_write)
[email protected]da34ae02009-09-22 20:41:2039 return false;
[email protected]da34ae02009-09-22 20:41:2040
[email protected]b5be3f532009-10-24 01:28:3941 // If a new file is created, it must also be writable.
42 if (is_create && !is_read_write)
[email protected]da34ae02009-09-22 20:41:2043 return false;
[email protected]da34ae02009-09-22 20:41:2044
[email protected]b5be3f532009-10-24 01:28:3945 // 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]da34ae02009-09-22 20:41:2048 return false;
[email protected]da34ae02009-09-22 20:41:2049
50 // The main DB, main journal and master journal cannot be auto-deleted.
[email protected]b5be3f532009-10-24 01:28:3951 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]da34ae02009-09-22 20:41:2054 return false;
55 }
56
57 // Make sure we're opening the DB directory or that a file type is set.
[email protected]b5be3f532009-10-24 01:28:3958 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]da34ae02009-09-22 20:41:2065}
66
[email protected]b5be3f532009-10-24 01:28:3967void 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]da34ae02009-09-22 20:41:2073 // 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]b5be3f532009-10-24 01:28:3979 if (desired_flags & SQLITE_OPEN_READWRITE)
[email protected]da34ae02009-09-22 20:41:2080 flags |= base::PLATFORM_FILE_WRITE;
[email protected]da34ae02009-09-22 20:41:2081
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]b5be3f532009-10-24 01:28:3987 flags |= ((desired_flags & SQLITE_OPEN_CREATE) ?
88 base::PLATFORM_FILE_OPEN_ALWAYS : base::PLATFORM_FILE_OPEN);
[email protected]da34ae02009-09-22 20:41:2089
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]b5be3f532009-10-24 01:28:39103 if (!file_util::CreateTemporaryFileInDir(db_dir, &db_file_name))
[email protected]da34ae02009-09-22 20:41:20104 db_file_name = FilePath();
[email protected]da34ae02009-09-22 20:41:20105 } else {
106 db_file_name = file_name;
107 }
108
109 // Try to open/create the DB file.
[email protected]b5be3f532009-10-24 01:28:39110 base::PlatformFile file_handle = (db_file_name.empty() ?
111 base::kInvalidPlatformFileValue :
[email protected]da34ae02009-09-22 20:41:20112 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]b5be3f532009-10-24 01:28:39145int VfsBackend::DeleteFile(const FilePath& file_name,
146 const FilePath& db_dir,
147 bool sync_dir) {
148 if (!file_util::PathExists(file_name))
[email protected]da34ae02009-09-22 20:41:20149 return SQLITE_OK;
[email protected]b5be3f532009-10-24 01:28:39150 if (!file_util::Delete(file_name, false))
[email protected]da34ae02009-09-22 20:41:20151 return SQLITE_IOERR_DELETE;
[email protected]da34ae02009-09-22 20:41:20152
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]b5be3f532009-10-24 01:28:39161 if (fsync(dir_fd))
[email protected]da34ae02009-09-22 20:41:20162 error_code = SQLITE_IOERR_DIR_FSYNC;
[email protected]da34ae02009-09-22 20:41:20163 base::ClosePlatformFile(dir_fd);
164 }
165 }
166#endif
167 return error_code;
168}
169
170uint32 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]b5be3f532009-10-24 01:28:39175 if (!access(file_name.value().c_str(), R_OK))
[email protected]da34ae02009-09-22 20:41:20176 attributes |= static_cast<uint32>(R_OK);
[email protected]b5be3f532009-10-24 01:28:39177 if (!access(file_name.value().c_str(), W_OK))
[email protected]da34ae02009-09-22 20:41:20178 attributes |= static_cast<uint32>(W_OK);
[email protected]b5be3f532009-10-24 01:28:39179 if (!attributes)
[email protected]da34ae02009-09-22 20:41:20180 attributes = -1;
[email protected]da34ae02009-09-22 20:41:20181#endif
182 return attributes;
183}
184
185int64 VfsBackend::GetFileSize(const FilePath& file_name) {
186 int64 size = 0;
187 return (file_util::GetFileSize(file_name, &size) ? size : 0);
188}
189
[email protected]b5be3f532009-10-24 01:28:39190} // namespace webkit_database