GCC Code Coverage Report


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