GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/sqlitevfs.cc
Date: 2024-04-28 02:33:07
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 #include "cvmfs_config.h"
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