OLD | NEW |
---|---|
(Empty) | |
1 // 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" | |
14 #include "base/strings/string_piece.h" | |
15 #include "base/strings/string_util.h" | |
16 #include "base/strings/stringprintf.h" | |
17 | |
18 #if defined(OS_MACOSX) && !defined(OS_IOS) | |
19 #include <CoreFoundation/CoreFoundation.h> | |
20 #include <CoreServices/CoreServices.h> | |
21 | |
22 #include "base/mac/mac_util.h" | |
23 #include "base/mac/scoped_cftyperef.h" | |
24 #endif | |
25 | |
26 namespace sql { | |
27 namespace { | |
28 | |
29 // https://www.sqlite.org/vfs.html - documents the overall VFS system. | |
30 // | |
31 // https://www.sqlite.org/c3ref/vfs.html - VFS methods. This code tucks the | |
32 // wrapped VFS pointer into the wrapper's pAppData pointer. | |
33 // | |
34 // https://www.sqlite.org/c3ref/file.html - instance of an open file. This code | |
35 // allocates a VfsFile for this, which contains a pointer to the wrapped file. | |
36 // Idiomatic SQLite would take the wrapped VFS szOsFile and increase it to store | |
37 // additional data as a prefix. | |
38 | |
39 sqlite3_vfs* GetWrappedVfs(sqlite3_vfs* wrapped_vfs) { | |
40 return static_cast<sqlite3_vfs*>(wrapped_vfs->pAppData); | |
41 } | |
42 | |
43 // NOTE(shess): This structure is allocated by SQLite using malloc. Do not add | |
44 // C++ objects, they will not be correctly constructed and destructed. Instead, | |
45 // manually manage a pointer to a C++ object in Open() and Close(). | |
46 struct VfsFile { | |
47 const sqlite3_io_methods* methods; | |
48 sqlite3_file* wrapped_file; | |
49 }; | |
50 | |
51 VfsFile* AsVfsFile(sqlite3_file* wrapper_file) { | |
52 return reinterpret_cast<VfsFile*>(wrapper_file); | |
53 } | |
54 | |
55 sqlite3_file* GetWrappedFile(sqlite3_file* wrapper_file) { | |
56 return AsVfsFile(wrapper_file)->wrapped_file; | |
57 } | |
58 | |
59 int Close(sqlite3_file* sqlite_file) | |
60 { | |
61 VfsFile* file = AsVfsFile(sqlite_file); | |
62 | |
63 int r = file->wrapped_file->pMethods->xClose(file->wrapped_file); | |
64 sqlite3_free(file->wrapped_file); | |
65 memset(file, '\0', sizeof(*file)); | |
66 return r; | |
67 } | |
68 | |
69 int Read(sqlite3_file* sqlite_file, void* buf, int amt, sqlite3_int64 ofs) | |
70 { | |
71 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file); | |
72 return wrapped_file->pMethods->xRead(wrapped_file, buf, amt, ofs); | |
73 } | |
74 | |
75 int Write(sqlite3_file* sqlite_file, const void* buf, int amt, | |
76 sqlite3_int64 ofs) | |
77 { | |
78 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file); | |
79 return wrapped_file->pMethods->xWrite(wrapped_file, buf, amt, ofs); | |
80 } | |
81 | |
82 int Truncate(sqlite3_file* sqlite_file, sqlite3_int64 size) | |
83 { | |
84 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file); | |
85 return wrapped_file->pMethods->xTruncate(wrapped_file, size); | |
86 } | |
87 | |
88 int Sync(sqlite3_file* sqlite_file, int flags) | |
89 { | |
90 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file); | |
91 return wrapped_file->pMethods->xSync(wrapped_file, flags); | |
92 } | |
93 | |
94 int FileSize(sqlite3_file* sqlite_file, sqlite3_int64* size) | |
95 { | |
96 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file); | |
97 return wrapped_file->pMethods->xFileSize(wrapped_file, size); | |
98 } | |
99 | |
100 int Lock(sqlite3_file* sqlite_file, int file_lock) | |
101 { | |
102 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file); | |
103 return wrapped_file->pMethods->xLock(wrapped_file, file_lock); | |
104 } | |
105 | |
106 int Unlock(sqlite3_file* sqlite_file, int file_lock) | |
107 { | |
108 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file); | |
109 return wrapped_file->pMethods->xUnlock(wrapped_file, file_lock); | |
110 } | |
111 | |
112 int CheckReservedLock(sqlite3_file* sqlite_file, int* result) | |
113 { | |
114 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file); | |
115 return wrapped_file->pMethods->xCheckReservedLock(wrapped_file, result); | |
116 } | |
117 | |
118 int FileControl(sqlite3_file* sqlite_file, int op, void* arg) | |
119 { | |
120 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file); | |
121 return wrapped_file->pMethods->xFileControl(wrapped_file, op, arg); | |
122 } | |
123 | |
124 int SectorSize(sqlite3_file* sqlite_file) | |
125 { | |
126 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file); | |
127 return wrapped_file->pMethods->xSectorSize(wrapped_file); | |
128 } | |
129 | |
130 int DeviceCharacteristics(sqlite3_file* sqlite_file) | |
131 { | |
132 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file); | |
133 return wrapped_file->pMethods->xDeviceCharacteristics(wrapped_file); | |
134 } | |
135 | |
136 int ShmMap(sqlite3_file *sqlite_file, int region, int size, | |
137 int extend, void volatile **pp) { | |
138 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file); | |
139 return wrapped_file->pMethods->xShmMap( | |
140 wrapped_file, region, size, extend, pp); | |
141 } | |
142 | |
143 int ShmLock(sqlite3_file *sqlite_file, int ofst, int n, int flags) { | |
144 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file); | |
145 return wrapped_file->pMethods->xShmLock(wrapped_file, ofst, n, flags); | |
146 } | |
147 | |
148 void ShmBarrier(sqlite3_file *sqlite_file) { | |
149 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file); | |
150 wrapped_file->pMethods->xShmBarrier(wrapped_file); | |
151 } | |
152 | |
153 int ShmUnmap(sqlite3_file *sqlite_file, int del) { | |
154 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file); | |
155 return wrapped_file->pMethods->xShmUnmap(wrapped_file, del); | |
156 } | |
157 | |
158 int Fetch(sqlite3_file *sqlite_file, sqlite3_int64 off, int amt, void **pp) { | |
159 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file); | |
160 return wrapped_file->pMethods->xFetch(wrapped_file, off, amt, pp); | |
161 } | |
162 | |
163 int Unfetch(sqlite3_file *sqlite_file, sqlite3_int64 off, void *p) { | |
164 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file); | |
165 return wrapped_file->pMethods->xUnfetch(wrapped_file, off, p); | |
166 } | |
167 | |
168 #if defined(OS_MACOSX) && !defined(OS_IOS) | |
169 // Helper to convert a POSIX path into a CoreFoundation path. Returns a bare | |
Marijn Kruisselbrink
2017/01/23 23:32:46
nit: update the comment now it no longer returns a
Scott Hess - ex-Googler
2017/01/23 23:47:06
Done.
| |
170 // ref which must be released. | |
171 base::ScopedCFTypeRef<CFURLRef> CFURLRefForPath(const char* path){ | |
172 base::ScopedCFTypeRef<CFStringRef> urlString( | |
173 CFStringCreateWithFileSystemRepresentation(kCFAllocatorDefault, path)); | |
174 base::ScopedCFTypeRef<CFURLRef> url( | |
175 CFURLCreateWithFileSystemPath(kCFAllocatorDefault, urlString, | |
176 kCFURLPOSIXPathStyle, FALSE)); | |
177 return url; | |
178 } | |
179 #endif | |
180 | |
181 int Open(sqlite3_vfs* vfs, const char* file_name, sqlite3_file* wrapper_file, | |
182 int desired_flags, int* used_flags) { | |
183 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs); | |
184 | |
185 sqlite3_file* wrapped_file = static_cast<sqlite3_file*>( | |
186 sqlite3_malloc(wrapped_vfs->szOsFile)); | |
187 if (!wrapped_file) | |
188 return SQLITE_NOMEM; | |
189 | |
190 // NOTE(shess): SQLite's unixOpen() makes assumptions about the structure of | |
191 // |file_name|. Do not pass a local copy, here, only the passed-in value. | |
192 int rc = wrapped_vfs->xOpen(wrapped_vfs, | |
193 file_name, wrapped_file, | |
194 desired_flags, used_flags); | |
195 if (rc != SQLITE_OK) { | |
196 sqlite3_free(wrapped_file); | |
197 return rc; | |
198 } | |
199 // NOTE(shess): Any early exit from here needs to call xClose() on | |
200 // |wrapped_file|. | |
201 | |
202 #if defined(OS_MACOSX) && !defined(OS_IOS) | |
203 // When opening journal files, propagate time-machine exclusion from db. | |
204 static int kJournalFlags = | |
205 SQLITE_OPEN_MAIN_JOURNAL | SQLITE_OPEN_TEMP_JOURNAL | | |
206 SQLITE_OPEN_SUBJOURNAL | SQLITE_OPEN_MASTER_JOURNAL; | |
207 if (file_name && (desired_flags & kJournalFlags)) { | |
208 // https://www.sqlite.org/c3ref/vfs.html indicates that the journal path | |
209 // will have a "-suffix". | |
210 size_t dash_index = base::StringPiece(file_name).rfind('-'); | |
211 if (dash_index != base::StringPiece::npos) { | |
212 std::string db_name(file_name, dash_index); | |
213 base::ScopedCFTypeRef<CFURLRef> db_url(CFURLRefForPath(db_name.c_str())); | |
214 if (CSBackupIsItemExcluded(db_url, nullptr)) { | |
215 base::ScopedCFTypeRef<CFURLRef> journal_url(CFURLRefForPath(file_name)); | |
216 CSBackupSetItemExcluded(journal_url, TRUE, FALSE); | |
217 } | |
218 } | |
219 } | |
220 #endif | |
221 | |
222 // The wrapper instances must support a specific |iVersion|, but there is no | |
223 // explicit guarantee that the wrapped VFS will always vend instances with the | |
224 // same |iVersion| (though I believe this is always the case in practice). | |
225 // Vend a distinct set of IO methods for each version supported. | |
226 // | |
227 // |iVersion| determines what methods SQLite may call on the instance. Having | |
228 // the methods which can't be proxied return an error may cause SQLite to | |
229 // operate differently than if it didn't call those methods at all. Another | |
230 // solution would be to fail if the wrapped file does not have the expected | |
231 // version, which may cause problems on platforms which use the system SQLite | |
232 // (iOS and some Linux distros). | |
233 VfsFile* file = AsVfsFile(wrapper_file); | |
234 file->wrapped_file = wrapped_file; | |
235 if (wrapped_file->pMethods->iVersion == 1) { | |
236 static const sqlite3_io_methods io_methods = { | |
237 1, | |
238 Close, | |
239 Read, | |
240 Write, | |
241 Truncate, | |
242 Sync, | |
243 FileSize, | |
244 Lock, | |
245 Unlock, | |
246 CheckReservedLock, | |
247 FileControl, | |
248 SectorSize, | |
249 DeviceCharacteristics, | |
250 }; | |
251 file->methods = &io_methods; | |
252 } else if (wrapped_file->pMethods->iVersion == 2) { | |
253 static const sqlite3_io_methods io_methods = { | |
254 2, | |
255 Close, | |
256 Read, | |
257 Write, | |
258 Truncate, | |
259 Sync, | |
260 FileSize, | |
261 Lock, | |
262 Unlock, | |
263 CheckReservedLock, | |
264 FileControl, | |
265 SectorSize, | |
266 DeviceCharacteristics, | |
267 // Methods above are valid for version 1. | |
268 ShmMap, | |
269 ShmLock, | |
270 ShmBarrier, | |
271 ShmUnmap, | |
272 }; | |
273 file->methods = &io_methods; | |
274 } else { | |
275 static const sqlite3_io_methods io_methods = { | |
276 3, | |
277 Close, | |
278 Read, | |
279 Write, | |
280 Truncate, | |
281 Sync, | |
282 FileSize, | |
283 Lock, | |
284 Unlock, | |
285 CheckReservedLock, | |
286 FileControl, | |
287 SectorSize, | |
288 DeviceCharacteristics, | |
289 // Methods above are valid for version 1. | |
290 ShmMap, | |
291 ShmLock, | |
292 ShmBarrier, | |
293 ShmUnmap, | |
294 // Methods above are valid for version 2. | |
295 Fetch, | |
296 Unfetch, | |
297 }; | |
298 file->methods = &io_methods; | |
299 } | |
300 return SQLITE_OK; | |
301 } | |
302 | |
303 int Delete(sqlite3_vfs* vfs, const char* file_name, int sync_dir) { | |
304 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs); | |
305 return wrapped_vfs->xDelete(wrapped_vfs, file_name, sync_dir); | |
306 } | |
307 | |
308 int Access(sqlite3_vfs* vfs, const char* file_name, int flag, int* res) { | |
309 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs); | |
310 return wrapped_vfs->xAccess(wrapped_vfs, file_name, flag, res); | |
311 } | |
312 | |
313 int FullPathname(sqlite3_vfs* vfs, const char* relative_path, | |
314 int buf_size, char* absolute_path) { | |
315 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs); | |
316 return wrapped_vfs->xFullPathname( | |
317 wrapped_vfs, relative_path, buf_size, absolute_path); | |
318 } | |
319 | |
320 void* DlOpen(sqlite3_vfs* vfs, const char* filename) { | |
321 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs); | |
322 return wrapped_vfs->xDlOpen(wrapped_vfs, filename); | |
323 } | |
324 | |
325 void DlError(sqlite3_vfs* vfs, int buf_size, char* error_buffer) { | |
326 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs); | |
327 wrapped_vfs->xDlError(wrapped_vfs, buf_size, error_buffer); | |
328 } | |
329 | |
330 void(*DlSym(sqlite3_vfs* vfs, void* handle, const char* sym))(void) { | |
331 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs); | |
332 return wrapped_vfs->xDlSym(wrapped_vfs, handle, sym); | |
333 } | |
334 | |
335 void DlClose(sqlite3_vfs* vfs, void* handle) { | |
336 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs); | |
337 wrapped_vfs->xDlClose(wrapped_vfs, handle); | |
338 } | |
339 | |
340 int Randomness(sqlite3_vfs* vfs, int buf_size, char* buffer) { | |
341 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs); | |
342 return wrapped_vfs->xRandomness(wrapped_vfs, buf_size, buffer); | |
343 } | |
344 | |
345 int Sleep(sqlite3_vfs* vfs, int microseconds) { | |
346 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs); | |
347 return wrapped_vfs->xSleep(wrapped_vfs, microseconds); | |
348 } | |
349 | |
350 int CurrentTime(sqlite3_vfs* vfs, double* now) { | |
351 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs); | |
352 return wrapped_vfs->xCurrentTime(wrapped_vfs, now); | |
353 } | |
354 | |
355 int GetLastError(sqlite3_vfs* vfs, int e, char* s) { | |
356 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs); | |
357 return wrapped_vfs->xGetLastError(wrapped_vfs, e, s); | |
358 } | |
359 | |
360 int CurrentTimeInt64(sqlite3_vfs* vfs, sqlite3_int64* now) { | |
361 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs); | |
362 return wrapped_vfs->xCurrentTimeInt64(wrapped_vfs, now); | |
363 } | |
364 | |
365 int SetSystemCall(sqlite3_vfs* vfs, const char* name, | |
366 sqlite3_syscall_ptr func) { | |
367 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs); | |
368 return wrapped_vfs->xSetSystemCall(wrapped_vfs, name, func); | |
369 } | |
370 | |
371 sqlite3_syscall_ptr GetSystemCall(sqlite3_vfs* vfs, const char* name) { | |
372 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs); | |
373 return wrapped_vfs->xGetSystemCall(wrapped_vfs, name); | |
374 } | |
375 | |
376 const char* NextSystemCall(sqlite3_vfs* vfs, const char* name) { | |
377 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs); | |
378 return wrapped_vfs->xNextSystemCall(wrapped_vfs, name); | |
379 } | |
380 | |
381 } // namespace | |
382 | |
383 sqlite3_vfs* VFSWrapper() { | |
384 const char* kVFSName = "VFSWrapper"; | |
385 | |
386 // Return existing version if already registered. | |
387 { | |
388 sqlite3_vfs* vfs = sqlite3_vfs_find(kVFSName); | |
389 if (vfs != nullptr) | |
390 return vfs; | |
391 } | |
392 | |
393 // Get the default VFS for this platform. If no default VFS, give up. | |
394 sqlite3_vfs* wrapped_vfs = sqlite3_vfs_find(nullptr); | |
395 if (!wrapped_vfs) | |
396 return nullptr; | |
397 | |
398 std::unique_ptr<sqlite3_vfs, std::function<void(sqlite3_vfs*)>> wrapper_vfs( | |
399 static_cast<sqlite3_vfs*>(sqlite3_malloc(sizeof(sqlite3_vfs))), | |
400 [](sqlite3_vfs* v) { | |
401 sqlite3_free(v); | |
402 }); | |
403 memset(wrapper_vfs.get(), '\0', sizeof(sqlite3_vfs)); | |
404 | |
405 // VFS implementations should always work with a SQLite that only knows about | |
406 // earlier versions. | |
407 wrapper_vfs->iVersion = std::min(wrapped_vfs->iVersion, 3); | |
408 | |
409 // Caller of xOpen() allocates this much space. | |
410 wrapper_vfs->szOsFile = sizeof(VfsFile); | |
411 | |
412 wrapper_vfs->mxPathname = wrapped_vfs->mxPathname; | |
413 wrapper_vfs->pNext = nullptr; | |
414 wrapper_vfs->zName = kVFSName; | |
415 | |
416 // Keep a reference to the wrapped vfs for use in methods. | |
417 wrapper_vfs->pAppData = wrapped_vfs; | |
418 | |
419 // VFS methods. | |
420 wrapper_vfs->xOpen = &Open; | |
421 wrapper_vfs->xDelete = &Delete; | |
422 wrapper_vfs->xAccess = &Access; | |
423 wrapper_vfs->xFullPathname = &FullPathname; | |
424 wrapper_vfs->xDlOpen = &DlOpen; | |
425 wrapper_vfs->xDlError = &DlError; | |
426 wrapper_vfs->xDlSym = &DlSym; | |
427 wrapper_vfs->xDlClose = &DlClose; | |
428 wrapper_vfs->xRandomness = &Randomness; | |
429 wrapper_vfs->xSleep = &Sleep; | |
430 wrapper_vfs->xCurrentTime = &CurrentTime; | |
431 wrapper_vfs->xGetLastError = &GetLastError; | |
432 // The methods above are in version 1 of sqlite_vfs. | |
433 // There were VFS implementations with nullptr for |xCurrentTimeInt64|. | |
434 wrapper_vfs->xCurrentTimeInt64 = | |
435 (wrapped_vfs->xCurrentTimeInt64 ? &CurrentTimeInt64 : nullptr); | |
436 // The methods above are in version 2 of sqlite_vfs. | |
437 wrapper_vfs->xSetSystemCall = &SetSystemCall; | |
438 wrapper_vfs->xGetSystemCall = &GetSystemCall; | |
439 wrapper_vfs->xNextSystemCall = &NextSystemCall; | |
440 // The methods above are in version 3 of sqlite_vfs. | |
441 | |
442 if (SQLITE_OK == sqlite3_vfs_register(wrapper_vfs.get(), 0)) { | |
443 ANNOTATE_LEAKING_OBJECT_PTR(wrapper_vfs.get()); | |
444 wrapper_vfs.release(); | |
445 } | |
446 | |
447 return sqlite3_vfs_find(kVFSName); | |
448 } | |
449 | |
450 } // namespace sql | |
OLD | NEW |