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 0x53, 0x51, 0x4c, 0x69, 0x74, 0x65, 0x20, 0x66,
323 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x20, 0x33, 0x00,
324 0x20, 0x00, 0x02, 0x02, kReservedBytes
, 0x40, 0x20, 0x20,
325 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01};
326 memcpy(zBuf
, aEmptyDb
, sizeof(aEmptyDb
));
327 memset(((u8
*)zBuf
) + sizeof(aEmptyDb
), 0, iAmt
- sizeof(aEmptyDb
));
334 ** Write data to an obfuscated file or journal.
336 static int obfsWrite(sqlite3_file
* pFile
, const void* zBuf
, int iAmt
,
337 sqlite_int64 iOfst
) {
338 ObfsFile
* p
= (ObfsFile
*)pFile
;
339 pFile
= ORIGFILE(pFile
);
340 if (iAmt
== OBFS_PGSZ
&& !p
->inCkpt
) {
341 zBuf
= obfsEncode(p
, (u8
*)zBuf
, iAmt
);
342 if (zBuf
== nullptr) {
346 return pFile
->pMethods
->xWrite(pFile
, zBuf
, iAmt
, iOfst
);
350 ** Truncate an obfuscated file.
352 static int obfsTruncate(sqlite3_file
* pFile
, sqlite_int64 size
) {
353 pFile
= ORIGFILE(pFile
);
354 return pFile
->pMethods
->xTruncate(pFile
, size
);
358 ** Sync an obfuscated file.
360 static int obfsSync(sqlite3_file
* pFile
, int flags
) {
361 pFile
= ORIGFILE(pFile
);
362 return pFile
->pMethods
->xSync(pFile
, flags
);
366 ** Return the current file-size of an obfuscated file.
368 static int obfsFileSize(sqlite3_file
* pFile
, sqlite_int64
* pSize
) {
369 ObfsFile
* p
= (ObfsFile
*)pFile
;
371 return pFile
->pMethods
->xFileSize(pFile
, pSize
);
375 ** Lock an obfuscated file.
377 static int obfsLock(sqlite3_file
* pFile
, int eLock
) {
378 pFile
= ORIGFILE(pFile
);
379 return pFile
->pMethods
->xLock(pFile
, eLock
);
383 ** Unlock an obfuscated file.
385 static int obfsUnlock(sqlite3_file
* pFile
, int eLock
) {
386 pFile
= ORIGFILE(pFile
);
387 return pFile
->pMethods
->xUnlock(pFile
, eLock
);
391 ** Check if another file-handle holds a RESERVED lock on an obfuscated file.
393 static int obfsCheckReservedLock(sqlite3_file
* pFile
, int* pResOut
) {
394 pFile
= ORIGFILE(pFile
);
395 return pFile
->pMethods
->xCheckReservedLock(pFile
, pResOut
);
399 ** File control method. For custom operations on an obfuscated file.
401 static int obfsFileControl(sqlite3_file
* pFile
, int op
, void* pArg
) {
403 ObfsFile
* p
= (ObfsFile
*)pFile
;
404 pFile
= ORIGFILE(pFile
);
405 if (op
== SQLITE_FCNTL_PRAGMA
) {
406 char** azArg
= (char**)pArg
;
407 MOZ_ASSERT(azArg
[1] != nullptr);
408 if (azArg
[2] != nullptr && sqlite3_stricmp(azArg
[1], "page_size") == 0) {
409 /* Do not allow page size changes on an obfuscated database */
412 } else if (op
== SQLITE_FCNTL_CKPT_START
|| op
== SQLITE_FCNTL_CKPT_DONE
) {
413 p
->inCkpt
= op
== SQLITE_FCNTL_CKPT_START
;
415 p
->pPartner
->inCkpt
= p
->inCkpt
;
418 rc
= pFile
->pMethods
->xFileControl(pFile
, op
, pArg
);
419 if (rc
== SQLITE_OK
&& op
== SQLITE_FCNTL_VFSNAME
) {
420 *(char**)pArg
= sqlite3_mprintf("obfs/%z", *(char**)pArg
);
426 ** Return the sector-size in bytes for an obfuscated file.
428 static int obfsSectorSize(sqlite3_file
* pFile
) {
429 pFile
= ORIGFILE(pFile
);
430 return pFile
->pMethods
->xSectorSize(pFile
);
434 ** Return the device characteristic flags supported by an obfuscated file.
436 static int obfsDeviceCharacteristics(sqlite3_file
* pFile
) {
437 pFile
= ORIGFILE(pFile
);
438 return pFile
->pMethods
->xDeviceCharacteristics(pFile
);
441 /* Create a shared memory file mapping */
442 static int obfsShmMap(sqlite3_file
* pFile
, int iPg
, int pgsz
, int bExtend
,
443 void volatile** pp
) {
444 pFile
= ORIGFILE(pFile
);
445 return pFile
->pMethods
->xShmMap(pFile
, iPg
, pgsz
, bExtend
, pp
);
448 /* Perform locking on a shared-memory segment */
449 static int obfsShmLock(sqlite3_file
* pFile
, int offset
, int n
, int flags
) {
450 pFile
= ORIGFILE(pFile
);
451 return pFile
->pMethods
->xShmLock(pFile
, offset
, n
, flags
);
454 /* Memory barrier operation on shared memory */
455 static void obfsShmBarrier(sqlite3_file
* pFile
) {
456 pFile
= ORIGFILE(pFile
);
457 pFile
->pMethods
->xShmBarrier(pFile
);
460 /* Unmap a shared memory segment */
461 static int obfsShmUnmap(sqlite3_file
* pFile
, int deleteFlag
) {
462 pFile
= ORIGFILE(pFile
);
463 return pFile
->pMethods
->xShmUnmap(pFile
, deleteFlag
);
466 /* Fetch a page of a memory-mapped file */
467 static int obfsFetch(sqlite3_file
* pFile
, sqlite3_int64 iOfst
, int iAmt
,
473 /* Release a memory-mapped page */
474 static int obfsUnfetch(sqlite3_file
* pFile
, sqlite3_int64 iOfst
, void* pPage
) {
475 pFile
= ORIGFILE(pFile
);
476 return pFile
->pMethods
->xUnfetch(pFile
, iOfst
, pPage
);
480 ** Translate a single byte of Hex into an integer.
481 ** This routine only works if h really is a valid hexadecimal
482 ** character: 0..9a..fA..F
484 static u8
obfsHexToInt(int h
) {
485 MOZ_ASSERT((h
>= '0' && h
<= '9') || (h
>= 'a' && h
<= 'f') ||
486 (h
>= 'A' && h
<= 'F'));
488 h
+= 9 * (1 & (h
>> 6));
490 h
+= 9 * (1 & ~(h
>> 4));
492 return (u8
)(h
& 0xf);
498 ** If the file is an ordinary database file, or a rollback or WAL journal
499 ** file, and if the key=XXXX parameter exists, then try to open the file
500 ** as an obfuscated database. All other open attempts fall through into
501 ** the lower-level VFS shim.
503 ** If the key=XXXX parameter exists but is not 64-bytes of hex key, then
504 ** put an error message in NS_WARNING() and return SQLITE_CANTOPEN.
506 static int obfsOpen(sqlite3_vfs
* pVfs
, const char* zName
, sqlite3_file
* pFile
,
507 int flags
, int* pOutFlags
) {
509 sqlite3_file
* pSubFile
;
510 sqlite3_vfs
* pSubVfs
;
514 pSubVfs
= ORIGVFS(pVfs
);
516 (SQLITE_OPEN_MAIN_DB
| SQLITE_OPEN_WAL
| SQLITE_OPEN_MAIN_JOURNAL
)) {
517 zKey
= sqlite3_uri_parameter(zName
, "key");
521 if (zKey
== nullptr) {
522 return pSubVfs
->xOpen(pSubVfs
, zName
, pFile
, flags
, pOutFlags
);
525 i
< kKeyBytes
&& isxdigit(zKey
[i
* 2]) && isxdigit(zKey
[i
* 2 + 1]);
527 aKey
[i
] = (obfsHexToInt(zKey
[i
* 2]) << 4) | obfsHexToInt(zKey
[i
* 2 + 1]);
529 if (i
!= kKeyBytes
) {
531 nsPrintfCString("invalid query parameter on %s: key=%s", zName
, zKey
)
533 return SQLITE_CANTOPEN
;
535 p
= (ObfsFile
*)pFile
;
536 memset(p
, 0, sizeof(*p
));
538 auto encryptCipherStrategy
= MakeUnique
<IPCStreamCipherStrategy
>();
539 auto decryptCipherStrategy
= MakeUnique
<IPCStreamCipherStrategy
>();
541 auto resetMethods
= MakeScopeExit([pFile
] { pFile
->pMethods
= nullptr; });
543 if (NS_WARN_IF(NS_FAILED(encryptCipherStrategy
->Init(
544 CipherMode::Encrypt
, Span
{aKey
, sizeof(aKey
)},
545 IPCStreamCipherStrategy::MakeBlockPrefix())))) {
549 if (NS_WARN_IF(NS_FAILED(decryptCipherStrategy
->Init(
550 CipherMode::Decrypt
, Span
{aKey
, sizeof(aKey
)})))) {
554 pSubFile
= ORIGFILE(pFile
);
555 p
->base
.pMethods
= &obfs_io_methods
;
556 rc
= pSubVfs
->xOpen(pSubVfs
, zName
, pSubFile
, flags
, pOutFlags
);
561 resetMethods
.release();
563 if (flags
& (SQLITE_OPEN_WAL
| SQLITE_OPEN_MAIN_JOURNAL
)) {
564 sqlite3_file
* pDb
= sqlite3_database_file_object(zName
);
565 p
->pPartner
= (ObfsFile
*)pDb
;
566 MOZ_ASSERT(p
->pPartner
->pPartner
== nullptr);
567 p
->pPartner
->pPartner
= p
;
571 p
->encryptCipherStrategy
= encryptCipherStrategy
.release();
572 p
->decryptCipherStrategy
= decryptCipherStrategy
.release();
578 ** All other VFS methods are pass-thrus.
580 static int obfsDelete(sqlite3_vfs
* pVfs
, const char* zPath
, int syncDir
) {
581 return ORIGVFS(pVfs
)->xDelete(ORIGVFS(pVfs
), zPath
, syncDir
);
583 static int obfsAccess(sqlite3_vfs
* pVfs
, const char* zPath
, int flags
,
585 return ORIGVFS(pVfs
)->xAccess(ORIGVFS(pVfs
), zPath
, flags
, pResOut
);
587 static int obfsFullPathname(sqlite3_vfs
* pVfs
, const char* zPath
, int nOut
,
589 return ORIGVFS(pVfs
)->xFullPathname(ORIGVFS(pVfs
), zPath
, nOut
, zOut
);
591 static void* obfsDlOpen(sqlite3_vfs
* pVfs
, const char* zPath
) {
592 return ORIGVFS(pVfs
)->xDlOpen(ORIGVFS(pVfs
), zPath
);
594 static void obfsDlError(sqlite3_vfs
* pVfs
, int nByte
, char* zErrMsg
) {
595 ORIGVFS(pVfs
)->xDlError(ORIGVFS(pVfs
), nByte
, zErrMsg
);
597 static void (*obfsDlSym(sqlite3_vfs
* pVfs
, void* p
, const char* zSym
))(void) {
598 return ORIGVFS(pVfs
)->xDlSym(ORIGVFS(pVfs
), p
, zSym
);
600 static void obfsDlClose(sqlite3_vfs
* pVfs
, void* pHandle
) {
601 ORIGVFS(pVfs
)->xDlClose(ORIGVFS(pVfs
), pHandle
);
603 static int obfsRandomness(sqlite3_vfs
* pVfs
, int nByte
, char* zBufOut
) {
604 return ORIGVFS(pVfs
)->xRandomness(ORIGVFS(pVfs
), nByte
, zBufOut
);
606 static int obfsSleep(sqlite3_vfs
* pVfs
, int nMicroseconds
) {
607 return ORIGVFS(pVfs
)->xSleep(ORIGVFS(pVfs
), nMicroseconds
);
609 static int obfsCurrentTime(sqlite3_vfs
* pVfs
, double* pTimeOut
) {
610 return ORIGVFS(pVfs
)->xCurrentTime(ORIGVFS(pVfs
), pTimeOut
);
612 static int obfsGetLastError(sqlite3_vfs
* pVfs
, int a
, char* b
) {
613 return ORIGVFS(pVfs
)->xGetLastError(ORIGVFS(pVfs
), a
, b
);
615 static int obfsCurrentTimeInt64(sqlite3_vfs
* pVfs
, sqlite3_int64
* p
) {
616 return ORIGVFS(pVfs
)->xCurrentTimeInt64(ORIGVFS(pVfs
), p
);
618 static int obfsSetSystemCall(sqlite3_vfs
* pVfs
, const char* zName
,
619 sqlite3_syscall_ptr pCall
) {
620 return ORIGVFS(pVfs
)->xSetSystemCall(ORIGVFS(pVfs
), zName
, pCall
);
622 static sqlite3_syscall_ptr
obfsGetSystemCall(sqlite3_vfs
* pVfs
,
624 return ORIGVFS(pVfs
)->xGetSystemCall(ORIGVFS(pVfs
), zName
);
626 static const char* obfsNextSystemCall(sqlite3_vfs
* pVfs
, const char* zName
) {
627 return ORIGVFS(pVfs
)->xNextSystemCall(ORIGVFS(pVfs
), zName
);
633 const char* GetObfuscatingVFSName() { return "obfsvfs"; }
635 UniquePtr
<sqlite3_vfs
> ConstructObfuscatingVFS(const char* aBaseVFSName
) {
636 MOZ_ASSERT(aBaseVFSName
);
638 if (sqlite3_vfs_find(GetObfuscatingVFSName()) != nullptr) {
641 sqlite3_vfs
* const pOrig
= sqlite3_vfs_find(aBaseVFSName
);
642 if (pOrig
== nullptr) {
647 // If the VFS version is higher than the last known one, you should update
648 // this VFS adding appropriate methods for any methods added in the version
650 static constexpr int kLastKnownVfsVersion
= 3;
651 MOZ_ASSERT(pOrig
->iVersion
<= kLastKnownVfsVersion
);
654 const sqlite3_vfs obfs_vfs
= {
655 pOrig
->iVersion
, /* iVersion */
656 static_cast<int>(pOrig
->szOsFile
+ sizeof(ObfsFile
)), /* szOsFile */
657 pOrig
->mxPathname
, /* mxPathname */
659 GetObfuscatingVFSName(), /* zName */
660 pOrig
, /* pAppData */
661 obfsOpen
, /* xOpen */
662 obfsDelete
, /* xDelete */
663 obfsAccess
, /* xAccess */
664 obfsFullPathname
, /* xFullPathname */
665 obfsDlOpen
, /* xDlOpen */
666 obfsDlError
, /* xDlError */
667 obfsDlSym
, /* xDlSym */
668 obfsDlClose
, /* xDlClose */
669 obfsRandomness
, /* xRandomness */
670 obfsSleep
, /* xSleep */
671 obfsCurrentTime
, /* xCurrentTime */
672 obfsGetLastError
, /* xGetLastError */
673 obfsCurrentTimeInt64
, /* xCurrentTimeInt64 */
674 obfsSetSystemCall
, /* xSetSystemCall */
675 obfsGetSystemCall
, /* xGetSystemCall */
676 obfsNextSystemCall
/* xNextSystemCall */
679 return MakeUnique
<sqlite3_vfs
>(obfs_vfs
);
682 } // namespace storage
683 } // namespace mozilla