1use crate::libsqlite3::*;
4
5use js_sys::{Date, Math, Number};
6use once_cell::unsync::Lazy;
7use std::{
8 cell::RefCell,
9 ffi::{CStr, CString},
10 ops::Deref,
11};
12
13#[macro_export]
17macro_rules! bail {
18 ($ex:expr) => {
19 bail!($ex, SQLITE_ERROR);
20 };
21 ($ex:expr, $code: expr) => {
22 if $ex {
23 return $code;
24 }
25 };
26}
27
28#[macro_export]
34macro_rules! check_option {
35 ($ex:expr) => {
36 check_option!($ex, SQLITE_ERROR)
37 };
38 ($ex:expr, $code: expr) => {
39 if let Some(v) = $ex {
40 v
41 } else {
42 return $code;
43 }
44 };
45}
46
47#[macro_export]
53macro_rules! check_result {
54 ($ex:expr) => {
55 check_result!($ex, SQLITE_ERROR)
56 };
57 ($ex:expr, $code: expr) => {
58 if let Ok(v) = $ex {
59 v
60 } else {
61 return $code;
62 }
63 };
64}
65
66#[macro_export]
68macro_rules! unused {
69 ($ex:expr) => {
70 let _ = $ex;
71 };
72}
73
74pub(crate) struct ThreadLocalWrapper<T>(pub(crate) T);
75
76#[cfg(not(target_feature = "atomics"))]
77unsafe impl<T> Sync for ThreadLocalWrapper<T> {}
78
79#[cfg(not(target_feature = "atomics"))]
80unsafe impl<T> Send for ThreadLocalWrapper<T> {}
81
82pub struct LazyCell<T, F = fn() -> T>(ThreadLocalWrapper<Lazy<T, F>>);
84
85impl<T, F> LazyCell<T, F> {
86 pub const fn new(init: F) -> LazyCell<T, F> {
87 Self(ThreadLocalWrapper(Lazy::new(init)))
88 }
89}
90
91impl<T, F: FnOnce() -> T> LazyCell<T, F> {
92 pub fn force(this: &Self) -> &T {
93 &this.0 .0
94 }
95}
96
97impl<T> Deref for LazyCell<T> {
98 type Target = T;
99
100 fn deref(&self) -> &T {
101 ::once_cell::unsync::Lazy::force(&self.0 .0)
102 }
103}
104
105pub const SQLITE3_HEADER: &str = "SQLite format 3";
107
108pub fn random_name() -> String {
110 let random = Number::from(Math::random()).to_string(36).unwrap();
111 random.slice(2, random.length()).as_string().unwrap()
112}
113
114pub struct MemChunksFile {
116 chunks: Vec<Vec<u8>>,
117 chunk_size: Option<usize>,
118 file_size: usize,
119}
120
121impl Default for MemChunksFile {
122 fn default() -> Self {
123 Self::new(512)
124 }
125}
126
127impl MemChunksFile {
128 pub fn new(chunk_size: usize) -> Self {
130 assert!(chunk_size != 0, "chunk size can't be zero");
131 MemChunksFile {
132 chunks: Vec::new(),
133 chunk_size: Some(chunk_size),
134 file_size: 0,
135 }
136 }
137
138 pub fn waiting_for_write() -> Self {
142 MemChunksFile {
143 chunks: Vec::new(),
144 chunk_size: None,
145 file_size: 0,
146 }
147 }
148}
149
150impl VfsFile for MemChunksFile {
151 fn read(&self, buf: &mut [u8], offset: usize) -> VfsResult<bool> {
152 let Some(chunk_size) = self.chunk_size else {
153 buf.fill(0);
154 return Ok(false);
155 };
156
157 if self.file_size <= offset {
158 buf.fill(0);
159 return Ok(false);
160 }
161
162 if chunk_size == buf.len() && offset % chunk_size == 0 {
163 buf.copy_from_slice(&self.chunks[offset / chunk_size]);
164 Ok(true)
165 } else {
166 let mut size = buf.len();
167 let chunk_idx = offset / chunk_size;
168 let mut remaining_idx = offset % chunk_size;
169 let mut offset = 0;
170
171 for chunk in &self.chunks[chunk_idx..] {
172 let n = std::cmp::min(chunk_size.min(self.file_size) - remaining_idx, size);
173 buf[offset..offset + n].copy_from_slice(&chunk[remaining_idx..remaining_idx + n]);
174 offset += n;
175 size -= n;
176 remaining_idx = 0;
177 if size == 0 {
178 break;
179 }
180 }
181
182 if offset < buf.len() {
183 buf[offset..].fill(0);
184 Ok(false)
185 } else {
186 Ok(true)
187 }
188 }
189 }
190
191 fn write(&mut self, buf: &[u8], offset: usize) -> VfsResult<()> {
192 if buf.is_empty() {
193 return Ok(());
194 }
195
196 let chunk_size = if let Some(chunk_size) = self.chunk_size {
197 chunk_size
198 } else {
199 let size = buf.len();
200 self.chunk_size = Some(size);
201 size
202 };
203
204 let new_length = self.file_size.max(offset + buf.len());
205
206 if chunk_size == buf.len() && offset % chunk_size == 0 {
207 for _ in self.chunks.len()..offset / chunk_size {
208 self.chunks.push(vec![0; chunk_size]);
209 }
210 if let Some(buffer) = self.chunks.get_mut(offset / chunk_size) {
211 buffer.copy_from_slice(buf);
212 } else {
213 self.chunks.push(buf.to_vec());
214 }
215 } else {
216 let mut size = buf.len();
217 let chunk_start_idx = offset / chunk_size;
218 let chunk_end_idx = (offset + size - 1) / chunk_size;
219 let chunks_length = self.chunks.len();
220
221 for _ in chunks_length..=chunk_end_idx {
222 self.chunks.push(vec![0; chunk_size]);
223 }
224
225 let mut remaining_idx = offset % chunk_size;
226 let mut offset = 0;
227
228 for idx in chunk_start_idx..=chunk_end_idx {
229 let n = std::cmp::min(chunk_size - remaining_idx, size);
230 self.chunks[idx][remaining_idx..remaining_idx + n]
231 .copy_from_slice(&buf[offset..offset + n]);
232 offset += n;
233 size -= n;
234 remaining_idx = 0;
235 if size == 0 {
236 break;
237 }
238 }
239 }
240
241 self.file_size = new_length;
242
243 Ok(())
244 }
245
246 fn truncate(&mut self, size: usize) -> VfsResult<()> {
247 if let Some(chunk_size) = self.chunk_size {
248 if size == 0 {
249 std::mem::take(&mut self.chunks);
250 } else {
251 let idx = ((size - 1) / chunk_size) + 1;
252 self.chunks.drain(idx..);
253 }
254 } else if size != 0 {
255 assert_eq!(self.file_size, 0);
256 return Err(VfsError::new(SQLITE_IOERR, "Failed to truncate".into()));
257 }
258 self.file_size = size;
259 Ok(())
260 }
261
262 fn flush(&mut self) -> VfsResult<()> {
263 Ok(())
264 }
265
266 fn size(&self) -> VfsResult<usize> {
267 Ok(self.file_size)
268 }
269}
270
271#[repr(C)]
275pub struct SQLiteVfsFile {
276 pub io_methods: sqlite3_file,
279 pub vfs: *mut sqlite3_vfs,
281 pub flags: i32,
283 pub name_ptr: *const u8,
286 pub name_length: usize,
288}
289
290impl SQLiteVfsFile {
291 pub unsafe fn from_file(file: *mut sqlite3_file) -> &'static SQLiteVfsFile {
297 &*file.cast::<Self>()
298 }
299
300 pub unsafe fn name(&self) -> &'static mut str {
308 std::str::from_utf8_unchecked_mut(std::slice::from_raw_parts_mut(
310 self.name_ptr.cast_mut(),
311 self.name_length,
312 ))
313 }
314
315 pub fn sqlite3_file(&'static self) -> *mut sqlite3_file {
317 self as *const SQLiteVfsFile as *mut sqlite3_file
318 }
319}
320
321#[derive(thiserror::Error, Debug)]
323pub enum RegisterVfsError {
324 #[error("An error occurred converting the given vfs name to a CStr")]
325 ToCStr,
326 #[error("An error occurred while registering vfs with sqlite")]
327 RegisterVfs,
328}
329
330pub fn registered_vfs(vfs_name: &str) -> Result<Option<*mut sqlite3_vfs>, RegisterVfsError> {
332 let name = CString::new(vfs_name).map_err(|_| RegisterVfsError::ToCStr)?;
333 let vfs = unsafe { sqlite3_vfs_find(name.as_ptr()) };
334 Ok((!vfs.is_null()).then_some(vfs))
335}
336
337pub fn register_vfs<IO: SQLiteIoMethods, V: SQLiteVfs<IO>>(
339 vfs_name: &str,
340 app_data: IO::AppData,
341 default_vfs: bool,
342) -> Result<*mut sqlite3_vfs, RegisterVfsError> {
343 let name = CString::new(vfs_name).map_err(|_| RegisterVfsError::ToCStr)?;
344 let name_ptr = name.into_raw();
345
346 let app_data = VfsAppData::new(app_data).leak();
347 let vfs = Box::leak(Box::new(V::vfs(name_ptr, app_data.cast())));
348 let ret = unsafe { sqlite3_vfs_register(vfs, i32::from(default_vfs)) };
349
350 if ret != SQLITE_OK {
351 unsafe {
352 drop(Box::from_raw(vfs));
353 drop(CString::from_raw(name_ptr));
354 drop(VfsAppData::from_raw(app_data));
355 }
356 return Err(RegisterVfsError::RegisterVfs);
357 }
358
359 Ok(vfs as *mut sqlite3_vfs)
360}
361
362#[derive(Debug)]
364pub struct VfsError {
365 code: i32,
366 message: String,
367}
368
369impl VfsError {
370 pub fn new(code: i32, message: String) -> Self {
371 VfsError { code, message }
372 }
373}
374
375pub type VfsResult<T> = Result<T, VfsError>;
377
378pub struct VfsAppData<T> {
380 data: T,
381 last_err: RefCell<Option<(i32, String)>>,
382}
383
384impl<T> VfsAppData<T> {
385 pub fn new(t: T) -> Self {
386 VfsAppData {
387 data: t,
388 last_err: RefCell::new(None),
389 }
390 }
391
392 pub fn leak(self) -> *mut Self {
394 Box::into_raw(Box::new(self))
395 }
396
397 pub unsafe fn from_raw(t: *mut Self) -> VfsAppData<T> {
401 *Box::from_raw(t)
402 }
403
404 pub fn pop_err(&self) -> Option<(i32, String)> {
406 self.last_err.borrow_mut().take()
407 }
408
409 pub fn store_err(&self, err: VfsError) -> i32 {
411 let VfsError { code, message } = err;
412 self.last_err.borrow_mut().replace((code, message));
413 code
414 }
415}
416
417impl<T> Deref for VfsAppData<T> {
419 type Target = T;
420
421 fn deref(&self) -> &Self::Target {
422 &self.data
423 }
424}
425
426pub trait VfsFile {
428 fn read(&self, buf: &mut [u8], offset: usize) -> VfsResult<bool>;
430 fn write(&mut self, buf: &[u8], offset: usize) -> VfsResult<()>;
432 fn truncate(&mut self, size: usize) -> VfsResult<()>;
434 fn flush(&mut self) -> VfsResult<()>;
436 fn size(&self) -> VfsResult<usize>;
438}
439
440pub trait VfsStore<File, AppData> {
442 unsafe fn app_data(vfs: *mut sqlite3_vfs) -> &'static VfsAppData<AppData> {
448 &*(*vfs).pAppData.cast()
449 }
450 fn add_file(vfs: *mut sqlite3_vfs, file: &str, flags: i32) -> VfsResult<()>;
452 fn contains_file(vfs: *mut sqlite3_vfs, file: &str) -> VfsResult<bool>;
454 fn delete_file(vfs: *mut sqlite3_vfs, file: &str) -> VfsResult<()>;
456 fn with_file<F: Fn(&File) -> VfsResult<i32>>(vfs_file: &SQLiteVfsFile, f: F) -> VfsResult<i32>;
458 fn with_file_mut<F: Fn(&mut File) -> VfsResult<i32>>(
460 vfs_file: &SQLiteVfsFile,
461 f: F,
462 ) -> VfsResult<i32>;
463}
464
465#[allow(clippy::missing_safety_doc)]
467pub trait SQLiteVfs<IO: SQLiteIoMethods> {
468 const VERSION: ::std::os::raw::c_int;
469 const MAX_PATH_SIZE: ::std::os::raw::c_int = 1024;
470
471 fn vfs(
472 vfs_name: *const ::std::os::raw::c_char,
473 app_data: *mut VfsAppData<IO::AppData>,
474 ) -> sqlite3_vfs {
475 sqlite3_vfs {
476 iVersion: Self::VERSION,
477 szOsFile: std::mem::size_of::<SQLiteVfsFile>() as i32,
478 mxPathname: Self::MAX_PATH_SIZE,
479 pNext: std::ptr::null_mut(),
480 zName: vfs_name,
481 pAppData: app_data.cast(),
482 xOpen: Some(Self::xOpen),
483 xDelete: Some(Self::xDelete),
484 xAccess: Some(Self::xAccess),
485 xFullPathname: Some(Self::xFullPathname),
486 xDlOpen: None,
487 xDlError: None,
488 xDlSym: None,
489 xDlClose: None,
490 xRandomness: Some(x_methods_shim::xRandomness),
491 xSleep: Some(x_methods_shim::xSleep),
492 xCurrentTime: Some(x_methods_shim::xCurrentTime),
493 xGetLastError: Some(Self::xGetLastError),
494 xCurrentTimeInt64: Some(x_methods_shim::xCurrentTimeInt64),
495 xSetSystemCall: None,
496 xGetSystemCall: None,
497 xNextSystemCall: None,
498 }
499 }
500
501 unsafe extern "C" fn xOpen(
502 pVfs: *mut sqlite3_vfs,
503 zName: sqlite3_filename,
504 pFile: *mut sqlite3_file,
505 flags: ::std::os::raw::c_int,
506 pOutFlags: *mut ::std::os::raw::c_int,
507 ) -> ::std::os::raw::c_int {
508 Self::xOpenImpl(pVfs, zName, pFile, flags, pOutFlags)
509 }
510
511 unsafe extern "C" fn xOpenImpl(
512 pVfs: *mut sqlite3_vfs,
513 zName: sqlite3_filename,
514 pFile: *mut sqlite3_file,
515 flags: ::std::os::raw::c_int,
516 pOutFlags: *mut ::std::os::raw::c_int,
517 ) -> ::std::os::raw::c_int {
518 let app_data = IO::Store::app_data(pVfs);
519
520 let name = if zName.is_null() {
521 random_name()
522 } else {
523 check_result!(CStr::from_ptr(zName).to_str()).into()
524 };
525
526 let exist = match IO::Store::contains_file(pVfs, &name) {
527 Ok(exist) => exist,
528 Err(err) => return app_data.store_err(err),
529 };
530
531 if !exist {
532 if flags & SQLITE_OPEN_CREATE == 0 {
533 return app_data.store_err(VfsError::new(
534 SQLITE_CANTOPEN,
535 format!("file not found: {name}"),
536 ));
537 }
538 if let Err(err) = IO::Store::add_file(pVfs, &name, flags) {
539 return app_data.store_err(err);
540 }
541 }
542
543 let leak = name.leak();
544 let vfs_file = pFile.cast::<SQLiteVfsFile>();
545 (*vfs_file).vfs = pVfs;
546 (*vfs_file).flags = flags;
547 (*vfs_file).name_ptr = leak.as_ptr();
548 (*vfs_file).name_length = leak.len();
549
550 (*pFile).pMethods = &IO::METHODS;
551
552 if !pOutFlags.is_null() {
553 *pOutFlags = flags;
554 }
555
556 SQLITE_OK
557 }
558
559 unsafe extern "C" fn xDelete(
560 pVfs: *mut sqlite3_vfs,
561 zName: *const ::std::os::raw::c_char,
562 syncDir: ::std::os::raw::c_int,
563 ) -> ::std::os::raw::c_int {
564 unused!(syncDir);
565
566 let app_data = IO::Store::app_data(pVfs);
567 bail!(zName.is_null(), SQLITE_IOERR_DELETE);
568 let s = check_result!(CStr::from_ptr(zName).to_str());
569 if let Err(err) = IO::Store::delete_file(pVfs, s) {
570 app_data.store_err(err)
571 } else {
572 SQLITE_OK
573 }
574 }
575
576 unsafe extern "C" fn xAccess(
577 pVfs: *mut sqlite3_vfs,
578 zName: *const ::std::os::raw::c_char,
579 flags: ::std::os::raw::c_int,
580 pResOut: *mut ::std::os::raw::c_int,
581 ) -> ::std::os::raw::c_int {
582 unused!(flags);
583
584 *pResOut = if zName.is_null() {
585 0
586 } else {
587 let app_data = IO::Store::app_data(pVfs);
588 let file = check_result!(CStr::from_ptr(zName).to_str());
589 let exist = match IO::Store::contains_file(pVfs, file) {
590 Ok(exist) => exist,
591 Err(err) => return app_data.store_err(err),
592 };
593 i32::from(exist)
594 };
595
596 SQLITE_OK
597 }
598
599 unsafe extern "C" fn xFullPathname(
600 pVfs: *mut sqlite3_vfs,
601 zName: *const ::std::os::raw::c_char,
602 nOut: ::std::os::raw::c_int,
603 zOut: *mut ::std::os::raw::c_char,
604 ) -> ::std::os::raw::c_int {
605 unused!(pVfs);
606 bail!(zName.is_null() || zOut.is_null(), SQLITE_CANTOPEN);
607 let len = CStr::from_ptr(zName).to_bytes_with_nul().len();
608 bail!(len > nOut as usize, SQLITE_CANTOPEN);
609 zName.copy_to(zOut, len);
610 SQLITE_OK
611 }
612
613 unsafe extern "C" fn xGetLastError(
614 pVfs: *mut sqlite3_vfs,
615 nOut: ::std::os::raw::c_int,
616 zOut: *mut ::std::os::raw::c_char,
617 ) -> ::std::os::raw::c_int {
618 let app_data = IO::Store::app_data(pVfs);
619 let Some((code, msg)) = app_data.pop_err() else {
620 return SQLITE_OK;
621 };
622 if !zOut.is_null() {
623 let nOut = nOut as usize;
624 let count = msg.len().min(nOut);
625 msg.as_ptr().copy_to(zOut.cast(), count);
626 let zero = match nOut.cmp(&msg.len()) {
627 std::cmp::Ordering::Less | std::cmp::Ordering::Equal => nOut,
628 std::cmp::Ordering::Greater => msg.len() + 1,
629 };
630 if zero > 0 {
631 std::ptr::write(zOut.add(zero - 1), 0);
632 }
633 }
634 code
635 }
636}
637
638#[allow(clippy::missing_safety_doc)]
640pub trait SQLiteIoMethods {
641 type File: VfsFile;
642 type AppData: 'static;
643 type Store: VfsStore<Self::File, Self::AppData>;
644
645 const VERSION: ::std::os::raw::c_int;
646
647 const METHODS: sqlite3_io_methods = sqlite3_io_methods {
648 iVersion: Self::VERSION,
649 xClose: Some(Self::xClose),
650 xRead: Some(Self::xRead),
651 xWrite: Some(Self::xWrite),
652 xTruncate: Some(Self::xTruncate),
653 xSync: Some(Self::xSync),
654 xFileSize: Some(Self::xFileSize),
655 xLock: Some(Self::xLock),
656 xUnlock: Some(Self::xUnlock),
657 xCheckReservedLock: Some(Self::xCheckReservedLock),
658 xFileControl: Some(Self::xFileControl),
659 xSectorSize: Some(Self::xSectorSize),
660 xDeviceCharacteristics: Some(Self::xDeviceCharacteristics),
661 xShmMap: None,
662 xShmLock: None,
663 xShmBarrier: None,
664 xShmUnmap: None,
665 xFetch: None,
666 xUnfetch: None,
667 };
668
669 unsafe extern "C" fn xClose(pFile: *mut sqlite3_file) -> ::std::os::raw::c_int {
670 Self::xCloseImpl(pFile)
671 }
672
673 unsafe extern "C" fn xCloseImpl(pFile: *mut sqlite3_file) -> ::std::os::raw::c_int {
674 let vfs_file = SQLiteVfsFile::from_file(pFile);
675 let app_data = Self::Store::app_data(vfs_file.vfs);
676
677 if vfs_file.flags & SQLITE_OPEN_DELETEONCLOSE != 0 {
678 if let Err(err) = Self::Store::delete_file(vfs_file.vfs, vfs_file.name()) {
679 return app_data.store_err(err);
680 }
681 }
682
683 drop(Box::from_raw(vfs_file.name()));
684
685 SQLITE_OK
686 }
687
688 unsafe extern "C" fn xRead(
689 pFile: *mut sqlite3_file,
690 zBuf: *mut ::std::os::raw::c_void,
691 iAmt: ::std::os::raw::c_int,
692 iOfst: sqlite3_int64,
693 ) -> ::std::os::raw::c_int {
694 let vfs_file = SQLiteVfsFile::from_file(pFile);
695 let app_data = Self::Store::app_data(vfs_file.vfs);
696
697 let f = |file: &Self::File| {
698 let size = iAmt as usize;
699 let offset = iOfst as usize;
700 let slice = std::slice::from_raw_parts_mut(zBuf.cast::<u8>(), size);
701 let code = if file.read(slice, offset)? {
702 SQLITE_OK
703 } else {
704 SQLITE_IOERR_SHORT_READ
705 };
706 Ok(code)
707 };
708
709 match Self::Store::with_file(vfs_file, f) {
710 Ok(code) => code,
711 Err(err) => app_data.store_err(err),
712 }
713 }
714
715 unsafe extern "C" fn xWrite(
716 pFile: *mut sqlite3_file,
717 zBuf: *const ::std::os::raw::c_void,
718 iAmt: ::std::os::raw::c_int,
719 iOfst: sqlite3_int64,
720 ) -> ::std::os::raw::c_int {
721 let vfs_file = SQLiteVfsFile::from_file(pFile);
722 let app_data = Self::Store::app_data(vfs_file.vfs);
723
724 let f = |file: &mut Self::File| {
725 let (offset, size) = (iOfst as usize, iAmt as usize);
726 let slice = std::slice::from_raw_parts(zBuf.cast::<u8>(), size);
727 file.write(slice, offset)?;
728 Ok(SQLITE_OK)
729 };
730
731 match Self::Store::with_file_mut(vfs_file, f) {
732 Ok(code) => code,
733 Err(err) => app_data.store_err(err),
734 }
735 }
736
737 unsafe extern "C" fn xTruncate(
738 pFile: *mut sqlite3_file,
739 size: sqlite3_int64,
740 ) -> ::std::os::raw::c_int {
741 let vfs_file = SQLiteVfsFile::from_file(pFile);
742 let app_data = Self::Store::app_data(vfs_file.vfs);
743
744 let f = |file: &mut Self::File| {
745 file.truncate(size as usize)?;
746 Ok(SQLITE_OK)
747 };
748
749 match Self::Store::with_file_mut(vfs_file, f) {
750 Ok(code) => code,
751 Err(err) => app_data.store_err(err),
752 }
753 }
754
755 unsafe extern "C" fn xSync(
756 pFile: *mut sqlite3_file,
757 flags: ::std::os::raw::c_int,
758 ) -> ::std::os::raw::c_int {
759 unused!(flags);
760
761 let vfs_file = SQLiteVfsFile::from_file(pFile);
762 let app_data = Self::Store::app_data(vfs_file.vfs);
763
764 let f = |file: &mut Self::File| {
765 file.flush()?;
766 Ok(SQLITE_OK)
767 };
768
769 match Self::Store::with_file_mut(vfs_file, f) {
770 Ok(code) => code,
771 Err(err) => app_data.store_err(err),
772 }
773 }
774
775 unsafe extern "C" fn xFileSize(
776 pFile: *mut sqlite3_file,
777 pSize: *mut sqlite3_int64,
778 ) -> ::std::os::raw::c_int {
779 let vfs_file = SQLiteVfsFile::from_file(pFile);
780 let app_data = Self::Store::app_data(vfs_file.vfs);
781
782 let f = |file: &Self::File| {
783 file.size().map(|size| {
784 *pSize = size as sqlite3_int64;
785 })?;
786 Ok(SQLITE_OK)
787 };
788
789 match Self::Store::with_file(vfs_file, f) {
790 Ok(code) => code,
791 Err(err) => app_data.store_err(err),
792 }
793 }
794
795 unsafe extern "C" fn xLock(
796 pFile: *mut sqlite3_file,
797 eLock: ::std::os::raw::c_int,
798 ) -> ::std::os::raw::c_int {
799 unused!((pFile, eLock));
800 SQLITE_OK
801 }
802
803 unsafe extern "C" fn xUnlock(
804 pFile: *mut sqlite3_file,
805 eLock: ::std::os::raw::c_int,
806 ) -> ::std::os::raw::c_int {
807 unused!((pFile, eLock));
808 SQLITE_OK
809 }
810
811 unsafe extern "C" fn xCheckReservedLock(
812 pFile: *mut sqlite3_file,
813 pResOut: *mut ::std::os::raw::c_int,
814 ) -> ::std::os::raw::c_int {
815 unused!(pFile);
816 *pResOut = 0;
817 SQLITE_OK
818 }
819
820 unsafe extern "C" fn xFileControl(
821 pFile: *mut sqlite3_file,
822 op: ::std::os::raw::c_int,
823 pArg: *mut ::std::os::raw::c_void,
824 ) -> ::std::os::raw::c_int {
825 unused!((pFile, op, pArg));
826 SQLITE_NOTFOUND
827 }
828
829 unsafe extern "C" fn xSectorSize(pFile: *mut sqlite3_file) -> ::std::os::raw::c_int {
830 unused!(pFile);
831 512
832 }
833
834 unsafe extern "C" fn xDeviceCharacteristics(pFile: *mut sqlite3_file) -> ::std::os::raw::c_int {
835 unused!(pFile);
836 0
837 }
838}
839
840#[allow(clippy::missing_safety_doc)]
842pub mod x_methods_shim {
843 use super::*;
844
845 #[cfg(target_feature = "atomics")]
847 pub unsafe extern "C" fn xSleep(
848 _pVfs: *mut sqlite3_vfs,
849 microseconds: ::std::os::raw::c_int,
850 ) -> ::std::os::raw::c_int {
851 use std::{thread, time::Duration};
852 thread::sleep(Duration::from_micros(microseconds as u64));
853 SQLITE_OK
854 }
855
856 #[cfg(not(target_feature = "atomics"))]
857 pub unsafe extern "C" fn xSleep(
858 _pVfs: *mut sqlite3_vfs,
859 _microseconds: ::std::os::raw::c_int,
860 ) -> ::std::os::raw::c_int {
861 SQLITE_OK
862 }
863
864 pub unsafe extern "C" fn xRandomness(
866 _pVfs: *mut sqlite3_vfs,
867 nByte: ::std::os::raw::c_int,
868 zOut: *mut ::std::os::raw::c_char,
869 ) -> ::std::os::raw::c_int {
870 for i in 0..nByte as usize {
871 *zOut.add(i) = (Math::random() * 255000.0) as _;
872 }
873 nByte
874 }
875
876 pub unsafe extern "C" fn xCurrentTime(
878 _pVfs: *mut sqlite3_vfs,
879 pTimeOut: *mut f64,
880 ) -> ::std::os::raw::c_int {
881 *pTimeOut = 2440587.5 + (Date::new_0().get_time() / 86400000.0);
882 SQLITE_OK
883 }
884
885 pub unsafe extern "C" fn xCurrentTimeInt64(
887 _pVfs: *mut sqlite3_vfs,
888 pOut: *mut sqlite3_int64,
889 ) -> ::std::os::raw::c_int {
890 *pOut = ((2440587.5 * 86400000.0) + Date::new_0().get_time()) as sqlite3_int64;
891 SQLITE_OK
892 }
893}
894
895#[derive(thiserror::Error, Debug)]
896pub enum ImportDbError {
897 #[error("Byte array size is invalid for an SQLite db.")]
898 InvalidDbSize,
899 #[error("Input does not contain an SQLite database header.")]
900 InvalidHeader,
901 #[error("Page size must be a power of two between 512 and 65536 inclusive")]
902 InvalidPageSize,
903}
904
905pub fn check_import_db(bytes: &[u8]) -> Result<usize, ImportDbError> {
907 let length = bytes.len();
908
909 if length < 512 || length % 512 != 0 {
910 return Err(ImportDbError::InvalidDbSize);
911 }
912
913 if SQLITE3_HEADER
914 .as_bytes()
915 .iter()
916 .zip(bytes)
917 .any(|(x, y)| x != y)
918 {
919 return Err(ImportDbError::InvalidHeader);
920 }
921
922 let page_size = u16::from_be_bytes([bytes[16], bytes[17]]);
925 let page_size = if page_size == 1 {
926 65536
927 } else {
928 usize::from(page_size)
929 };
930
931 Ok(page_size)
932}
933
934pub fn check_db_and_page_size(db_size: usize, page_size: usize) -> Result<(), ImportDbError> {
936 if !(page_size.is_power_of_two() && (512..=65536).contains(&page_size)) {
937 return Err(ImportDbError::InvalidPageSize);
938 }
939 if db_size % page_size != 0 {
940 return Err(ImportDbError::InvalidDbSize);
941 }
942 Ok(())
943}
944
945#[cfg(test)]
946pub mod test_suite {
947 use super::{
948 sqlite3_file, sqlite3_vfs, SQLiteVfsFile, VfsAppData, VfsError, VfsFile, VfsResult,
949 VfsStore, SQLITE_IOERR, SQLITE_OK, SQLITE_OPEN_CREATE, SQLITE_OPEN_MAIN_DB,
950 SQLITE_OPEN_READWRITE,
951 };
952
953 fn test_vfs_file<File: VfsFile>(file: &mut File) -> VfsResult<i32> {
954 let base_offset = 1024 * 1024;
955
956 let mut write_buffer = vec![42; 64 * 1024];
957 let mut read_buffer = vec![42; base_offset + write_buffer.len()];
958 let hw = "hello world!";
959 write_buffer[0..hw.len()].copy_from_slice(hw.as_bytes());
960
961 file.write(&write_buffer, 0)?;
962 assert!(!file.read(&mut read_buffer, 0)?);
963 if &read_buffer[0..hw.len()] != hw.as_bytes()
964 || read_buffer[hw.len()..write_buffer.len()]
965 .iter()
966 .any(|&x| x != 42)
967 || read_buffer[write_buffer.len()..].iter().any(|&x| x != 0)
968 {
969 return Err(VfsError::new(SQLITE_IOERR, "incorrect buffer data".into()))?;
970 }
971 if file.size()? != write_buffer.len() {
972 return Err(VfsError::new(
973 SQLITE_IOERR,
974 "incorrect buffer length".into(),
975 ))?;
976 }
977
978 file.write(&write_buffer, base_offset)?;
979 if file.size()? != base_offset + write_buffer.len() {
980 return Err(VfsError::new(
981 SQLITE_IOERR,
982 "incorrect buffer length".into(),
983 ))?;
984 }
985 assert!(file.read(&mut read_buffer, 0)?);
986 if &read_buffer[0..hw.len()] != hw.as_bytes()
987 || read_buffer[hw.len()..write_buffer.len()]
988 .iter()
989 .any(|&x| x != 42)
990 || read_buffer[write_buffer.len()..base_offset]
991 .iter()
992 .all(|&x| x != 0)
993 || &read_buffer[base_offset..base_offset + hw.len()] != hw.as_bytes()
994 || read_buffer[base_offset + hw.len()..]
995 .iter()
996 .any(|&x| x != 42)
997 {
998 return Err(VfsError::new(SQLITE_IOERR, "incorrect buffer data".into()))?;
999 }
1000
1001 Ok(SQLITE_OK)
1002 }
1003
1004 pub fn test_vfs_store<AppData, File: VfsFile, Store: VfsStore<File, AppData>>(
1005 vfs_data: VfsAppData<AppData>,
1006 ) -> VfsResult<()> {
1007 let layout = std::alloc::Layout::new::<sqlite3_vfs>();
1008 let vfs = unsafe {
1009 let vfs = std::alloc::alloc(layout) as *mut sqlite3_vfs;
1010 (*vfs).pAppData = vfs_data.leak().cast();
1011 vfs
1012 };
1013
1014 let test_file = |filename: &str, flags: i32| {
1015 if Store::contains_file(vfs, filename)? {
1016 return Err(VfsError::new(SQLITE_IOERR, "found file before test".into()))?;
1017 }
1018
1019 let vfs_file = SQLiteVfsFile {
1020 io_methods: sqlite3_file {
1021 pMethods: std::ptr::null(),
1022 },
1023 vfs,
1024 flags,
1025 name_ptr: filename.as_ptr(),
1026 name_length: filename.len(),
1027 };
1028
1029 Store::add_file(vfs, filename, flags)?;
1030
1031 if !Store::contains_file(vfs, filename)? {
1032 return Err(VfsError::new(
1033 SQLITE_IOERR,
1034 "not found file after create".into(),
1035 ))?;
1036 }
1037
1038 Store::with_file_mut(&vfs_file, |file| test_vfs_file(file))?;
1039
1040 Store::delete_file(vfs, filename)?;
1041
1042 if Store::contains_file(vfs, filename)? {
1043 return Err(VfsError::new(
1044 SQLITE_IOERR,
1045 "found file after delete".into(),
1046 ))?;
1047 }
1048
1049 Ok(())
1050 };
1051
1052 test_file(
1053 "___test_vfs_store#1___",
1054 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB,
1055 )?;
1056
1057 test_file(
1058 "___test_vfs_store#2___",
1059 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
1060 )?;
1061
1062 unsafe {
1063 drop(VfsAppData::<AppData>::from_raw((*vfs).pAppData as *mut _));
1064 std::alloc::dealloc(vfs.cast(), layout);
1065 }
1066
1067 Ok(())
1068 }
1069}
1070
1071#[cfg(test)]
1072mod tests {
1073 use super::{MemChunksFile, VfsFile};
1074 use wasm_bindgen_test::wasm_bindgen_test;
1075
1076 #[wasm_bindgen_test]
1077 fn test_chunks_file() {
1078 let mut file = MemChunksFile::new(512);
1079 file.write(&[], 0).unwrap();
1080 assert!(file.size().unwrap() == 0);
1081
1082 let mut buffer = [1; 2];
1083 let ret = file.read(&mut buffer, 0).unwrap();
1084 assert_eq!(ret, false);
1085 assert_eq!([0; 2], buffer);
1086
1087 file.write(&[1], 0).unwrap();
1088 assert!(file.size().unwrap() == 1);
1089 let mut buffer = [2; 2];
1090 let ret = file.read(&mut buffer, 0).unwrap();
1091 assert_eq!(ret, false);
1092 assert_eq!([1, 0], buffer);
1093
1094 let mut file = MemChunksFile::new(512);
1095 file.write(&[1; 512], 0).unwrap();
1096 assert!(file.size().unwrap() == 512);
1097 assert!(file.chunks.len() == 1);
1098
1099 file.truncate(512).unwrap();
1100 assert!(file.size().unwrap() == 512);
1101 assert!(file.chunks.len() == 1);
1102
1103 file.write(&[41, 42, 43], 511).unwrap();
1104 assert!(file.size().unwrap() == 514);
1105 assert!(file.chunks.len() == 2);
1106
1107 let mut buffer = [0; 3];
1108 let ret = file.read(&mut buffer, 511).unwrap();
1109 assert_eq!(ret, true);
1110 assert_eq!(buffer, [41, 42, 43]);
1111
1112 file.truncate(513).unwrap();
1113 assert!(file.size().unwrap() == 513);
1114 assert!(file.chunks.len() == 2);
1115
1116 file.write(&[1], 2048).unwrap();
1117 assert!(file.size().unwrap() == 2049);
1118 assert!(file.chunks.len() == 5);
1119
1120 file.truncate(0).unwrap();
1121 assert!(file.size().unwrap() == 0);
1122 assert!(file.chunks.len() == 0);
1123 }
1124}