1//! The file system notebooks and their replicas live in: std's natively. In the browser,
2//! which gives a module none, it is `web`'s, which keeps SQLite's files beside the notebooks'.
3
4#[cfg(not(target_arch = "wasm32"))]
5pub use onestore::{confirm_file, place_file, read_file, read_file_limited, supersede_file};
6#[cfg(not(target_arch = "wasm32"))]
7pub use std::{fs::*, path::absolute, process::id as process_id};
8
9/// `Transaction::commit_file` through this file system.
10#[cfg(not(target_arch = "wasm32"))]
11pub fn commit_file(
12 transaction: &onestore::Transaction,
13 path: impl AsRef<std::path::Path>,
14) -> Result<(), onestore::CommitError> {
15 transaction.commit_file(path)
16}
17
18#[cfg(target_arch = "wasm32")]
19mod web;
20#[cfg(target_arch = "wasm32")]
21pub use web::*;
22
23/// Reads a regular file within `limit`, including when it grows during the read.
24pub fn read_limited(path: impl AsRef<std::path::Path>, limit: usize) -> std::io::Result<Vec<u8>> {
25 use std::io::Read;
26 let file = File::open(path)?;
27 let metadata = file.metadata()?;
28 if !metadata.is_file() {
29 return Err(std::io::ErrorKind::InvalidInput.into());
30 }
31 if metadata.len() > limit as u64 {
32 return Err(std::io::ErrorKind::FileTooLarge.into());
33 }
34 let mut bytes = Vec::new();
35 file.take((limit as u64).saturating_add(1))
36 .read_to_end(&mut bytes)?;
37 if bytes.len() > limit {
38 return Err(std::io::ErrorKind::FileTooLarge.into());
39 }
40 Ok(bytes)
41}
42
43#[cfg(not(target_arch = "wasm32"))]
44pub async fn durable() -> std::io::Result<()> {
45 Ok(())
46}
47
48#[cfg(all(test, not(target_arch = "wasm32")))]
49mod tests {
50 use super::*;
51
52 #[test]
53 fn bounded_reads_refuse_an_eight_gib_file() {
54 let file = tempfile::NamedTempFile::new().unwrap();
55 write(file.path(), b"hello").unwrap();
56 assert_eq!(read_limited(file.path(), 5).unwrap(), b"hello");
57 assert_eq!(
58 read_limited(file.path(), 4).unwrap_err().kind(),
59 std::io::ErrorKind::FileTooLarge
60 );
61 file.as_file().set_len(8 << 30).unwrap();
62 assert_eq!(
63 read_limited(file.path(), crate::MAX_FILE_BYTES)
64 .unwrap_err()
65 .kind(),
66 std::io::ErrorKind::FileTooLarge
67 );
68 let folder = tempfile::tempdir().unwrap();
69 assert!(read_limited(folder.path(), crate::MAX_FILE_BYTES).is_err());
70 }
71}