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