blob: 954d488fc0f59d53353af2fc1340d77d742190fe [file] [log] [blame]
shess5f2c3442017-01-24 02:15:101// Copyright (c) 2017 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 "sql/vfs_wrapper.h"
6
7#include <algorithm>
8#include <string>
9#include <vector>
10
11#include "base/debug/leak_annotations.h"
12#include "base/logging.h"
13#include "base/memory/ptr_util.h"
shess3998fbc2017-03-15 16:18:3114#include "base/metrics/histogram_macros.h"
shess5f2c3442017-01-24 02:15:1015#include "base/strings/string_piece.h"
16
17#if defined(OS_MACOSX) && !defined(OS_IOS)
18#include <CoreFoundation/CoreFoundation.h>
19#include <CoreServices/CoreServices.h>
20
21#include "base/mac/mac_util.h"
22#include "base/mac/scoped_cftyperef.h"
23#endif
24
25namespace sql {
26namespace {
27
28// https://www.sqlite.org/vfs.html - documents the overall VFS system.
29//
30// https://www.sqlite.org/c3ref/vfs.html - VFS methods. This code tucks the
31// wrapped VFS pointer into the wrapper's pAppData pointer.
32//
33// https://www.sqlite.org/c3ref/file.html - instance of an open file. This code
34// allocates a VfsFile for this, which contains a pointer to the wrapped file.
35// Idiomatic SQLite would take the wrapped VFS szOsFile and increase it to store
36// additional data as a prefix.
37
shess3998fbc2017-03-15 16:18:3138// This enum must match the numbering from Sqlite.VfsEvents in histograms.xml.
39// Do not reorder or remove items, only add new items before VFS_EVENT_MAX.
40enum VfsEventType {
41 // VFS method xOpen() call.
42 VFS_OPEN = 0,
43
44 // VFS method xDelete() call.
45 VFS_DELETE,
46
47 // VFS method xAccess() call.
48 VFS_ACCESS,
49
50 // VFS method xFullPathname() call.
51 VFS_FULLPATHNAME,
52
53 // I/O method xClose() call, should balance VFS_OPEN.
54 VFS_IO_CLOSE,
55
56 // I/O method xRead() call.
57 VFS_IO_READ,
58
59 // I/O method xWrite() call.
60 VFS_IO_WRITE,
61
62 // I/O method xTruncate() call.
63 VFS_IO_TRUNCATE,
64
65 // I/O method xSync() call.
66 VFS_IO_SYNC,
67
68 // I/O method xFileSize() call.
69 VFS_IO_FILESIZE,
70
71 // I/O method xFetch() call. This is like xRead(), but when using
72 // memory-mapping.
73 VFS_IO_FETCH,
74
75 // Add new items before this one, always keep this one at the end.
76 VFS_EVENT_MAX
77};
78
79// TODO(shess): If the VFS was parameterized, then results could be binned by
80// database. It would require a separate VFS per database, though the variants
81// could all use the same VFS functions.
82void RecordVfsEvent(VfsEventType vfs_event) {
83 UMA_HISTOGRAM_ENUMERATION("Sqlite.Vfs_Events", vfs_event, VFS_EVENT_MAX);
84}
85
shess5f2c3442017-01-24 02:15:1086sqlite3_vfs* GetWrappedVfs(sqlite3_vfs* wrapped_vfs) {
87 return static_cast<sqlite3_vfs*>(wrapped_vfs->pAppData);
88}
89
90// NOTE(shess): This structure is allocated by SQLite using malloc. Do not add
91// C++ objects, they will not be correctly constructed and destructed. Instead,
92// manually manage a pointer to a C++ object in Open() and Close().
93struct VfsFile {
94 const sqlite3_io_methods* methods;
95 sqlite3_file* wrapped_file;
96};
97
98VfsFile* AsVfsFile(sqlite3_file* wrapper_file) {
99 return reinterpret_cast<VfsFile*>(wrapper_file);
100}
101
102sqlite3_file* GetWrappedFile(sqlite3_file* wrapper_file) {
103 return AsVfsFile(wrapper_file)->wrapped_file;
104}
105
106int Close(sqlite3_file* sqlite_file)
107{
shess3998fbc2017-03-15 16:18:31108 RecordVfsEvent(VFS_IO_CLOSE);
109
shess5f2c3442017-01-24 02:15:10110 VfsFile* file = AsVfsFile(sqlite_file);
111
112 int r = file->wrapped_file->pMethods->xClose(file->wrapped_file);
113 sqlite3_free(file->wrapped_file);
114 memset(file, '\0', sizeof(*file));
115 return r;
116}
117
118int Read(sqlite3_file* sqlite_file, void* buf, int amt, sqlite3_int64 ofs)
119{
shess3998fbc2017-03-15 16:18:31120 RecordVfsEvent(VFS_IO_READ);
121 UMA_HISTOGRAM_COUNTS("Sqlite.Vfs_Read", amt);
122
shess5f2c3442017-01-24 02:15:10123 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file);
124 return wrapped_file->pMethods->xRead(wrapped_file, buf, amt, ofs);
125}
126
127int Write(sqlite3_file* sqlite_file, const void* buf, int amt,
128 sqlite3_int64 ofs)
129{
shess3998fbc2017-03-15 16:18:31130 RecordVfsEvent(VFS_IO_WRITE);
131 UMA_HISTOGRAM_COUNTS("Sqlite.Vfs_Write", amt);
132
shess5f2c3442017-01-24 02:15:10133 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file);
134 return wrapped_file->pMethods->xWrite(wrapped_file, buf, amt, ofs);
135}
136
137int Truncate(sqlite3_file* sqlite_file, sqlite3_int64 size)
138{
shess3998fbc2017-03-15 16:18:31139 RecordVfsEvent(VFS_IO_TRUNCATE);
140
shess5f2c3442017-01-24 02:15:10141 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file);
142 return wrapped_file->pMethods->xTruncate(wrapped_file, size);
143}
144
145int Sync(sqlite3_file* sqlite_file, int flags)
146{
shess3998fbc2017-03-15 16:18:31147 RecordVfsEvent(VFS_IO_SYNC);
148
shess5f2c3442017-01-24 02:15:10149 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file);
150 return wrapped_file->pMethods->xSync(wrapped_file, flags);
151}
152
153int FileSize(sqlite3_file* sqlite_file, sqlite3_int64* size)
154{
shess3998fbc2017-03-15 16:18:31155 RecordVfsEvent(VFS_IO_FILESIZE);
156
shess5f2c3442017-01-24 02:15:10157 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file);
158 return wrapped_file->pMethods->xFileSize(wrapped_file, size);
159}
160
161int Lock(sqlite3_file* sqlite_file, int file_lock)
162{
163 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file);
164 return wrapped_file->pMethods->xLock(wrapped_file, file_lock);
165}
166
167int Unlock(sqlite3_file* sqlite_file, int file_lock)
168{
169 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file);
170 return wrapped_file->pMethods->xUnlock(wrapped_file, file_lock);
171}
172
173int CheckReservedLock(sqlite3_file* sqlite_file, int* result)
174{
175 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file);
176 return wrapped_file->pMethods->xCheckReservedLock(wrapped_file, result);
177}
178
179int FileControl(sqlite3_file* sqlite_file, int op, void* arg)
180{
181 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file);
182 return wrapped_file->pMethods->xFileControl(wrapped_file, op, arg);
183}
184
185int SectorSize(sqlite3_file* sqlite_file)
186{
187 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file);
188 return wrapped_file->pMethods->xSectorSize(wrapped_file);
189}
190
191int DeviceCharacteristics(sqlite3_file* sqlite_file)
192{
193 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file);
194 return wrapped_file->pMethods->xDeviceCharacteristics(wrapped_file);
195}
196
197int ShmMap(sqlite3_file *sqlite_file, int region, int size,
198 int extend, void volatile **pp) {
199 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file);
200 return wrapped_file->pMethods->xShmMap(
201 wrapped_file, region, size, extend, pp);
202}
203
204int ShmLock(sqlite3_file *sqlite_file, int ofst, int n, int flags) {
205 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file);
206 return wrapped_file->pMethods->xShmLock(wrapped_file, ofst, n, flags);
207}
208
209void ShmBarrier(sqlite3_file *sqlite_file) {
210 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file);
211 wrapped_file->pMethods->xShmBarrier(wrapped_file);
212}
213
214int ShmUnmap(sqlite3_file *sqlite_file, int del) {
215 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file);
216 return wrapped_file->pMethods->xShmUnmap(wrapped_file, del);
217}
218
219int Fetch(sqlite3_file *sqlite_file, sqlite3_int64 off, int amt, void **pp) {
shess3998fbc2017-03-15 16:18:31220 RecordVfsEvent(VFS_IO_FETCH);
221 UMA_HISTOGRAM_COUNTS("Sqlite.Vfs_Fetch", amt);
222
shess5f2c3442017-01-24 02:15:10223 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file);
224 return wrapped_file->pMethods->xFetch(wrapped_file, off, amt, pp);
225}
226
227int Unfetch(sqlite3_file *sqlite_file, sqlite3_int64 off, void *p) {
228 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file);
229 return wrapped_file->pMethods->xUnfetch(wrapped_file, off, p);
230}
231
232#if defined(OS_MACOSX) && !defined(OS_IOS)
233// Helper to convert a POSIX path into a CoreFoundation path.
234base::ScopedCFTypeRef<CFURLRef> CFURLRefForPath(const char* path){
235 base::ScopedCFTypeRef<CFStringRef> urlString(
236 CFStringCreateWithFileSystemRepresentation(kCFAllocatorDefault, path));
237 base::ScopedCFTypeRef<CFURLRef> url(
238 CFURLCreateWithFileSystemPath(kCFAllocatorDefault, urlString,
239 kCFURLPOSIXPathStyle, FALSE));
240 return url;
241}
242#endif
243
244int Open(sqlite3_vfs* vfs, const char* file_name, sqlite3_file* wrapper_file,
245 int desired_flags, int* used_flags) {
shess3998fbc2017-03-15 16:18:31246 RecordVfsEvent(VFS_OPEN);
247
shess5f2c3442017-01-24 02:15:10248 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs);
249
250 sqlite3_file* wrapped_file = static_cast<sqlite3_file*>(
251 sqlite3_malloc(wrapped_vfs->szOsFile));
252 if (!wrapped_file)
253 return SQLITE_NOMEM;
254
255 // NOTE(shess): SQLite's unixOpen() makes assumptions about the structure of
256 // |file_name|. Do not pass a local copy, here, only the passed-in value.
257 int rc = wrapped_vfs->xOpen(wrapped_vfs,
258 file_name, wrapped_file,
259 desired_flags, used_flags);
260 if (rc != SQLITE_OK) {
261 sqlite3_free(wrapped_file);
262 return rc;
263 }
264 // NOTE(shess): Any early exit from here needs to call xClose() on
265 // |wrapped_file|.
266
267#if defined(OS_MACOSX) && !defined(OS_IOS)
268 // When opening journal files, propagate time-machine exclusion from db.
269 static int kJournalFlags =
270 SQLITE_OPEN_MAIN_JOURNAL | SQLITE_OPEN_TEMP_JOURNAL |
271 SQLITE_OPEN_SUBJOURNAL | SQLITE_OPEN_MASTER_JOURNAL;
272 if (file_name && (desired_flags & kJournalFlags)) {
273 // https://www.sqlite.org/c3ref/vfs.html indicates that the journal path
274 // will have a "-suffix".
275 size_t dash_index = base::StringPiece(file_name).rfind('-');
276 if (dash_index != base::StringPiece::npos) {
277 std::string db_name(file_name, dash_index);
278 base::ScopedCFTypeRef<CFURLRef> db_url(CFURLRefForPath(db_name.c_str()));
279 if (CSBackupIsItemExcluded(db_url, nullptr)) {
280 base::ScopedCFTypeRef<CFURLRef> journal_url(CFURLRefForPath(file_name));
281 CSBackupSetItemExcluded(journal_url, TRUE, FALSE);
282 }
283 }
284 }
285#endif
286
287 // The wrapper instances must support a specific |iVersion|, but there is no
288 // explicit guarantee that the wrapped VFS will always vend instances with the
289 // same |iVersion| (though I believe this is always the case in practice).
290 // Vend a distinct set of IO methods for each version supported.
291 //
292 // |iVersion| determines what methods SQLite may call on the instance. Having
293 // the methods which can't be proxied return an error may cause SQLite to
294 // operate differently than if it didn't call those methods at all. Another
295 // solution would be to fail if the wrapped file does not have the expected
296 // version, which may cause problems on platforms which use the system SQLite
297 // (iOS and some Linux distros).
298 VfsFile* file = AsVfsFile(wrapper_file);
299 file->wrapped_file = wrapped_file;
300 if (wrapped_file->pMethods->iVersion == 1) {
301 static const sqlite3_io_methods io_methods = {
302 1,
303 Close,
304 Read,
305 Write,
306 Truncate,
307 Sync,
308 FileSize,
309 Lock,
310 Unlock,
311 CheckReservedLock,
312 FileControl,
313 SectorSize,
314 DeviceCharacteristics,
315 };
316 file->methods = &io_methods;
317 } else if (wrapped_file->pMethods->iVersion == 2) {
318 static const sqlite3_io_methods io_methods = {
319 2,
320 Close,
321 Read,
322 Write,
323 Truncate,
324 Sync,
325 FileSize,
326 Lock,
327 Unlock,
328 CheckReservedLock,
329 FileControl,
330 SectorSize,
331 DeviceCharacteristics,
332 // Methods above are valid for version 1.
333 ShmMap,
334 ShmLock,
335 ShmBarrier,
336 ShmUnmap,
337 };
338 file->methods = &io_methods;
339 } else {
340 static const sqlite3_io_methods io_methods = {
341 3,
342 Close,
343 Read,
344 Write,
345 Truncate,
346 Sync,
347 FileSize,
348 Lock,
349 Unlock,
350 CheckReservedLock,
351 FileControl,
352 SectorSize,
353 DeviceCharacteristics,
354 // Methods above are valid for version 1.
355 ShmMap,
356 ShmLock,
357 ShmBarrier,
358 ShmUnmap,
359 // Methods above are valid for version 2.
360 Fetch,
361 Unfetch,
362 };
363 file->methods = &io_methods;
364 }
365 return SQLITE_OK;
366}
367
368int Delete(sqlite3_vfs* vfs, const char* file_name, int sync_dir) {
shess3998fbc2017-03-15 16:18:31369 RecordVfsEvent(VFS_DELETE);
370
shess5f2c3442017-01-24 02:15:10371 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs);
372 return wrapped_vfs->xDelete(wrapped_vfs, file_name, sync_dir);
373}
374
375int Access(sqlite3_vfs* vfs, const char* file_name, int flag, int* res) {
shess3998fbc2017-03-15 16:18:31376 RecordVfsEvent(VFS_ACCESS);
377
shess5f2c3442017-01-24 02:15:10378 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs);
379 return wrapped_vfs->xAccess(wrapped_vfs, file_name, flag, res);
380}
381
382int FullPathname(sqlite3_vfs* vfs, const char* relative_path,
383 int buf_size, char* absolute_path) {
shess3998fbc2017-03-15 16:18:31384 RecordVfsEvent(VFS_FULLPATHNAME);
385
shess5f2c3442017-01-24 02:15:10386 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs);
387 return wrapped_vfs->xFullPathname(
388 wrapped_vfs, relative_path, buf_size, absolute_path);
389}
390
391void* DlOpen(sqlite3_vfs* vfs, const char* filename) {
392 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs);
393 return wrapped_vfs->xDlOpen(wrapped_vfs, filename);
394}
395
396void DlError(sqlite3_vfs* vfs, int buf_size, char* error_buffer) {
397 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs);
398 wrapped_vfs->xDlError(wrapped_vfs, buf_size, error_buffer);
399}
400
401void(*DlSym(sqlite3_vfs* vfs, void* handle, const char* sym))(void) {
402 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs);
403 return wrapped_vfs->xDlSym(wrapped_vfs, handle, sym);
404}
405
406void DlClose(sqlite3_vfs* vfs, void* handle) {
407 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs);
408 wrapped_vfs->xDlClose(wrapped_vfs, handle);
409}
410
411int Randomness(sqlite3_vfs* vfs, int buf_size, char* buffer) {
412 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs);
413 return wrapped_vfs->xRandomness(wrapped_vfs, buf_size, buffer);
414}
415
416int Sleep(sqlite3_vfs* vfs, int microseconds) {
417 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs);
418 return wrapped_vfs->xSleep(wrapped_vfs, microseconds);
419}
420
421int CurrentTime(sqlite3_vfs* vfs, double* now) {
422 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs);
423 return wrapped_vfs->xCurrentTime(wrapped_vfs, now);
424}
425
426int GetLastError(sqlite3_vfs* vfs, int e, char* s) {
427 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs);
428 return wrapped_vfs->xGetLastError(wrapped_vfs, e, s);
429}
430
431int CurrentTimeInt64(sqlite3_vfs* vfs, sqlite3_int64* now) {
432 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs);
433 return wrapped_vfs->xCurrentTimeInt64(wrapped_vfs, now);
434}
435
436int SetSystemCall(sqlite3_vfs* vfs, const char* name,
437 sqlite3_syscall_ptr func) {
438 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs);
439 return wrapped_vfs->xSetSystemCall(wrapped_vfs, name, func);
440}
441
442sqlite3_syscall_ptr GetSystemCall(sqlite3_vfs* vfs, const char* name) {
443 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs);
444 return wrapped_vfs->xGetSystemCall(wrapped_vfs, name);
445}
446
447const char* NextSystemCall(sqlite3_vfs* vfs, const char* name) {
448 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs);
449 return wrapped_vfs->xNextSystemCall(wrapped_vfs, name);
450}
451
452} // namespace
453
454sqlite3_vfs* VFSWrapper() {
455 const char* kVFSName = "VFSWrapper";
456
457 // Return existing version if already registered.
458 {
459 sqlite3_vfs* vfs = sqlite3_vfs_find(kVFSName);
460 if (vfs != nullptr)
461 return vfs;
462 }
463
464 // Get the default VFS for this platform. If no default VFS, give up.
465 sqlite3_vfs* wrapped_vfs = sqlite3_vfs_find(nullptr);
466 if (!wrapped_vfs)
467 return nullptr;
468
469 std::unique_ptr<sqlite3_vfs, std::function<void(sqlite3_vfs*)>> wrapper_vfs(
470 static_cast<sqlite3_vfs*>(sqlite3_malloc(sizeof(sqlite3_vfs))),
471 [](sqlite3_vfs* v) {
472 sqlite3_free(v);
473 });
474 memset(wrapper_vfs.get(), '\0', sizeof(sqlite3_vfs));
475
476 // VFS implementations should always work with a SQLite that only knows about
477 // earlier versions.
478 wrapper_vfs->iVersion = std::min(wrapped_vfs->iVersion, 3);
479
480 // Caller of xOpen() allocates this much space.
481 wrapper_vfs->szOsFile = sizeof(VfsFile);
482
483 wrapper_vfs->mxPathname = wrapped_vfs->mxPathname;
484 wrapper_vfs->pNext = nullptr;
485 wrapper_vfs->zName = kVFSName;
486
487 // Keep a reference to the wrapped vfs for use in methods.
488 wrapper_vfs->pAppData = wrapped_vfs;
489
490 // VFS methods.
491 wrapper_vfs->xOpen = &Open;
492 wrapper_vfs->xDelete = &Delete;
493 wrapper_vfs->xAccess = &Access;
494 wrapper_vfs->xFullPathname = &FullPathname;
495 wrapper_vfs->xDlOpen = &DlOpen;
496 wrapper_vfs->xDlError = &DlError;
497 wrapper_vfs->xDlSym = &DlSym;
498 wrapper_vfs->xDlClose = &DlClose;
499 wrapper_vfs->xRandomness = &Randomness;
500 wrapper_vfs->xSleep = &Sleep;
501 wrapper_vfs->xCurrentTime = &CurrentTime;
502 wrapper_vfs->xGetLastError = &GetLastError;
503 // The methods above are in version 1 of sqlite_vfs.
504 // There were VFS implementations with nullptr for |xCurrentTimeInt64|.
505 wrapper_vfs->xCurrentTimeInt64 =
506 (wrapped_vfs->xCurrentTimeInt64 ? &CurrentTimeInt64 : nullptr);
507 // The methods above are in version 2 of sqlite_vfs.
508 wrapper_vfs->xSetSystemCall = &SetSystemCall;
509 wrapper_vfs->xGetSystemCall = &GetSystemCall;
510 wrapper_vfs->xNextSystemCall = &NextSystemCall;
511 // The methods above are in version 3 of sqlite_vfs.
512
513 if (SQLITE_OK == sqlite3_vfs_register(wrapper_vfs.get(), 0)) {
514 ANNOTATE_LEAKING_OBJECT_PTR(wrapper_vfs.get());
515 wrapper_vfs.release();
516 }
517
518 return sqlite3_vfs_find(kVFSName);
519}
520
521} // namespace sql