4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
7 ** May you do good and not evil.
8 ** May you find forgiveness for yourself and forgive others.
9 ** May you share freely, never taking more than you give.
11 ******************************************************************************
13 ** This file implements a VFS shim that obfuscates database content
14 ** written to disk by applying a CipherStrategy.
18 ** This extension requires SQLite 3.32.0 or later.
23 ** Initialize it using a single API call as follows:
25 ** sqlite3_obfsvfs_init();
27 ** Obfsvfs is a VFS Shim. When loaded, "obfsvfs" becomes the new
28 ** default VFS and it uses the prior default VFS as the next VFS
29 ** down in the stack. This is normally what you want. However, it
30 ** complex situations where multiple VFS shims are being loaded,
31 ** it might be important to ensure that obfsvfs is loaded in the
32 ** correct order so that it sequences itself into the default VFS
33 ** Shim stack in the right order.
37 ** Open database connections using the sqlite3_open_v2() with
38 ** the SQLITE_OPEN_URI flag and using a URI filename that includes
39 ** the query parameter "key=XXXXXXXXXXX..." where the XXXX... consists
40 ** of 64 hexadecimal digits (32 bytes of content).
42 ** Create a new encrypted database by opening a file that does not
43 ** yet exist using the key= query parameter.
47 ** * An obfuscated database must be created as such. There is
48 ** no way to convert an existing database file into an
49 ** obfuscated database file other than to run ".dump" on the
50 ** older database and reimport the SQL text into a new
51 ** obfuscated database.
53 ** * There is no way to change the key value, other than to
54 ** ".dump" and restore the database
56 ** * The database page size must be exactly 8192 bytes. No other
57 ** database page sizes are currently supported.
59 ** * Memory-mapped I/O does not work for obfuscated databases.
60 ** If you think about it, memory-mapped I/O doesn't make any
61 ** sense for obfuscated databases since you have to make a
62 ** copy of the content to deobfuscate anyhow - you might as
63 ** well use normal read()/write().
65 ** * Only the main database, the rollback journal, and WAL file
66 ** are obfuscated. Other temporary files used for things like
67 ** SAVEPOINTs or as part of a large external sort remain
70 ** * Requires SQLite 3.32.0 or later.
75 #include <stdio.h> /* For debugging only */
77 #include "mozilla/dom/quota/IPCStreamCipherStrategy.h"
78 #include "mozilla/ScopeExit.h"
79 #include "nsPrintfCString.h"
82 ** Forward declaration of objects used by this utility
84 using ObfsVfs
= sqlite3_vfs
;
87 ** Useful datatype abbreviations
89 #if !defined(SQLITE_CORE)
90 using u8
= unsigned char;
93 /* Access to a lower-level VFS that (might) implement dynamic loading,
94 ** access to randomness, etc.
96 #define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData))
97 #define ORIGFILE(p) ((sqlite3_file*)(((ObfsFile*)(p)) + 1))
100 ** Database page size for obfuscated databases
102 #define OBFS_PGSZ 8192
104 #define WAL_FRAMEHDRSIZE 24
106 using namespace mozilla
;
107 using namespace mozilla::dom::quota
;
111 sqlite3_file base
; /* IO methods */
112 const char* zFName
; /* Original name of the file */
113 bool inCkpt
; /* Currently doing a checkpoint */
114 ObfsFile
* pPartner
; /* Ptr from WAL to main-db, or from main-db to WAL */
115 void* pTemp
; /* Temporary storage for encoded pages */
116 IPCStreamCipherStrategy
*
117 encryptCipherStrategy
; /* CipherStrategy for encryption */
118 IPCStreamCipherStrategy
*
119 decryptCipherStrategy
; /* CipherStrategy for decryption */
123 ** Methods for ObfsFile
125 static int obfsClose(sqlite3_file
*);
126 static int obfsRead(sqlite3_file
*, void*, int iAmt
, sqlite3_int64 iOfst
);
127 static int obfsWrite(sqlite3_file
*, const void*, int iAmt
, sqlite3_int64 iOfst
);
128 static int obfsTruncate(sqlite3_file
*, sqlite3_int64 size
);
129 static int obfsSync(sqlite3_file
*, int flags
);
130 static int obfsFileSize(sqlite3_file
*, sqlite3_int64
* pSize
);
131 static int obfsLock(sqlite3_file
*, int);
132 static int obfsUnlock(sqlite3_file
*, int);
133 static int obfsCheckReservedLock(sqlite3_file
*, int* pResOut
);
134 static int obfsFileControl(sqlite3_file
*, int op
, void* pArg
);
135 static int obfsSectorSize(sqlite3_file
*);
136 static int obfsDeviceCharacteristics(sqlite3_file
*);
137 static int obfsShmMap(sqlite3_file
*, int iPg
, int pgsz
, int, void volatile**);
138 static int obfsShmLock(sqlite3_file
*, int offset
, int n
, int flags
);
139 static void obfsShmBarrier(sqlite3_file
*);
140 static int obfsShmUnmap(sqlite3_file
*, int deleteFlag
);
141 static int obfsFetch(sqlite3_file
*, sqlite3_int64 iOfst
, int iAmt
, void** pp
);
142 static int obfsUnfetch(sqlite3_file
*, sqlite3_int64 iOfst
, void* p
);
145 ** Methods for ObfsVfs
147 static int obfsOpen(sqlite3_vfs
*, const char*, sqlite3_file
*, int, int*);
148 static int obfsDelete(sqlite3_vfs
*, const char* zPath
, int syncDir
);
149 static int obfsAccess(sqlite3_vfs
*, const char* zPath
, int flags
, int*);
150 static int obfsFullPathname(sqlite3_vfs
*, const char* zPath
, int, char* zOut
);
151 static void* obfsDlOpen(sqlite3_vfs
*, const char* zPath
);
152 static void obfsDlError(sqlite3_vfs
*, int nByte
, char* zErrMsg
);
153 static void (*obfsDlSym(sqlite3_vfs
* pVfs
, void* p
, const char* zSym
))(void);
154 static void obfsDlClose(sqlite3_vfs
*, void*);
155 static int obfsRandomness(sqlite3_vfs
*, int nByte
, char* zBufOut
);
156 static int obfsSleep(sqlite3_vfs
*, int nMicroseconds
);
157 static int obfsCurrentTime(sqlite3_vfs
*, double*);
158 static int obfsGetLastError(sqlite3_vfs
*, int, char*);
159 static int obfsCurrentTimeInt64(sqlite3_vfs
*, sqlite3_int64
*);
160 static int obfsSetSystemCall(sqlite3_vfs
*, const char*, sqlite3_syscall_ptr
);
161 static sqlite3_syscall_ptr
obfsGetSystemCall(sqlite3_vfs
*, const char* z
);
162 static const char* obfsNextSystemCall(sqlite3_vfs
*, const char* zName
);
164 static const sqlite3_io_methods obfs_io_methods
= {
166 obfsClose
, /* xClose */
167 obfsRead
, /* xRead */
168 obfsWrite
, /* xWrite */
169 obfsTruncate
, /* xTruncate */
170 obfsSync
, /* xSync */
171 obfsFileSize
, /* xFileSize */
172 obfsLock
, /* xLock */
173 obfsUnlock
, /* xUnlock */
174 obfsCheckReservedLock
, /* xCheckReservedLock */
175 obfsFileControl
, /* xFileControl */
176 obfsSectorSize
, /* xSectorSize */
177 obfsDeviceCharacteristics
, /* xDeviceCharacteristics */
178 obfsShmMap
, /* xShmMap */
179 obfsShmLock
, /* xShmLock */
180 obfsShmBarrier
, /* xShmBarrier */
181 obfsShmUnmap
, /* xShmUnmap */
182 obfsFetch
, /* xFetch */
183 obfsUnfetch
/* xUnfetch */
186 static constexpr int kKeyBytes
= 32;
187 static constexpr int kIvBytes
= IPCStreamCipherStrategy::BlockPrefixLength
;
188 static constexpr int kClearTextPrefixBytesOnFirstPage
= 32;
189 static constexpr int kReservedBytes
= 32;
190 static constexpr int kBasicBlockSize
= IPCStreamCipherStrategy::BasicBlockSize
;
191 static_assert(kClearTextPrefixBytesOnFirstPage
% kBasicBlockSize
== 0);
192 static_assert(kReservedBytes
% kBasicBlockSize
== 0);
194 /* Obfuscate a page using p->encryptCipherStrategy.
196 ** A new random nonce is created and stored in the last 32 bytes
197 ** of the page. All other bytes of the page are obfuscasted using the
198 ** CipherStrategy. Except, for page-1 (including the SQLite
199 ** database header) the first 32 bytes are not obfuscated
201 ** Return a pointer to the obfuscated content, which is held in the
202 ** p->pTemp buffer. Or return a NULL pointer if something goes wrong.
203 ** Errors are reported using NS_WARNING().
205 static void* obfsEncode(ObfsFile
* p
, /* File containing page to be obfuscated */
206 u8
* a
, /* database page to be obfuscated */
207 int nByte
/* Bytes of content in a[]. Must be a multiple
208 of kBasicBlockSize. */
214 static_assert((kIvBytes
& (kIvBytes
- 1)) == 0);
215 sqlite3_randomness(kIvBytes
, aIv
);
216 pOut
= (u8
*)p
->pTemp
;
217 if (pOut
== nullptr) {
218 pOut
= static_cast<u8
*>(sqlite3_malloc64(nByte
));
219 if (pOut
== nullptr) {
220 NS_WARNING(nsPrintfCString("unable to allocate a buffer in which to"
221 " write obfuscated database content for %s",
228 if (memcmp(a
, "SQLite format 3", 16) == 0) {
229 i
= kClearTextPrefixBytesOnFirstPage
;
230 if (a
[20] != kReservedBytes
) {
231 NS_WARNING(nsPrintfCString("obfuscated database must have reserved-bytes"
237 memcpy(pOut
, a
, kClearTextPrefixBytesOnFirstPage
);
241 const int payloadLength
= nByte
- kReservedBytes
- i
;
242 MOZ_ASSERT(payloadLength
> 0);
243 // XXX I guess this can be done in-place as well, then we don't need the
244 // temporary page at all, I guess?
245 p
->encryptCipherStrategy
->Cipher(
246 Span
{aIv
}, Span
{a
+ i
, static_cast<unsigned>(payloadLength
)},
247 Span
{pOut
+ i
, static_cast<unsigned>(payloadLength
)});
248 memcpy(pOut
+ nByte
- kReservedBytes
, aIv
, kIvBytes
);
253 /* De-obfuscate a page using p->decryptCipherStrategy.
255 ** The deobfuscation is done in-place.
257 ** For pages that begin with the SQLite header text, the first
258 ** 32 bytes are not deobfuscated.
260 static void obfsDecode(ObfsFile
* p
, /* File containing page to be obfuscated */
261 u8
* a
, /* database page to be obfuscated */
262 int nByte
/* Bytes of content in a[]. Must be a multiple
263 of kBasicBlockSize. */
267 if (memcmp(a
, "SQLite format 3", 16) == 0) {
268 i
= kClearTextPrefixBytesOnFirstPage
;
272 const int payloadLength
= nByte
- kReservedBytes
- i
;
273 MOZ_ASSERT(payloadLength
> 0);
274 p
->decryptCipherStrategy
->Cipher(
275 Span
{a
+ nByte
- kReservedBytes
, kIvBytes
},
276 Span
{a
+ i
, static_cast<unsigned>(payloadLength
)},
277 Span
{a
+ i
, static_cast<unsigned>(payloadLength
)});
278 memset(a
+ nByte
- kReservedBytes
, 0, kIvBytes
);
282 ** Close an obfsucated file.
284 static int obfsClose(sqlite3_file
* pFile
) {
285 ObfsFile
* p
= (ObfsFile
*)pFile
;
287 MOZ_ASSERT(p
->pPartner
->pPartner
== p
);
288 p
->pPartner
->pPartner
= nullptr;
289 p
->pPartner
= nullptr;
291 sqlite3_free(p
->pTemp
);
293 delete p
->decryptCipherStrategy
;
294 delete p
->encryptCipherStrategy
;
296 pFile
= ORIGFILE(pFile
);
297 return pFile
->pMethods
->xClose(pFile
);
301 ** Read data from an obfuscated file.
303 ** If the file is less than one full page in length, then return
304 ** a substitute "prototype" page-1. This prototype page one
305 ** specifies a database in WAL mode with an 8192-byte page size
306 ** and a 32-byte reserved-bytes value. Those settings are necessary
307 ** for obfuscation to function correctly.
309 static int obfsRead(sqlite3_file
* pFile
, void* zBuf
, int iAmt
,
310 sqlite_int64 iOfst
) {
312 ObfsFile
* p
= (ObfsFile
*)pFile
;
313 pFile
= ORIGFILE(pFile
);
314 rc
= pFile
->pMethods
->xRead(pFile
, zBuf
, iAmt
, iOfst
);
315 if (rc
== SQLITE_OK
) {
316 if ((iAmt
== OBFS_PGSZ
|| iAmt
== OBFS_PGSZ
+ WAL_FRAMEHDRSIZE
) &&
318 obfsDecode(p
, ((u8
*)zBuf
) + iAmt
- OBFS_PGSZ
, OBFS_PGSZ
);
320 } else if (rc
== SQLITE_IOERR_SHORT_READ
&& iOfst
== 0 && iAmt
>= 100) {
321 static const unsigned char aEmptyDb
[] = {
322 // Offset 0, Size 16, The header string: "SQLite format 3\000"
323 0x53, 0x51, 0x4c, 0x69, 0x74, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x61,
324 0x74, 0x20, 0x33, 0x00,
325 // XXX Add description for other fields
326 0x20, 0x00, 0x02, 0x02, kReservedBytes
, 0x40, 0x20, 0x20, 0x00, 0x00,
327 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
328 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
330 // Offset 52, Size 4, The page number of the largest root b-tree page
331 // when in auto-vacuum or incremental-vacuum modes, or zero otherwise.
332 0x00, 0x00, 0x00, 0x01};
334 memcpy(zBuf
, aEmptyDb
, sizeof(aEmptyDb
));
335 memset(((u8
*)zBuf
) + sizeof(aEmptyDb
), 0, iAmt
- sizeof(aEmptyDb
));
342 ** Write data to an obfuscated file or journal.
344 static int obfsWrite(sqlite3_file
* pFile
, const void* zBuf
, int iAmt
,
345 sqlite_int64 iOfst
) {
346 ObfsFile
* p
= (ObfsFile
*)pFile
;
347 pFile
= ORIGFILE(pFile
);
348 if (iAmt
== OBFS_PGSZ
&& !p
->inCkpt
) {
349 zBuf
= obfsEncode(p
, (u8
*)zBuf
, iAmt
);
350 if (zBuf
== nullptr) {
354 return pFile
->pMethods
->xWrite(pFile
, zBuf
, iAmt
, iOfst
);
358 ** Truncate an obfuscated file.
360 static int obfsTruncate(sqlite3_file
* pFile
, sqlite_int64 size
) {
361 pFile
= ORIGFILE(pFile
);
362 return pFile
->pMethods
->xTruncate(pFile
, size
);
366 ** Sync an obfuscated file.
368 static int obfsSync(sqlite3_file
* pFile
, int flags
) {
369 pFile
= ORIGFILE(pFile
);
370 return pFile
->pMethods
->xSync(pFile
, flags
);
374 ** Return the current file-size of an obfuscated file.
376 static int obfsFileSize(sqlite3_file
* pFile
, sqlite_int64
* pSize
) {
377 ObfsFile
* p
= (ObfsFile
*)pFile
;
379 return pFile
->pMethods
->xFileSize(pFile
, pSize
);
383 ** Lock an obfuscated file.
385 static int obfsLock(sqlite3_file
* pFile
, int eLock
) {
386 pFile
= ORIGFILE(pFile
);
387 return pFile
->pMethods
->xLock(pFile
, eLock
);
391 ** Unlock an obfuscated file.
393 static int obfsUnlock(sqlite3_file
* pFile
, int eLock
) {
394 pFile
= ORIGFILE(pFile
);
395 return pFile
->pMethods
->xUnlock(pFile
, eLock
);
399 ** Check if another file-handle holds a RESERVED lock on an obfuscated file.
401 static int obfsCheckReservedLock(sqlite3_file
* pFile
, int* pResOut
) {
402 pFile
= ORIGFILE(pFile
);
403 return pFile
->pMethods
->xCheckReservedLock(pFile
, pResOut
);
407 ** File control method. For custom operations on an obfuscated file.
409 static int obfsFileControl(sqlite3_file
* pFile
, int op
, void* pArg
) {
411 ObfsFile
* p
= (ObfsFile
*)pFile
;
412 pFile
= ORIGFILE(pFile
);
413 if (op
== SQLITE_FCNTL_PRAGMA
) {
414 char** azArg
= (char**)pArg
;
415 MOZ_ASSERT(azArg
[1] != nullptr);
416 if (azArg
[2] != nullptr && sqlite3_stricmp(azArg
[1], "page_size") == 0) {
417 /* Do not allow page size changes on an obfuscated database */
420 } else if (op
== SQLITE_FCNTL_CKPT_START
|| op
== SQLITE_FCNTL_CKPT_DONE
) {
421 p
->inCkpt
= op
== SQLITE_FCNTL_CKPT_START
;
423 p
->pPartner
->inCkpt
= p
->inCkpt
;
426 rc
= pFile
->pMethods
->xFileControl(pFile
, op
, pArg
);
427 if (rc
== SQLITE_OK
&& op
== SQLITE_FCNTL_VFSNAME
) {
428 *(char**)pArg
= sqlite3_mprintf("obfs/%z", *(char**)pArg
);
434 ** Return the sector-size in bytes for an obfuscated file.
436 static int obfsSectorSize(sqlite3_file
* pFile
) {
437 pFile
= ORIGFILE(pFile
);
438 return pFile
->pMethods
->xSectorSize(pFile
);
442 ** Return the device characteristic flags supported by an obfuscated file.
444 static int obfsDeviceCharacteristics(sqlite3_file
* pFile
) {
445 pFile
= ORIGFILE(pFile
);
446 return pFile
->pMethods
->xDeviceCharacteristics(pFile
);
449 /* Create a shared memory file mapping */
450 static int obfsShmMap(sqlite3_file
* pFile
, int iPg
, int pgsz
, int bExtend
,
451 void volatile** pp
) {
452 pFile
= ORIGFILE(pFile
);
453 return pFile
->pMethods
->xShmMap(pFile
, iPg
, pgsz
, bExtend
, pp
);
456 /* Perform locking on a shared-memory segment */
457 static int obfsShmLock(sqlite3_file
* pFile
, int offset
, int n
, int flags
) {
458 pFile
= ORIGFILE(pFile
);
459 return pFile
->pMethods
->xShmLock(pFile
, offset
, n
, flags
);
462 /* Memory barrier operation on shared memory */
463 static void obfsShmBarrier(sqlite3_file
* pFile
) {
464 pFile
= ORIGFILE(pFile
);
465 pFile
->pMethods
->xShmBarrier(pFile
);
468 /* Unmap a shared memory segment */
469 static int obfsShmUnmap(sqlite3_file
* pFile
, int deleteFlag
) {
470 pFile
= ORIGFILE(pFile
);
471 return pFile
->pMethods
->xShmUnmap(pFile
, deleteFlag
);
474 /* Fetch a page of a memory-mapped file */
475 static int obfsFetch(sqlite3_file
* pFile
, sqlite3_int64 iOfst
, int iAmt
,
481 /* Release a memory-mapped page */
482 static int obfsUnfetch(sqlite3_file
* pFile
, sqlite3_int64 iOfst
, void* pPage
) {
483 pFile
= ORIGFILE(pFile
);
484 return pFile
->pMethods
->xUnfetch(pFile
, iOfst
, pPage
);
488 ** Translate a single byte of Hex into an integer.
489 ** This routine only works if h really is a valid hexadecimal
490 ** character: 0..9a..fA..F
492 static u8
obfsHexToInt(int h
) {
493 MOZ_ASSERT((h
>= '0' && h
<= '9') || (h
>= 'a' && h
<= 'f') ||
494 (h
>= 'A' && h
<= 'F'));
496 h
+= 9 * (1 & (h
>> 6));
498 h
+= 9 * (1 & ~(h
>> 4));
500 return (u8
)(h
& 0xf);
506 ** If the file is an ordinary database file, or a rollback or WAL journal
507 ** file, and if the key=XXXX parameter exists, then try to open the file
508 ** as an obfuscated database. All other open attempts fall through into
509 ** the lower-level VFS shim.
511 ** If the key=XXXX parameter exists but is not 64-bytes of hex key, then
512 ** put an error message in NS_WARNING() and return SQLITE_CANTOPEN.
514 static int obfsOpen(sqlite3_vfs
* pVfs
, const char* zName
, sqlite3_file
* pFile
,
515 int flags
, int* pOutFlags
) {
517 sqlite3_file
* pSubFile
;
518 sqlite3_vfs
* pSubVfs
;
522 pSubVfs
= ORIGVFS(pVfs
);
524 (SQLITE_OPEN_MAIN_DB
| SQLITE_OPEN_WAL
| SQLITE_OPEN_MAIN_JOURNAL
)) {
525 zKey
= sqlite3_uri_parameter(zName
, "key");
529 if (zKey
== nullptr) {
530 return pSubVfs
->xOpen(pSubVfs
, zName
, pFile
, flags
, pOutFlags
);
533 i
< kKeyBytes
&& isxdigit(zKey
[i
* 2]) && isxdigit(zKey
[i
* 2 + 1]);
535 aKey
[i
] = (obfsHexToInt(zKey
[i
* 2]) << 4) | obfsHexToInt(zKey
[i
* 2 + 1]);
537 if (i
!= kKeyBytes
) {
539 nsPrintfCString("invalid query parameter on %s: key=%s", zName
, zKey
)
541 return SQLITE_CANTOPEN
;
543 p
= (ObfsFile
*)pFile
;
544 memset(p
, 0, sizeof(*p
));
546 auto encryptCipherStrategy
= MakeUnique
<IPCStreamCipherStrategy
>();
547 auto decryptCipherStrategy
= MakeUnique
<IPCStreamCipherStrategy
>();
549 auto resetMethods
= MakeScopeExit([pFile
] { pFile
->pMethods
= nullptr; });
551 if (NS_WARN_IF(NS_FAILED(encryptCipherStrategy
->Init(
552 CipherMode::Encrypt
, Span
{aKey
, sizeof(aKey
)},
553 IPCStreamCipherStrategy::MakeBlockPrefix())))) {
557 if (NS_WARN_IF(NS_FAILED(decryptCipherStrategy
->Init(
558 CipherMode::Decrypt
, Span
{aKey
, sizeof(aKey
)})))) {
562 pSubFile
= ORIGFILE(pFile
);
563 p
->base
.pMethods
= &obfs_io_methods
;
564 rc
= pSubVfs
->xOpen(pSubVfs
, zName
, pSubFile
, flags
, pOutFlags
);
569 resetMethods
.release();
571 if (flags
& (SQLITE_OPEN_WAL
| SQLITE_OPEN_MAIN_JOURNAL
)) {
572 sqlite3_file
* pDb
= sqlite3_database_file_object(zName
);
573 p
->pPartner
= (ObfsFile
*)pDb
;
574 MOZ_ASSERT(p
->pPartner
->pPartner
== nullptr);
575 p
->pPartner
->pPartner
= p
;
579 p
->encryptCipherStrategy
= encryptCipherStrategy
.release();
580 p
->decryptCipherStrategy
= decryptCipherStrategy
.release();
586 ** All other VFS methods are pass-thrus.
588 static int obfsDelete(sqlite3_vfs
* pVfs
, const char* zPath
, int syncDir
) {
589 return ORIGVFS(pVfs
)->xDelete(ORIGVFS(pVfs
), zPath
, syncDir
);
591 static int obfsAccess(sqlite3_vfs
* pVfs
, const char* zPath
, int flags
,
593 return ORIGVFS(pVfs
)->xAccess(ORIGVFS(pVfs
), zPath
, flags
, pResOut
);
595 static int obfsFullPathname(sqlite3_vfs
* pVfs
, const char* zPath
, int nOut
,
597 return ORIGVFS(pVfs
)->xFullPathname(ORIGVFS(pVfs
), zPath
, nOut
, zOut
);
599 static void* obfsDlOpen(sqlite3_vfs
* pVfs
, const char* zPath
) {
600 return ORIGVFS(pVfs
)->xDlOpen(ORIGVFS(pVfs
), zPath
);
602 static void obfsDlError(sqlite3_vfs
* pVfs
, int nByte
, char* zErrMsg
) {
603 ORIGVFS(pVfs
)->xDlError(ORIGVFS(pVfs
), nByte
, zErrMsg
);
605 static void (*obfsDlSym(sqlite3_vfs
* pVfs
, void* p
, const char* zSym
))(void) {
606 return ORIGVFS(pVfs
)->xDlSym(ORIGVFS(pVfs
), p
, zSym
);
608 static void obfsDlClose(sqlite3_vfs
* pVfs
, void* pHandle
) {
609 ORIGVFS(pVfs
)->xDlClose(ORIGVFS(pVfs
), pHandle
);
611 static int obfsRandomness(sqlite3_vfs
* pVfs
, int nByte
, char* zBufOut
) {
612 return ORIGVFS(pVfs
)->xRandomness(ORIGVFS(pVfs
), nByte
, zBufOut
);
614 static int obfsSleep(sqlite3_vfs
* pVfs
, int nMicroseconds
) {
615 return ORIGVFS(pVfs
)->xSleep(ORIGVFS(pVfs
), nMicroseconds
);
617 static int obfsCurrentTime(sqlite3_vfs
* pVfs
, double* pTimeOut
) {
618 return ORIGVFS(pVfs
)->xCurrentTime(ORIGVFS(pVfs
), pTimeOut
);
620 static int obfsGetLastError(sqlite3_vfs
* pVfs
, int a
, char* b
) {
621 return ORIGVFS(pVfs
)->xGetLastError(ORIGVFS(pVfs
), a
, b
);
623 static int obfsCurrentTimeInt64(sqlite3_vfs
* pVfs
, sqlite3_int64
* p
) {
624 return ORIGVFS(pVfs
)->xCurrentTimeInt64(ORIGVFS(pVfs
), p
);
626 static int obfsSetSystemCall(sqlite3_vfs
* pVfs
, const char* zName
,
627 sqlite3_syscall_ptr pCall
) {
628 return ORIGVFS(pVfs
)->xSetSystemCall(ORIGVFS(pVfs
), zName
, pCall
);
630 static sqlite3_syscall_ptr
obfsGetSystemCall(sqlite3_vfs
* pVfs
,
632 return ORIGVFS(pVfs
)->xGetSystemCall(ORIGVFS(pVfs
), zName
);
634 static const char* obfsNextSystemCall(sqlite3_vfs
* pVfs
, const char* zName
) {
635 return ORIGVFS(pVfs
)->xNextSystemCall(ORIGVFS(pVfs
), zName
);
641 const char* GetObfuscatingVFSName() { return "obfsvfs"; }
643 UniquePtr
<sqlite3_vfs
> ConstructObfuscatingVFS(const char* aBaseVFSName
) {
644 MOZ_ASSERT(aBaseVFSName
);
646 if (sqlite3_vfs_find(GetObfuscatingVFSName()) != nullptr) {
649 sqlite3_vfs
* const pOrig
= sqlite3_vfs_find(aBaseVFSName
);
650 if (pOrig
== nullptr) {
655 // If the VFS version is higher than the last known one, you should update
656 // this VFS adding appropriate methods for any methods added in the version
658 static constexpr int kLastKnownVfsVersion
= 3;
659 MOZ_ASSERT(pOrig
->iVersion
<= kLastKnownVfsVersion
);
662 const sqlite3_vfs obfs_vfs
= {
663 pOrig
->iVersion
, /* iVersion */
664 static_cast<int>(pOrig
->szOsFile
+ sizeof(ObfsFile
)), /* szOsFile */
665 pOrig
->mxPathname
, /* mxPathname */
667 GetObfuscatingVFSName(), /* zName */
668 pOrig
, /* pAppData */
669 obfsOpen
, /* xOpen */
670 obfsDelete
, /* xDelete */
671 obfsAccess
, /* xAccess */
672 obfsFullPathname
, /* xFullPathname */
673 obfsDlOpen
, /* xDlOpen */
674 obfsDlError
, /* xDlError */
675 obfsDlSym
, /* xDlSym */
676 obfsDlClose
, /* xDlClose */
677 obfsRandomness
, /* xRandomness */
678 obfsSleep
, /* xSleep */
679 obfsCurrentTime
, /* xCurrentTime */
680 obfsGetLastError
, /* xGetLastError */
681 obfsCurrentTimeInt64
, /* xCurrentTimeInt64 */
682 obfsSetSystemCall
, /* xSetSystemCall */
683 obfsGetSystemCall
, /* xGetSystemCall */
684 obfsNextSystemCall
/* xNextSystemCall */
687 return MakeUnique
<sqlite3_vfs
>(obfs_vfs
);
690 } // namespace storage
691 } // namespace mozilla