GCC Code Coverage Report


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