From 8da8acc177b9cb45ebe3aa756a45f3967252913f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Fri, 25 Apr 2025 17:42:39 +0200 Subject: [PATCH 01/13] Add support for littlefs opening flags --- Cargo.toml | 3 +++ src/fs.rs | 44 ++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b6d14f3b..ea4c3ba8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,7 @@ repository.workspace = true all-features = true [dependencies] +bitflags = "2.9.0" delog = "0.1.0" generic-array = "0.14" heapless = "0.7" @@ -57,3 +58,5 @@ log-error = [] # member `char name[LFS_NAME_MAX+1]`. # This means that if we change `traits::Storage::FILENAME_MAX_PLUS_ONE`, # we need to pass this on! +[patch.crates-io] +littlefs2-sys = { git = "https://github.com/sosthene-nitrokey/littlefs2-sys", rev = "c0f90bd7c12b41984c8eff550004f1de89c8b1d6" } diff --git a/src/fs.rs b/src/fs.rs index 3f33d958..dd62a225 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -79,8 +79,25 @@ impl Default for Allocation { Self::new() } } + +#[derive(Default, Clone, Debug)] +#[non_exhaustive] +pub struct Config { + pub mount_flags: MountFlags, +} + +bitflags::bitflags! { + #[derive(Default, Clone, Copy,Debug)] + pub struct MountFlags: u32 { + const DISABLE_BLOCK_COUNT_CHECK = ll::lfs_fs_flags_LFS_CFG_DISABLE_BLOCK_COUNT_CHECK; + } +} + impl Allocation { - pub fn new() -> Allocation { + pub fn new() -> Self { + Self::with_config(Config::default()) + } + pub fn with_config(config: Config) -> Allocation { let read_size: u32 = Storage::READ_SIZE as _; let write_size: u32 = Storage::WRITE_SIZE as _; let block_size: u32 = Storage::BLOCK_SIZE as _; @@ -163,6 +180,7 @@ impl Allocation { metadata_max: 0, inline_max: 0, disk_version: DISK_VERSION.into(), + flags: config.mount_flags.bits(), }; Self { @@ -208,7 +226,11 @@ impl Filesystem<'_, Storage> { } pub fn format(storage: &mut Storage) -> Result<()> { - let alloc = &mut Allocation::new(); + Self::format_with_config(storage, Config::default()) + } + + pub fn format_with_config(storage: &mut Storage, config: Config) -> Result<()> { + let alloc = &mut Allocation::with_config(config); let fs = Filesystem::new(alloc, storage); let mut alloc = fs.alloc.borrow_mut(); let return_code = unsafe { ll::lfs_format(&mut alloc.state, &alloc.config) }; @@ -217,7 +239,12 @@ impl Filesystem<'_, Storage> { // TODO: check if this is equivalent to `is_formatted`. pub fn is_mountable(storage: &mut Storage) -> bool { - let alloc = &mut Allocation::new(); + Self::is_mountable_with_config(storage, Config::default()) + } + + // TODO: check if this is equivalent to `is_formatted`. + pub fn is_mountable_with_config(storage: &mut Storage, config: Config) -> bool { + let alloc = &mut Allocation::with_config(config); Filesystem::mount(alloc, storage).is_ok() } @@ -233,7 +260,16 @@ impl Filesystem<'_, Storage> { storage: &mut Storage, f: impl FnOnce(&Filesystem<'_, Storage>) -> Result, ) -> Result { - let mut alloc = Allocation::new(); + Self::mount_and_then_with_config(storage, Config::default(), f) + } + + /// This API avoids the need for using `Allocation`. + pub fn mount_and_then_with_config( + storage: &mut Storage, + config: Config, + f: impl FnOnce(&Filesystem<'_, Storage>) -> Result, + ) -> Result { + let mut alloc = Allocation::with_config(config); let fs = Filesystem::mount(&mut alloc, storage)?; f(&fs) } From 68c84b91a1604ed7acc78091bd129cd36033a04e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Fri, 25 Apr 2025 17:49:49 +0200 Subject: [PATCH 02/13] Add support for shrinking/growing filesystems --- src/fs.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/fs.rs b/src/fs.rs index dd62a225..2da7eadb 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -274,6 +274,20 @@ impl Filesystem<'_, Storage> { f(&fs) } + pub fn shrink(&self, block_count: usize) -> Result<()> { + let mut alloc = self.alloc.borrow_mut(); + let return_code = unsafe { ll::lfs_fs_shrink(&mut alloc.state, block_count as _) }; + drop(alloc); + result_from((), return_code) + } + + pub fn grow(&self, block_count: usize) -> Result<()> { + let mut alloc = self.alloc.borrow_mut(); + let return_code = unsafe { ll::lfs_fs_grow(&mut alloc.state, block_count as _) }; + drop(alloc); + result_from((), return_code) + } + /// Total number of blocks in the filesystem pub fn total_blocks(&self) -> usize { Storage::BLOCK_COUNT From 5a6a39f8d0e135635da2bb6154c7be56a9ffd545 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Fri, 25 Apr 2025 17:54:53 +0200 Subject: [PATCH 03/13] Fix avr CI --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 445fd3f4..dcee2df6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -79,7 +79,6 @@ jobs: - name: Patch delog run: | - echo '[patch.crates-io]' >> Cargo.toml echo 'delog = { version = "0.1.6", git = "https://github.com/LechevSpace/delog.git", rev = "e83f3fd" }' >> Cargo.toml - name: Build avr From dcc421506afab2a864249d700edf40cbd1cdae6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Fri, 25 Apr 2025 17:55:20 +0200 Subject: [PATCH 04/13] Fix clippy warnings --- core/src/path.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/path.rs b/core/src/path.rs index 242f5b39..61ad8673 100644 --- a/core/src/path.rs +++ b/core/src/path.rs @@ -338,7 +338,7 @@ impl Path { } pub fn parent(&self) -> Option { - let rk_path_bytes = self.as_ref()[..].as_bytes(); + let rk_path_bytes = self.as_ref().as_bytes(); match rk_path_bytes.iter().rposition(|x| *x == b'/') { Some(0) if rk_path_bytes.len() != 1 => Some(path!("/").into()), Some(slash_index) => { From b8052f1533b62c8ea46d0180feff96d063007009 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Fri, 25 Apr 2025 18:03:46 +0200 Subject: [PATCH 05/13] fixup! Add support for littlefs opening flags --- src/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fs.rs b/src/fs.rs index 2da7eadb..d2c20801 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -88,7 +88,7 @@ pub struct Config { bitflags::bitflags! { #[derive(Default, Clone, Copy,Debug)] - pub struct MountFlags: u32 { + pub struct MountFlags: ll::lfs_fs_flags { const DISABLE_BLOCK_COUNT_CHECK = ll::lfs_fs_flags_LFS_CFG_DISABLE_BLOCK_COUNT_CHECK; } } From 3d33ff513fef44fdbfd772ef31202c1981802d59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Fri, 25 Apr 2025 18:26:12 +0200 Subject: [PATCH 06/13] mount_or_else: give access to allocation in callback --- src/fs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fs.rs b/src/fs.rs index d2c20801..d7975cad 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -1111,11 +1111,11 @@ impl<'a, Storage: driver::Storage> Filesystem<'a, Storage> { f: F, ) -> Result where - F: FnOnce(Error, &mut Storage) -> Result<()>, + F: FnOnce(Error, &mut Storage, &mut Allocation) -> Result<()>, { let fs = Self::new(alloc, storage); if let Err(err) = fs.raw_mount() { - f(err, fs.storage)?; + f(err, fs.storage, &mut fs.alloc.borrow_mut())?; fs.raw_mount()?; } Ok(fs) From f2fc946f632e0691d77ce57d62c1a0a273932351 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Wed, 30 Apr 2025 12:16:23 +0200 Subject: [PATCH 07/13] core: add debug-error feature to have a proper debug implementation of errors --- core/Cargo.toml | 1 + core/src/io.rs | 25 ++++++++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/core/Cargo.toml b/core/Cargo.toml index 2eae6182..54e9f10f 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -22,3 +22,4 @@ heapless-bytes04 = ["dep:heapless-bytes04"] heapless07 = ["dep:heapless07"] heapless08 = ["dep:heapless08"] serde = ["dep:serde"] +debug-error = [] diff --git a/core/src/io.rs b/core/src/io.rs index e04e996a..91a33686 100644 --- a/core/src/io.rs +++ b/core/src/io.rs @@ -202,7 +202,30 @@ impl Error { /// As a short-term fix, the `Debug` implementation currently always returns a static string. impl Debug for Error { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("Error").finish() + #[cfg(not(feature = "debug-error"))] + { + f.debug_struct("Error").finish() + } + #[cfg(feature = "debug-error")] + { + match self { + &Self::IO => f.write_str("IO"), + &Self::CORRUPTION => f.write_str("CORRUPTION"), + &Self::NO_SUCH_ENTRY => f.write_str("NO_SUCH_ENTRY"), + &Self::ENTRY_ALREADY_EXISTED => f.write_str("ENTRY_ALREADY_EXISTED"), + &Self::PATH_NOT_DIR => f.write_str("PATH_NOT_DIR"), + &Self::PATH_IS_DIR => f.write_str("PATH_IS_DIR"), + &Self::DIR_NOT_EMPTY => f.write_str("DIR_NOT_EMPTY"), + &Self::BAD_FILE_DESCRIPTOR => f.write_str("BAD_FILE_DESCRIPTOR"), + &Self::FILE_TOO_BIG => f.write_str("FILE_TOO_BIG"), + &Self::INVALID => f.write_str("INVALID"), + &Self::NO_SPACE => f.write_str("NO_SPACE"), + &Self::NO_MEMORY => f.write_str("NO_MEMORY"), + &Self::NO_ATTRIBUTE => f.write_str("NO_ATTRIBUTE"), + &Self::FILENAME_TOO_LONG => f.write_str("FILENAME_TOO_LONG"), + other => f.debug_tuple("Error").field(&other.code).finish(), + } + } } } From 2d87542f8ec03fb03da8ca739503e0e477e474de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Wed, 30 Apr 2025 12:17:20 +0200 Subject: [PATCH 08/13] mount_or_else: ensure that allocation has not been overwritten in the else clause --- src/fs.rs | 20 ++++++++++++-------- src/tests.rs | 15 ++++++++++++++- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/fs.rs b/src/fs.rs index d7975cad..f26c209e 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -1104,6 +1104,13 @@ impl<'a, Storage: driver::Storage> Filesystem<'a, Storage> { Ok(fs) } + fn set_alloc_config(alloc: &mut Allocation, storage: &mut Storage) { + alloc.config.context = storage as *mut _ as *mut c_void; + alloc.config.read_buffer = alloc.cache.read.get() as *mut c_void; + alloc.config.prog_buffer = alloc.cache.write.get() as *mut c_void; + alloc.config.lookahead_buffer = alloc.cache.lookahead.get() as *mut c_void; + } + /// Mount the filesystem or, if that fails, call `f` with the mount error and the storage and then try again. pub fn mount_or_else( alloc: &'a mut Allocation, @@ -1113,9 +1120,11 @@ impl<'a, Storage: driver::Storage> Filesystem<'a, Storage> { where F: FnOnce(Error, &mut Storage, &mut Allocation) -> Result<()>, { - let fs = Self::new(alloc, storage); + let mut fs = Self::new(alloc, storage); if let Err(err) = fs.raw_mount() { - f(err, fs.storage, &mut fs.alloc.borrow_mut())?; + let alloc = fs.alloc.get_mut(); + f(err, fs.storage, alloc)?; + Self::set_alloc_config(alloc, fs.storage); fs.raw_mount()?; } Ok(fs) @@ -1130,12 +1139,7 @@ impl<'a, Storage: driver::Storage> Filesystem<'a, Storage> { // Not public, user should use `mount`, possibly after `format` fn new(alloc: &'a mut Allocation, storage: &'a mut Storage) -> Self { - alloc.config.context = storage as *mut _ as *mut c_void; - - alloc.config.read_buffer = alloc.cache.read.get() as *mut c_void; - alloc.config.prog_buffer = alloc.cache.write.get() as *mut c_void; - alloc.config.lookahead_buffer = alloc.cache.lookahead.get() as *mut c_void; - + Self::set_alloc_config(alloc, storage); Filesystem { alloc: RefCell::new(alloc), storage, diff --git a/src/tests.rs b/src/tests.rs index 20bc0929..5175b900 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -2,7 +2,7 @@ use core::convert::TryInto; use generic_array::typenum::consts; use crate::{ - fs::{Attribute, File, Filesystem}, + fs::{Allocation, Attribute, File, Filesystem}, io::{Error, OpenSeekFrom, Read, Result, SeekFrom}, path, BACKEND_VERSION, DISK_VERSION, }; @@ -521,6 +521,19 @@ fn test_iter_dirs() { .unwrap(); } +#[test] +fn test_mount_or_else_clobber_alloc() { + let mut backend = Ram::default(); + let mut storage = RamStorage::new(&mut backend); + let alloc = &mut Allocation::new(); + Filesystem::mount_or_else(alloc, &mut storage, |_, storage, alloc| { + *alloc = Allocation::new(); + Filesystem::format(storage).unwrap(); + Ok(()) + }) + .unwrap(); +} + // // These are some tests that ensure our type constructions // // actually do what we intend them to do. // // Since dev-features cannot be optional, trybuild is not `no_std`, From 1d35890824b3ad5b4ddbaf6e335be1894cc07cfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Wed, 30 Apr 2025 12:28:48 +0200 Subject: [PATCH 09/13] Fix avr compilation --- src/fs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fs.rs b/src/fs.rs index f26c209e..5bbdaea1 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -88,8 +88,8 @@ pub struct Config { bitflags::bitflags! { #[derive(Default, Clone, Copy,Debug)] - pub struct MountFlags: ll::lfs_fs_flags { - const DISABLE_BLOCK_COUNT_CHECK = ll::lfs_fs_flags_LFS_CFG_DISABLE_BLOCK_COUNT_CHECK; + pub struct MountFlags: u32 { + const DISABLE_BLOCK_COUNT_CHECK = ll::lfs_fs_flags_LFS_CFG_DISABLE_BLOCK_COUNT_CHECK as _; } } From 33cea6dfd901b44ac2228edfd8284c158c87756e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Wed, 30 Apr 2025 12:35:35 +0200 Subject: [PATCH 10/13] Update littlefs2-sys to use trussed version of littlefs --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ea4c3ba8..6fc2adc1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,4 +59,4 @@ log-error = [] # This means that if we change `traits::Storage::FILENAME_MAX_PLUS_ONE`, # we need to pass this on! [patch.crates-io] -littlefs2-sys = { git = "https://github.com/sosthene-nitrokey/littlefs2-sys", rev = "c0f90bd7c12b41984c8eff550004f1de89c8b1d6" } +littlefs2-sys = { git = "https://github.com/sosthene-nitrokey/littlefs2-sys", rev = "e1fbf664e24d03fc39b538900c681a41a2dd8c88" } From e76c1fd4c2248cf46512d8e32dbe6b3517ee0311 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Mon, 12 May 2025 17:46:31 +0200 Subject: [PATCH 11/13] Use tagged commit --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 6fc2adc1..58632039 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,4 +59,4 @@ log-error = [] # This means that if we change `traits::Storage::FILENAME_MAX_PLUS_ONE`, # we need to pass this on! [patch.crates-io] -littlefs2-sys = { git = "https://github.com/sosthene-nitrokey/littlefs2-sys", rev = "e1fbf664e24d03fc39b538900c681a41a2dd8c88" } +littlefs2-sys = { git = "https://github.com/trussed-dev/littlefs2-sys", rev = "v0.3.1-nitrokey.1" } From e691468328f386a6ee3c4be2d2b19b2cf022869d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Mon, 12 May 2025 18:01:06 +0200 Subject: [PATCH 12/13] Add tests --- src/tests.rs | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/src/tests.rs b/src/tests.rs index 5175b900..55b7de4d 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,8 +1,10 @@ use core::convert::TryInto; use generic_array::typenum::consts; +use littlefs2_core::PathBuf; use crate::{ - fs::{Allocation, Attribute, File, Filesystem}, + driver::Storage, + fs::{Allocation, Attribute, File, Filesystem, MountFlags}, io::{Error, OpenSeekFrom, Read, Result, SeekFrom}, path, BACKEND_VERSION, DISK_VERSION, }; @@ -35,6 +37,20 @@ ram_storage!( path_max_plus_one_ty = consts::U256, ); +ram_storage!( + name = LargerRamStorage, + backend = LargerRam, + erase_value = 0xff, + read_size = 20 * 5, + write_size = 20 * 7, + cache_size_ty = consts::U700, + block_size = 20 * 35, + block_count = 64, + lookahead_size_ty = consts::U16, + filename_max_plus_one_ty = consts::U256, + path_max_plus_one_ty = consts::U256, +); + #[test] fn version() { assert_eq!((BACKEND_VERSION.major(), BACKEND_VERSION.minor()), (2, 9)); @@ -545,3 +561,54 @@ fn test_mount_or_else_clobber_alloc() { // t.compile_fail("tests/ui/*-fail.rs"); // t.pass("tests/ui/*-pass.rs"); // } + +#[test] +fn shrinking() { + let backend = &mut Ram::default(); + let storage = &mut RamStorage::new(backend); + let alloc = &mut Allocation::new(); + + Filesystem::format(storage).unwrap(); + let _fs = Filesystem::mount(alloc, storage).unwrap(); + + let larger_backend = &mut LargerRam::default(); + larger_backend.buf[..backend.buf.len()].copy_from_slice(&backend.buf); + let larger_storage = &mut LargerRamStorage::new(larger_backend); + let larger_alloc = &mut Allocation::new(); + assert!(matches!( + Filesystem::mount(larger_alloc, larger_storage), + Err(Error::INVALID) + )); + + let larger_alloc = &mut Allocation::with_config(crate::fs::Config { + mount_flags: MountFlags::DISABLE_BLOCK_COUNT_CHECK, + }); + + let fs = Filesystem::mount(larger_alloc, larger_storage).unwrap(); + fs.grow(LargerRamStorage::BLOCK_COUNT).unwrap(); + fs.shrink(RamStorage::BLOCK_COUNT).unwrap(); +} + +#[test] +fn shrinking_full() { + let larger_backend = &mut LargerRam::default(); + let larger_storage = &mut LargerRamStorage::new(larger_backend); + let larger_alloc = &mut Allocation::new(); + Filesystem::format(larger_storage).unwrap(); + let fs = Filesystem::mount(larger_alloc, larger_storage).unwrap(); + + for i in 0.. { + let path = format!("file-{i}"); + let contents = &[0; 1024]; + match fs.write(&PathBuf::try_from(&*path).unwrap(), contents) { + Ok(_) => continue, + Err(Error::NO_SPACE) => break, + Err(err) => panic!("{err:?}"), + } + } + + assert!(matches!( + fs.shrink(RamStorage::BLOCK_COUNT), + Err(Error::DIR_NOT_EMPTY) + )) +} From f8d509fe8245f3b43d3011aab92f52c4211e0b63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Tue, 13 May 2025 09:44:02 +0200 Subject: [PATCH 13/13] Add tests that files can still be read after and before shrinknig --- src/tests.rs | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/tests.rs b/src/tests.rs index 55b7de4d..2a0bf9c2 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -569,7 +569,15 @@ fn shrinking() { let alloc = &mut Allocation::new(); Filesystem::format(storage).unwrap(); - let _fs = Filesystem::mount(alloc, storage).unwrap(); + let fs = Filesystem::mount(alloc, storage).unwrap(); + fs.write(path!("some-file"), &[42; 10]).unwrap(); + fs.write(path!("some-large-file"), &[42; 1024]).unwrap(); + + assert_eq!(fs.read::<10>(path!("some-file")).unwrap(), &[42; 10]); + assert_eq!( + fs.read::<1024>(path!("some-large-file")).unwrap(), + &[42; 1024] + ); let larger_backend = &mut LargerRam::default(); larger_backend.buf[..backend.buf.len()].copy_from_slice(&backend.buf); @@ -585,8 +593,25 @@ fn shrinking() { }); let fs = Filesystem::mount(larger_alloc, larger_storage).unwrap(); + assert_eq!(fs.read::<10>(path!("some-file")).unwrap(), &[42; 10]); + assert_eq!( + fs.read::<1024>(path!("some-large-file")).unwrap(), + &[42; 1024] + ); + fs.grow(LargerRamStorage::BLOCK_COUNT).unwrap(); + assert_eq!(fs.read::<10>(path!("some-file")).unwrap(), &[42; 10]); + assert_eq!( + fs.read::<1024>(path!("some-large-file")).unwrap(), + &[42; 1024] + ); + fs.shrink(RamStorage::BLOCK_COUNT).unwrap(); + assert_eq!(fs.read::<10>(path!("some-file")).unwrap(), &[42; 10]); + assert_eq!( + fs.read::<1024>(path!("some-large-file")).unwrap(), + &[42; 1024] + ); } #[test]