Directory: | cvmfs/ |
---|---|
File: | cvmfs/sqlitevfs.cc |
Date: | 2025-02-09 02:34:19 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 134 | 225 | 59.6% |
Branches: | 71 | 180 | 39.4% |
Line | Branch | Exec | Source |
---|---|---|---|
1 | /** | ||
2 | * This file is part of the CernVM File System. | ||
3 | * | ||
4 | * An optimized virtual file system layer for the client only. It expects to | ||
5 | * operate on immutable, valid SQlite files. Hence it can do a few | ||
6 | * optimizations. Most notably it doesn't need to know about the path of | ||
7 | * the SQlite file once opened. It works purely on the file descriptor. | ||
8 | */ | ||
9 | |||
10 | #ifndef __STDC_FORMAT_MACROS | ||
11 | #define __STDC_FORMAT_MACROS | ||
12 | #endif | ||
13 | |||
14 | |||
15 | #include "sqlitevfs.h" | ||
16 | |||
17 | #include <dlfcn.h> | ||
18 | #include <errno.h> | ||
19 | #include <fcntl.h> | ||
20 | #include <inttypes.h> | ||
21 | #include <stdint.h> | ||
22 | #include <sys/select.h> | ||
23 | #include <sys/time.h> | ||
24 | #include <sys/types.h> | ||
25 | #include <sys/uio.h> | ||
26 | #include <unistd.h> | ||
27 | |||
28 | #include <cassert> | ||
29 | #include <climits> | ||
30 | #include <cstring> | ||
31 | #include <ctime> | ||
32 | #include <vector> | ||
33 | |||
34 | #include "cache.h" | ||
35 | #include "duplex_sqlite3.h" | ||
36 | #include "statistics.h" | ||
37 | #include "util/logging.h" | ||
38 | #include "util/platform.h" | ||
39 | #include "util/smalloc.h" | ||
40 | #include "util/string.h" | ||
41 | |||
42 | using namespace std; // NOLINT | ||
43 | |||
44 | namespace sqlite { | ||
45 | |||
46 | namespace { | ||
47 | |||
48 | const char *kVfsName = "cvmfs-readonly"; | ||
49 | |||
50 | /** | ||
51 | * The private user data attached to the sqlite_vfs object. | ||
52 | */ | ||
53 | struct VfsRdOnly { | ||
54 | 64 | VfsRdOnly() | |
55 | 64 | : cache_mgr(NULL) | |
56 | 64 | , n_access(NULL) | |
57 | 64 | , no_open(NULL) | |
58 | 64 | , n_rand(NULL) | |
59 | 64 | , sz_rand(NULL) | |
60 | 64 | , n_read(NULL) | |
61 | 64 | , sz_read(NULL) | |
62 | 64 | , n_sleep(NULL) | |
63 | 64 | , sz_sleep(NULL) | |
64 | 64 | , n_time(NULL) | |
65 | 64 | { } | |
66 | CacheManager *cache_mgr; | ||
67 | perf::Counter *n_access; | ||
68 | perf::Counter *no_open; | ||
69 | perf::Counter *n_rand; | ||
70 | perf::Counter *sz_rand; | ||
71 | perf::Counter *n_read; | ||
72 | perf::Counter *sz_read; | ||
73 | perf::Counter *n_sleep; | ||
74 | perf::Counter *sz_sleep; | ||
75 | perf::Counter *n_time; | ||
76 | }; | ||
77 | |||
78 | /** | ||
79 | * This is passed to all operations once a file is opened. | ||
80 | */ | ||
81 | struct VfsRdOnlyFile { | ||
82 | sqlite3_file base; // Base class. Must be first. | ||
83 | VfsRdOnly *vfs_rdonly; | ||
84 | int fd; | ||
85 | uint64_t size; | ||
86 | }; | ||
87 | |||
88 | /** | ||
89 | * File descriptor mappings | ||
90 | */ | ||
91 | std::vector<int> *fd_from_ = NULL; | ||
92 | std::vector<int> *fd_to_ = NULL; | ||
93 | |||
94 | } // anonymous namespace | ||
95 | |||
96 | 369 | static void ApplyFdMap(VfsRdOnlyFile *pFile) { | |
97 | 369 | unsigned N = fd_from_->size(); | |
98 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 369 times.
|
369 | for (unsigned i = 0; i < N; ++i) { |
99 | ✗ | if (pFile->fd == (*fd_from_)[i]) { | |
100 | ✗ | LogCvmfs(kLogSql, kLogDebug, "map fd %d --> %d", | |
101 | ✗ | (*fd_from_)[i], (*fd_to_)[i]); | |
102 | ✗ | pFile->fd = (*fd_to_)[i]; | |
103 | ✗ | fd_from_->erase(fd_from_->begin() + i); | |
104 | ✗ | fd_to_->erase(fd_to_->begin() + i); | |
105 | ✗ | return; | |
106 | } | ||
107 | } | ||
108 | } | ||
109 | |||
110 | |||
111 | 34 | static int VfsRdOnlyClose(sqlite3_file *pFile) { | |
112 | 34 | VfsRdOnlyFile *p = reinterpret_cast<VfsRdOnlyFile *>(pFile); | |
113 | 34 | ApplyFdMap(p); | |
114 | 34 | int retval = p->vfs_rdonly->cache_mgr->Close(p->fd); | |
115 |
1/2✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
|
34 | if (retval == 0) { |
116 | 34 | perf::Dec(p->vfs_rdonly->no_open); | |
117 | 34 | return SQLITE_OK; | |
118 | } | ||
119 | ✗ | return SQLITE_IOERR_CLOSE; | |
120 | } | ||
121 | |||
122 | |||
123 | /** | ||
124 | * On a short read, the remaining bytes must be zero'ed. | ||
125 | * TODO(jblomer): the reads seem to be rather small. Investigate buffered read. | ||
126 | */ | ||
127 | 335 | static int VfsRdOnlyRead( | |
128 | sqlite3_file *pFile, | ||
129 | void *zBuf, | ||
130 | int iAmt, | ||
131 | sqlite_int64 iOfst | ||
132 | ) { | ||
133 | 335 | VfsRdOnlyFile *p = reinterpret_cast<VfsRdOnlyFile *>(pFile); | |
134 | 335 | ApplyFdMap(p); | |
135 | 335 | ssize_t got = p->vfs_rdonly->cache_mgr->Pread(p->fd, zBuf, iAmt, iOfst); | |
136 | 335 | perf::Inc(p->vfs_rdonly->n_read); | |
137 |
1/2✓ Branch 0 taken 335 times.
✗ Branch 1 not taken.
|
335 | if (got == iAmt) { |
138 | 335 | perf::Xadd(p->vfs_rdonly->sz_read, iAmt); | |
139 | 335 | return SQLITE_OK; | |
140 | ✗ | } else if (got < 0) { | |
141 | ✗ | return SQLITE_IOERR_READ; | |
142 | } else { | ||
143 | ✗ | perf::Xadd(p->vfs_rdonly->sz_read, got); | |
144 | ✗ | memset(reinterpret_cast<char *>(zBuf) + got, 0, iAmt - got); | |
145 | ✗ | return SQLITE_IOERR_SHORT_READ; | |
146 | } | ||
147 | } | ||
148 | |||
149 | |||
150 | ✗ | static int VfsRdOnlyWrite( | |
151 | sqlite3_file *pFile __attribute__((unused)), | ||
152 | const void *zBuf __attribute__((unused)), | ||
153 | int iAmt __attribute__((unused)), | ||
154 | sqlite_int64 iOfst __attribute__((unused))) | ||
155 | { | ||
156 | ✗ | return SQLITE_READONLY; | |
157 | } | ||
158 | |||
159 | |||
160 | ✗ | static int VfsRdOnlyTruncate( | |
161 | sqlite3_file *pFile __attribute__((unused)), | ||
162 | sqlite_int64 size __attribute__((unused))) | ||
163 | { | ||
164 | ✗ | return SQLITE_READONLY; | |
165 | } | ||
166 | |||
167 | |||
168 | ✗ | static int VfsRdOnlySync( | |
169 | sqlite3_file *pFile __attribute__((unused)), | ||
170 | int flags __attribute__((unused))) | ||
171 | { | ||
172 | ✗ | return SQLITE_OK; | |
173 | } | ||
174 | |||
175 | |||
176 | 34 | static int VfsRdOnlyFileSize(sqlite3_file *pFile, sqlite_int64 *pSize) { | |
177 | 34 | VfsRdOnlyFile *p = reinterpret_cast<VfsRdOnlyFile *>(pFile); | |
178 | 34 | *pSize = p->size; | |
179 | 34 | return SQLITE_OK; | |
180 | } | ||
181 | |||
182 | |||
183 | 34 | static int VfsRdOnlyLock( | |
184 | sqlite3_file *p __attribute__((unused)), | ||
185 | int level __attribute__((unused)) | ||
186 | ) { | ||
187 | 34 | return SQLITE_OK; | |
188 | } | ||
189 | |||
190 | |||
191 | 34 | static int VfsRdOnlyUnlock( | |
192 | sqlite3_file *p __attribute__((unused)), | ||
193 | int level __attribute__((unused)) | ||
194 | ) { | ||
195 | 34 | return SQLITE_OK; | |
196 | } | ||
197 | |||
198 | |||
199 | ✗ | static int VfsRdOnlyCheckReservedLock( | |
200 | sqlite3_file *p __attribute__((unused)), | ||
201 | int *pResOut | ||
202 | ) { | ||
203 | ✗ | *pResOut = 0; | |
204 | ✗ | return SQLITE_OK; | |
205 | } | ||
206 | |||
207 | |||
208 | /** | ||
209 | * No xFileControl() verbs are implemented by this VFS. | ||
210 | */ | ||
211 | 170 | static int VfsRdOnlyFileControl( | |
212 | sqlite3_file *p __attribute__((unused)), | ||
213 | int op __attribute__((unused)), | ||
214 | void *pArg __attribute__((unused)) | ||
215 | ) { | ||
216 | 170 | return SQLITE_NOTFOUND; | |
217 | } | ||
218 | |||
219 | |||
220 | /** | ||
221 | * A good unit of bytes to read at once. But probably only used for writes. | ||
222 | */ | ||
223 | 34 | static int VfsRdOnlySectorSize(sqlite3_file *p __attribute__((unused))) { | |
224 | 34 | return 4096; | |
225 | } | ||
226 | |||
227 | |||
228 | /** | ||
229 | * Only relevant for writing. | ||
230 | */ | ||
231 | 102 | static int VfsRdOnlyDeviceCharacteristics( | |
232 | sqlite3_file *p __attribute__((unused))) | ||
233 | { | ||
234 | 102 | return 0; | |
235 | } | ||
236 | |||
237 | |||
238 | /** | ||
239 | * Supports only read-only opens. The "file name" has to be in the form of | ||
240 | * '@<file descriptor>', where file descriptor is usable by the cache manager. | ||
241 | */ | ||
242 | 34 | static int VfsRdOnlyOpen( | |
243 | sqlite3_vfs *vfs, | ||
244 | const char *zName, | ||
245 | sqlite3_file *pFile, | ||
246 | int flags, | ||
247 | int *pOutFlags) | ||
248 | { | ||
249 | static const sqlite3_io_methods io_methods = { | ||
250 | 1, // iVersion | ||
251 | VfsRdOnlyClose, | ||
252 | VfsRdOnlyRead, | ||
253 | VfsRdOnlyWrite, | ||
254 | VfsRdOnlyTruncate, | ||
255 | VfsRdOnlySync, | ||
256 | VfsRdOnlyFileSize, | ||
257 | VfsRdOnlyLock, | ||
258 | VfsRdOnlyUnlock, | ||
259 | VfsRdOnlyCheckReservedLock, | ||
260 | VfsRdOnlyFileControl, | ||
261 | VfsRdOnlySectorSize, | ||
262 | VfsRdOnlyDeviceCharacteristics | ||
263 | }; | ||
264 | |||
265 | 34 | VfsRdOnlyFile *p = reinterpret_cast<VfsRdOnlyFile *>(pFile); | |
266 | 34 | CacheManager *cache_mgr = | |
267 | 34 | reinterpret_cast<VfsRdOnly *>(vfs->pAppData)->cache_mgr; | |
268 | // Prevent xClose from being called in case of errors | ||
269 | 34 | p->base.pMethods = NULL; | |
270 | |||
271 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
|
34 | if (flags & SQLITE_OPEN_READWRITE) |
272 | ✗ | return SQLITE_IOERR; | |
273 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
|
34 | if (flags & SQLITE_OPEN_DELETEONCLOSE) |
274 | ✗ | return SQLITE_IOERR; | |
275 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
|
34 | if (flags & SQLITE_OPEN_EXCLUSIVE) |
276 | ✗ | return SQLITE_IOERR; | |
277 | |||
278 |
2/4✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 34 times.
✗ Branch 3 not taken.
|
34 | assert(zName && (zName[0] == '@')); |
279 |
2/4✓ Branch 2 taken 34 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 34 times.
✗ Branch 6 not taken.
|
34 | p->fd = String2Int64(string(&zName[1])); |
280 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
|
34 | if (p->fd < 0) |
281 | ✗ | return SQLITE_IOERR; | |
282 | 34 | int64_t size = cache_mgr->GetSize(p->fd); | |
283 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
|
34 | if (size < 0) { |
284 | ✗ | cache_mgr->Close(p->fd); | |
285 | ✗ | p->fd = -1; | |
286 | ✗ | return SQLITE_IOERR_FSTAT; | |
287 | } | ||
288 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 34 times.
|
34 | if (cache_mgr->Readahead(p->fd) != 0) { |
289 | ✗ | cache_mgr->Close(p->fd); | |
290 | ✗ | p->fd = -1; | |
291 | ✗ | return SQLITE_IOERR; | |
292 | } | ||
293 | 34 | p->size = static_cast<uint64_t>(size); | |
294 |
1/2✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
|
34 | if (pOutFlags) |
295 | 34 | *pOutFlags = flags; | |
296 | 34 | p->vfs_rdonly = reinterpret_cast<VfsRdOnly *>(vfs->pAppData); | |
297 | 34 | p->base.pMethods = &io_methods; | |
298 | 34 | perf::Inc(p->vfs_rdonly->no_open); | |
299 | 34 | LogCvmfs(kLogSql, kLogDebug, "open sqlite3 catalog on fd %d, size %" PRIu64, | |
300 | p->fd, p->size); | ||
301 | 34 | return SQLITE_OK; | |
302 | } | ||
303 | |||
304 | |||
305 | ✗ | static int VfsRdOnlyDelete( | |
306 | sqlite3_vfs* __attribute__((unused)), | ||
307 | const char *zName __attribute__((unused)), | ||
308 | int syncDir __attribute__((unused))) | ||
309 | { | ||
310 | ✗ | return SQLITE_IOERR_DELETE; | |
311 | } | ||
312 | |||
313 | |||
314 | /** | ||
315 | * Cvmfs r/o file catalogs cannot have a write-ahead log or a journal. | ||
316 | */ | ||
317 | 68 | static int VfsRdOnlyAccess( | |
318 | sqlite3_vfs *vfs, | ||
319 | const char *zPath, | ||
320 | int flags, | ||
321 | int *pResOut) | ||
322 | { | ||
323 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 68 times.
|
68 | if (flags == SQLITE_ACCESS_READWRITE) { |
324 | ✗ | *pResOut = 0; | |
325 | ✗ | return SQLITE_OK; | |
326 | } | ||
327 |
22/50✓ Branch 2 taken 68 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 68 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 68 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 34 times.
✓ Branch 12 taken 34 times.
✓ Branch 15 taken 34 times.
✗ Branch 16 not taken.
✓ Branch 19 taken 34 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 34 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 34 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 34 times.
✓ Branch 27 taken 34 times.
✓ Branch 29 taken 34 times.
✓ Branch 30 taken 34 times.
✓ Branch 32 taken 34 times.
✓ Branch 33 taken 34 times.
✓ Branch 35 taken 34 times.
✓ Branch 36 taken 34 times.
✓ Branch 38 taken 68 times.
✗ Branch 39 not taken.
✓ Branch 41 taken 68 times.
✗ Branch 42 not taken.
✓ Branch 44 taken 68 times.
✗ Branch 45 not taken.
✓ Branch 47 taken 68 times.
✗ Branch 48 not taken.
✓ Branch 50 taken 68 times.
✗ Branch 51 not taken.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
✗ Branch 55 not taken.
✗ Branch 56 not taken.
✗ Branch 58 not taken.
✗ Branch 59 not taken.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
✗ Branch 64 not taken.
✗ Branch 65 not taken.
✗ Branch 67 not taken.
✗ Branch 68 not taken.
✗ Branch 70 not taken.
✗ Branch 71 not taken.
✗ Branch 73 not taken.
✗ Branch 74 not taken.
|
68 | if (HasSuffix(zPath, "-wal", false) || HasSuffix(zPath, "-journal", false)) { |
328 | 68 | *pResOut = 0; | |
329 | 68 | return SQLITE_OK; | |
330 | } | ||
331 | |||
332 | // This VFS deals with file descriptors, we know the files are there | ||
333 | ✗ | *pResOut = 0; | |
334 | ✗ | perf::Inc(reinterpret_cast<VfsRdOnly *>(vfs->pAppData)->n_access); | |
335 | ✗ | return SQLITE_OK; | |
336 | } | ||
337 | |||
338 | |||
339 | /** | ||
340 | * Since the path is never stored, there is no need to produce a full path. | ||
341 | */ | ||
342 | 34 | int VfsRdOnlyFullPathname( | |
343 | sqlite3_vfs *vfs __attribute__((unused)), | ||
344 | const char *zPath, | ||
345 | int nOut, | ||
346 | char *zOut) | ||
347 | { | ||
348 | 34 | zOut[nOut-1] = '\0'; | |
349 | 34 | sqlite3_snprintf(nOut, zOut, "%s", zPath); | |
350 | 34 | return SQLITE_OK; | |
351 | } | ||
352 | |||
353 | |||
354 | /** | ||
355 | * Taken from unixRandomness | ||
356 | */ | ||
357 | ✗ | static int VfsRdOnlyRandomness( | |
358 | sqlite3_vfs *vfs, | ||
359 | int nBuf, | ||
360 | char *zBuf) | ||
361 | { | ||
362 | ✗ | assert(static_cast<size_t>(nBuf) >= (sizeof(time_t) + sizeof(int))); | |
363 | ✗ | perf::Inc(reinterpret_cast<VfsRdOnly *>(vfs->pAppData)->n_rand); | |
364 | ✗ | memset(zBuf, 0, nBuf); | |
365 | ✗ | pid_t randomnessPid = getpid(); | |
366 | int fd, got; | ||
367 | ✗ | fd = open("/dev/urandom", O_RDONLY, 0); | |
368 | ✗ | if (fd < 0) { | |
369 | time_t t; | ||
370 | ✗ | time(&t); | |
371 | ✗ | memcpy(zBuf, &t, sizeof(t)); | |
372 | ✗ | memcpy(&zBuf[sizeof(t)], &randomnessPid, sizeof(randomnessPid)); | |
373 | ✗ | assert(sizeof(t) + sizeof(randomnessPid) <= static_cast<size_t>(nBuf)); | |
374 | ✗ | nBuf = sizeof(t) + sizeof(randomnessPid); | |
375 | } else { | ||
376 | do { | ||
377 | ✗ | got = read(fd, zBuf, nBuf); | |
378 | ✗ | } while (got < 0 && errno == EINTR); | |
379 | ✗ | close(fd); | |
380 | } | ||
381 | ✗ | perf::Xadd(reinterpret_cast<VfsRdOnly *>(vfs->pAppData)->sz_rand, nBuf); | |
382 | ✗ | return nBuf; | |
383 | } | ||
384 | |||
385 | |||
386 | /** | ||
387 | * Like SafeSleepMs, avoid conflict with the ALARM signal. | ||
388 | */ | ||
389 | ✗ | static int VfsRdOnlySleep( | |
390 | sqlite3_vfs *vfs, | ||
391 | int microseconds) | ||
392 | { | ||
393 | struct timeval wait_for; | ||
394 | ✗ | wait_for.tv_sec = microseconds / (1000*1000); | |
395 | ✗ | wait_for.tv_usec = microseconds % (1000 * 1000); | |
396 | ✗ | select(0, NULL, NULL, NULL, &wait_for); | |
397 | ✗ | perf::Inc(reinterpret_cast<VfsRdOnly *>(vfs->pAppData)->n_sleep); | |
398 | ✗ | perf::Xadd(reinterpret_cast<VfsRdOnly *>(vfs->pAppData)->sz_sleep, | |
399 | microseconds); | ||
400 | ✗ | return microseconds; | |
401 | } | ||
402 | |||
403 | |||
404 | /** | ||
405 | * Taken from unixCurrentTimeInt64() | ||
406 | */ | ||
407 | ✗ | static int VfsRdOnlyCurrentTimeInt64( | |
408 | sqlite3_vfs *vfs, | ||
409 | sqlite3_int64 *piNow) | ||
410 | { | ||
411 | static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000; | ||
412 | ✗ | int rc = SQLITE_OK; | |
413 | struct timeval sNow; | ||
414 | ✗ | if (gettimeofday(&sNow, 0) == 0) { | |
415 | ✗ | *piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_usec/1000; | |
416 | ✗ | perf::Inc(reinterpret_cast<VfsRdOnly *>(vfs->pAppData)->n_time); | |
417 | } else { | ||
418 | ✗ | rc = SQLITE_ERROR; | |
419 | } | ||
420 | ✗ | return rc; | |
421 | } | ||
422 | |||
423 | |||
424 | /** | ||
425 | * Taken from unixCurrentTime | ||
426 | */ | ||
427 | ✗ | static int VfsRdOnlyCurrentTime( | |
428 | sqlite3_vfs *vfs, | ||
429 | double *prNow) | ||
430 | { | ||
431 | ✗ | sqlite3_int64 i = 0; | |
432 | ✗ | int rc = VfsRdOnlyCurrentTimeInt64(vfs, &i); | |
433 | ✗ | *prNow = i/86400000.0; | |
434 | ✗ | return rc; | |
435 | } | ||
436 | |||
437 | |||
438 | /** | ||
439 | * So far unused by sqlite. | ||
440 | */ | ||
441 | ✗ | static int VfsRdOnlyGetLastError( | |
442 | sqlite3_vfs *vfs __attribute__((unused)), | ||
443 | int not_used1 __attribute__((unused)), | ||
444 | char *not_used2 __attribute__((unused))) | ||
445 | { | ||
446 | ✗ | return 0; | |
447 | } | ||
448 | |||
449 | |||
450 | /** | ||
451 | * Can only be registered once. | ||
452 | */ | ||
453 | 64 | bool RegisterVfsRdOnly( | |
454 | CacheManager *cache_mgr, | ||
455 | perf::Statistics *statistics, | ||
456 | const VfsOptions options) | ||
457 | { | ||
458 | 64 | fd_from_ = new std::vector<int>(); | |
459 | 64 | fd_to_ = new std::vector<int>(); | |
460 | |||
461 | sqlite3_vfs *vfs = reinterpret_cast<sqlite3_vfs *>( | ||
462 | 64 | smalloc(sizeof(sqlite3_vfs))); | |
463 | 64 | memset(vfs, 0, sizeof(sqlite3_vfs)); | |
464 | 64 | VfsRdOnly *vfs_rdonly = new VfsRdOnly(); | |
465 | |||
466 | 64 | vfs->iVersion = 2; | |
467 | 64 | vfs->szOsFile = sizeof(VfsRdOnlyFile); | |
468 | 64 | vfs->mxPathname = PATH_MAX; | |
469 | 64 | vfs->zName = kVfsName; | |
470 | 64 | vfs->pAppData = vfs_rdonly; | |
471 | 64 | vfs->xOpen = VfsRdOnlyOpen; | |
472 | 64 | vfs->xDelete = VfsRdOnlyDelete; | |
473 | 64 | vfs->xAccess = VfsRdOnlyAccess; | |
474 | 64 | vfs->xFullPathname = VfsRdOnlyFullPathname; | |
475 | 64 | vfs->xDlOpen = NULL; | |
476 | 64 | vfs->xDlError = NULL; | |
477 | 64 | vfs->xDlSym = NULL; | |
478 | 64 | vfs->xDlClose = NULL; | |
479 | 64 | vfs->xRandomness = VfsRdOnlyRandomness; | |
480 | 64 | vfs->xSleep = VfsRdOnlySleep; | |
481 | 64 | vfs->xCurrentTime = VfsRdOnlyCurrentTime; | |
482 | 64 | vfs->xGetLastError = VfsRdOnlyGetLastError; | |
483 | 64 | vfs->xCurrentTimeInt64 = VfsRdOnlyCurrentTimeInt64; | |
484 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 64 times.
|
64 | assert(vfs->zName); |
485 | |||
486 | 64 | int retval = sqlite3_vfs_register(vfs, options == kVfsOptDefault); | |
487 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 64 times.
|
64 | if (retval != SQLITE_OK) { |
488 | ✗ | free(const_cast<char *>(vfs->zName)); | |
489 | ✗ | delete vfs_rdonly; | |
490 | ✗ | free(vfs); | |
491 | ✗ | return false; | |
492 | } | ||
493 | |||
494 | 64 | vfs_rdonly->cache_mgr = cache_mgr; | |
495 | 64 | vfs_rdonly->n_access = | |
496 |
3/6✓ Branch 2 taken 64 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 64 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 64 times.
✗ Branch 10 not taken.
|
64 | statistics->Register("sqlite.n_access", "overall number of access() calls"); |
497 | 64 | vfs_rdonly->no_open = | |
498 |
3/6✓ Branch 2 taken 64 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 64 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 64 times.
✗ Branch 10 not taken.
|
64 | statistics->Register("sqlite.no_open", "currently open sqlite files"); |
499 | 64 | vfs_rdonly->n_rand = | |
500 |
3/6✓ Branch 2 taken 64 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 64 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 64 times.
✗ Branch 10 not taken.
|
64 | statistics->Register("sqlite.n_rand", "overall number of random() calls"); |
501 | 64 | vfs_rdonly->sz_rand = | |
502 |
3/6✓ Branch 2 taken 64 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 64 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 64 times.
✗ Branch 10 not taken.
|
64 | statistics->Register("sqlite.sz_rand", "overall number of random bytes"); |
503 | 64 | vfs_rdonly->n_read = | |
504 |
3/6✓ Branch 2 taken 64 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 64 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 64 times.
✗ Branch 10 not taken.
|
64 | statistics->Register("sqlite.n_read", "overall number of read() calls"); |
505 | 64 | vfs_rdonly->sz_read = | |
506 |
3/6✓ Branch 2 taken 64 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 64 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 64 times.
✗ Branch 10 not taken.
|
64 | statistics->Register("sqlite.sz_read", "overall bytes read()"); |
507 | 64 | vfs_rdonly->n_sleep = | |
508 |
3/6✓ Branch 2 taken 64 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 64 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 64 times.
✗ Branch 10 not taken.
|
64 | statistics->Register("sqlite.n_sleep", "overall number of sleep() calls"); |
509 | 64 | vfs_rdonly->sz_sleep = | |
510 |
3/6✓ Branch 2 taken 64 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 64 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 64 times.
✗ Branch 10 not taken.
|
64 | statistics->Register("sqlite.sz_sleep", "overall microseconds slept"); |
511 | 64 | vfs_rdonly->n_time = | |
512 |
3/6✓ Branch 2 taken 64 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 64 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 64 times.
✗ Branch 10 not taken.
|
64 | statistics->Register("sqlite.n_time", "overall number of time() calls"); |
513 | |||
514 | 64 | return true; | |
515 | } | ||
516 | |||
517 | |||
518 | /** | ||
519 | * If the file system was the default VFS, another default VFS is selected by | ||
520 | * SQlite randomly. | ||
521 | */ | ||
522 | 62 | bool UnregisterVfsRdOnly() { | |
523 | 62 | sqlite3_vfs *vfs = sqlite3_vfs_find(kVfsName); | |
524 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 62 times.
|
62 | if (vfs == NULL) |
525 | ✗ | return false; | |
526 | 62 | int retval = sqlite3_vfs_unregister(vfs); | |
527 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 62 times.
|
62 | if (retval != SQLITE_OK) |
528 | ✗ | return false; | |
529 | |||
530 |
1/2✓ Branch 0 taken 62 times.
✗ Branch 1 not taken.
|
62 | delete reinterpret_cast<VfsRdOnly *>(vfs->pAppData); |
531 | 62 | free(vfs); | |
532 | |||
533 |
1/2✓ Branch 0 taken 62 times.
✗ Branch 1 not taken.
|
62 | delete fd_from_; |
534 |
1/2✓ Branch 0 taken 62 times.
✗ Branch 1 not taken.
|
62 | delete fd_to_; |
535 | 62 | fd_from_ = NULL; | |
536 | 62 | fd_to_ = NULL; | |
537 | |||
538 | 62 | return true; | |
539 | } | ||
540 | |||
541 | ✗ | void RegisterFdMapping(int from, int to) { | |
542 | ✗ | fd_from_->push_back(from); | |
543 | ✗ | fd_to_->push_back(to); | |
544 | } | ||
545 | |||
546 | ✗ | void ReplaceCacheManager(CacheManager *new_cache_mgr) { | |
547 | ✗ | sqlite3_vfs *vfs = sqlite3_vfs_find(kVfsName); | |
548 | ✗ | if (vfs == NULL) | |
549 | ✗ | return; | |
550 | ✗ | static_cast<VfsRdOnly *>(vfs->pAppData)->cache_mgr = new_cache_mgr; | |
551 | } | ||
552 | |||
553 | } // namespace sqlite | ||
554 |