Skip to content

Commit

Permalink
Updates
Browse files Browse the repository at this point in the history
- rely on new resolver
- remove driver parameters which can't actually be used
- bump heapless

Keeps generic-array, as associated constants still can't be
used as constants.
  • Loading branch information
nickray committed Jun 10, 2021
1 parent 8dee660 commit cdcb99f
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 78 deletions.
29 changes: 5 additions & 24 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,44 +1,25 @@
[package]
name = "littlefs2"
description = "Idiomatic Rust API for littlefs"
version = "0.2.2"
version = "0.3.0"
authors = ["Nicolas Stalder <n@stalder.io>", "Brandon Edens <brandonedens@gmail.com>"]
edition = "2018"
license = "Apache-2.0 OR MIT"
readme = "README.md"
categories = ["embedded", "filesystem", "no-std"]
repository = "https://github.com/nickray/littlefs2"
resolver = "2"

[dependencies]
bitflags = "1"
cty = "0.2.1"
delog = "0.1.0"
generic-array = "0.14.2"
heapless = "0.6"
generic-array = "0.14"
heapless = "0.7"

[dependencies.cstr_core]
default-features = false
# Update: we are just waiting for stabilization of
# https://doc.rust-lang.org/beta/cargo/reference/unstable.html#resolver

# HACK TL;DR :sadface: we are using an older version here to avoid
# rust-lang/cargo#4361 which has been fixed in nightly but lives behind a
# unstable flag as of Rust 1.42.0
#
# longer explanation: this crate depends on bindgen (build dependency) and
# bindgen depends on `memchr` "2" with default features enabled, which include a
# "std" feature that makes the crate depend on `std`. `cstr_core` ">0.1.1" and
# "0.2" also depend on "memchr" but with default features disabled. As this
# crate depends on both it ends up enabling the "std" of the `memchr` crate
# (that's the bug because that shouldn't happen).
#
# To avoid `bindgen` enabling the "std" dependency of `memchr` "2" we use an
# older version of `cstr_core` that depends on version of "1" of `memchr`. This
# way the bug won't enable the "std" of `memchr` "1" (because `memchr` "1" and
# `memchr` "2" are considered different crates)
#
# NB: It really has to be 0.1.0, both 0.1.1 and 0.1.2 don't work
version = "=0.1.0"
version = "0.2"

[dependencies.littlefs2-sys]
version = "0.1.6"
Expand Down
1 change: 1 addition & 0 deletions src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ pub const PATH_MAX: usize = 255;
pub const PATH_MAX_PLUS_ONE: usize = PATH_MAX + 1;
pub const FILEBYTES_MAX: u32 = crate::ll::LFS_FILE_MAX as _;
pub const ATTRBYTES_MAX: u32 = 1_022;
pub type ATTRBYTES_MAX_TYPE = U1022;
pub const LOOKAHEADWORDS_SIZE: u32 = 16;

44 changes: 22 additions & 22 deletions src/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,35 +59,35 @@ pub trait Storage {
type LOOKAHEADWORDS_SIZE: ArrayLength<u32>;
// type LOOKAHEAD_SIZE: ArrayLength<u8>;

/// Maximum length of a filename plus one. Stored in superblock.
/// Should default to 255+1, but associated type defaults don't exist currently.
/// At most 1_022+1.
///
/// TODO: We can't actually change this - need to pass on as compile flag
/// to the C backend.
type FILENAME_MAX_PLUS_ONE: ArrayLength<u8>;
///// Maximum length of a filename plus one. Stored in superblock.
///// Should default to 255+1, but associated type defaults don't exist currently.
///// At most 1_022+1.
/////
///// TODO: We can't actually change this - need to pass on as compile flag
///// to the C backend.
//type FILENAME_MAX_PLUS_ONE: ArrayLength<u8>;

/// Maximum length of a path plus one. Necessary to convert Rust string slices
/// to C strings, which requires an allocation for the terminating
/// zero-byte. If in doubt, set to `FILENAME_MAX_PLUS_ONE`.
/// Must be larger than `FILENAME_MAX_PLUS_ONE`.
type PATH_MAX_PLUS_ONE: ArrayLength<u8>;

/// Maximum size of file. Stored in superblock.
/// Defaults to 2_147_483_647 (or u31, to avoid sign issues in the C code).
/// At most 2_147_483_647.
///
/// TODO: We can't actually change this - need to pass on as compile flag
/// to the C backend.
const FILEBYTES_MAX: usize = ll::LFS_FILE_MAX as _;

/// Maximum size of custom attributes.
/// Should default to 1_022, but associated type defaults don't exists currently.
/// At most 1_022.
///
/// TODO: We can't actually change this - need to pass on as compile flag
/// to the C backend.
type ATTRBYTES_MAX: ArrayLength<u8>;
///// Maximum size of file. Stored in superblock.
///// Defaults to 2_147_483_647 (or u31, to avoid sign issues in the C code).
///// At most 2_147_483_647.
/////
///// TODO: We can't actually change this - need to pass on as compile flag
///// to the C backend.
//const FILEBYTES_MAX: usize = ll::LFS_FILE_MAX as _;

///// Maximum size of custom attributes.
///// Should default to 1_022, but associated type defaults don't exists currently.
///// At most 1_022.
/////
///// TODO: We can't actually change this - need to pass on as compile flag
///// to the C backend.
//type ATTRBYTES_MAX: ArrayLength<u8>;

/// Read data from the storage device.
/// Guaranteed to be called only with bufs of length a multiple of READ_SIZE.
Expand Down
55 changes: 34 additions & 21 deletions src/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ pub struct Allocation<Storage: driver::Storage> {

// pub fn check_storage_requirements(

impl<Storage: driver::Storage> Default for Allocation<Storage> {
fn default() -> Self {
Self::new()
}
}
impl<Storage: driver::Storage> Allocation<Storage> {

pub fn new() -> Allocation<Storage> {
Expand Down Expand Up @@ -86,21 +91,20 @@ impl<Storage: driver::Storage> Allocation<Storage> {

let cache = Cache::new();

let filename_max_plus_one: u32 =
<Storage as driver::Storage>::FILENAME_MAX_PLUS_ONE::to_u32();
let filename_max_plus_one: u32 = crate::consts::FILENAME_MAX_PLUS_ONE;
debug_assert!(filename_max_plus_one > 1);
debug_assert!(filename_max_plus_one <= 1_022+1);
// limitation of ll-bindings
debug_assert!(filename_max_plus_one == 255+1);
let path_max_plus_one: u32 = <Storage as driver::Storage>::PATH_MAX_PLUS_ONE::to_u32();
// TODO: any upper limit?
debug_assert!(path_max_plus_one >= filename_max_plus_one);
let file_max = Storage::FILEBYTES_MAX as u32;
let file_max = crate::consts::FILEBYTES_MAX;
assert!(file_max > 0);
assert!(file_max <= 2_147_483_647);
// limitation of ll-bindings
assert!(file_max == 2_147_483_647);
let attr_max: u32 = <Storage as driver::Storage>::ATTRBYTES_MAX::to_u32();
let attr_max: u32 = crate::consts::ATTRBYTES_MAX;
assert!(attr_max > 0);
assert!(attr_max <= 1_022);
// limitation of ll-bindings
Expand Down Expand Up @@ -130,7 +134,7 @@ impl<Storage: driver::Storage> Allocation<Storage> {

name_max: filename_max_plus_one.wrapping_sub(1),
file_max,
attr_max: attr_max,
attr_max,
};

Self {
Expand Down Expand Up @@ -237,10 +241,7 @@ impl<Storage: driver::Storage> Filesystem<'_, Storage> {
// TODO: check if this is equivalent to `is_formatted`.
pub fn is_mountable(storage: &mut Storage) -> bool {
let alloc = &mut Allocation::new();
match Filesystem::mount(alloc, storage) {
Ok(_) => true,
_ => false,
}
matches!(Filesystem::mount(alloc, storage), Ok(_))
}

// Can BorrowMut be implemented "unsafely" instead?
Expand Down Expand Up @@ -434,10 +435,10 @@ impl<Storage: driver::Storage> Filesystem<'_, Storage> {
path: &Path,
id: u8,
) ->
Result<Option<Attribute<Storage>>>
Result<Option<Attribute>>
{
let mut attribute = Attribute::new(id);
let attr_max = <Storage as driver::Storage>::ATTRBYTES_MAX::to_u32();
let attr_max = crate::consts::ATTRBYTES_MAX;

let return_code = unsafe { ll::lfs_getattr(
&mut self.alloc.borrow_mut().state,
Expand Down Expand Up @@ -478,7 +479,7 @@ impl<Storage: driver::Storage> Filesystem<'_, Storage> {
pub fn set_attribute(
&self,
path: &Path,
attribute: &Attribute<Storage>
attribute: &Attribute,
) ->
Result<()>
{
Expand Down Expand Up @@ -571,13 +572,13 @@ impl<Storage: driver::Storage> Filesystem<'_, Storage> {
/// Use [`Filesystem::attribute`](struct.Filesystem.html#method.attribute),
/// [`Filesystem::set_attribute`](struct.Filesystem.html#method.set_attribute), and
/// [`Filesystem::clear_attribute`](struct.Filesystem.html#method.clear_attribute).
pub struct Attribute<S: driver::Storage> {
pub struct Attribute {
id: u8,
data: Bytes<S::ATTRBYTES_MAX>,
data: Bytes<crate::consts::ATTRBYTES_MAX_TYPE>,
size: usize,
}

impl<S: driver::Storage> Attribute<S> {
impl Attribute {
pub fn new(id: u8) -> Self {
Attribute {
id,
Expand All @@ -591,13 +592,13 @@ impl<S: driver::Storage> Attribute<S> {
}

pub fn data(&self) -> &[u8] {
let attr_max = <S as driver::Storage>::ATTRBYTES_MAX::to_usize();
let attr_max = crate::consts::ATTRBYTES_MAX as _;
let len = cmp::min(attr_max, self.size);
&self.data[..len]
}

pub fn set_data(&mut self, data: &[u8]) -> &mut Self {
let attr_max = <S as driver::Storage>::ATTRBYTES_MAX::to_usize();
let attr_max = crate::consts::ATTRBYTES_MAX as _;
let len = cmp::min(attr_max, data.len());
self.data[..len].copy_from_slice(&data[..len]);
self.size = len;
Expand Down Expand Up @@ -638,6 +639,12 @@ pub struct FileAllocation<S: driver::Storage>
config: ll::lfs_file_config,
}

impl<S: driver::Storage> Default for FileAllocation<S> {
fn default() -> Self {
Self::new()
}
}

impl<S: driver::Storage> FileAllocation<S> {
pub fn new() -> Self {
let cache_size: u32 = <S as driver::Storage>::CACHE_SIZE::to_u32();
Expand Down Expand Up @@ -782,7 +789,7 @@ impl<'a, 'b, Storage: driver::Storage> File<'a, 'b, Storage>
}

// This belongs in `io::Read` but really don't want that to have a generic parameter
pub fn read_to_end<N: heapless::ArrayLength<u8>>(&self, buf: &mut heapless::Vec<u8, N>) -> Result<usize> {
pub fn read_to_end<const N: usize>(&self, buf: &mut heapless::Vec<u8, N>) -> Result<usize> {
// My understanding of
// https://github.com/ARMmbed/littlefs/blob/4c9146ea539f72749d6cc3ea076372a81b12cb11/lfs.c#L2816
// is that littlefs keeps reading until either the buffer is full, or the file is exhausted
Expand Down Expand Up @@ -1032,6 +1039,12 @@ pub struct ReadDirAllocation {
state: ll::lfs_dir_t,
}

impl Default for ReadDirAllocation {
fn default() -> Self {
Self::new()
}
}

impl ReadDirAllocation {
pub fn new() -> Self {
unsafe { mem::MaybeUninit::zeroed().assume_init() }
Expand Down Expand Up @@ -1258,7 +1271,7 @@ impl<'a, Storage: driver::Storage> Filesystem<'a, Storage> {
}

/// Read the entire contents of a file into a bytes vector.
pub fn read<N: generic_array::ArrayLength<u8>>(
pub fn read<const N: usize>(
&self,
path: &Path,
)
Expand Down Expand Up @@ -1375,7 +1388,7 @@ mod tests {
println!("\nfile {}: {:?}", i, entry.file_name());

if entry.file_type().is_file() {
let content: heapless::Vec::<u8, heapless::consts::U256> = fs.read(entry.path())?;
let content: heapless::Vec::<u8, 256> = fs.read(entry.path())?;
println!("content:\n{:?}", core::str::from_utf8(&content).unwrap());
// println!("and now the removal");
// fs.remove(entry.path())?;
Expand Down Expand Up @@ -1476,7 +1489,7 @@ mod tests {
}
)?;

let content: heapless::Vec<_, consts::U256> = fs.read(filename)?;
let content: heapless::Vec<_, 256> = fs.read(filename)?;
assert_eq!(content, b"first part - second part");
// println!("content: {:?}", core::str::from_utf8(&content).unwrap());
Ok(())
Expand Down
4 changes: 0 additions & 4 deletions src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,7 @@ macro_rules! ram_storage { (
const BLOCK_SIZE: usize = $block_size;
const BLOCK_COUNT: usize = $block_count;
type LOOKAHEADWORDS_SIZE = $lookaheadwords_size;
type FILENAME_MAX_PLUS_ONE = $filename_max_plus_one;
type PATH_MAX_PLUS_ONE = $path_max_plus_one;
type ATTRBYTES_MAX = consts::U1022;

fn read(&self, offset: usize, buf: &mut [u8]) -> $Result<usize> {
let read_size: usize = Self::READ_SIZE;
Expand Down Expand Up @@ -182,9 +180,7 @@ macro_rules! const_ram_storage { (
const BLOCK_SIZE: usize = $block_size;
const BLOCK_COUNT: usize = $block_count;
type LOOKAHEADWORDS_SIZE = $lookaheadwords_size;
type FILENAME_MAX_PLUS_ONE = $filename_max_plus_one;
type PATH_MAX_PLUS_ONE = $path_max_plus_one;
type ATTRBYTES_MAX = consts::U1022;

fn read(&self, offset: usize, buf: &mut [u8]) -> $Result<usize> {
let read_size: usize = Self::READ_SIZE;
Expand Down
8 changes: 4 additions & 4 deletions src/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ impl Path {
///
/// The buffer will be first interpreted as a `CStr` and then checked to be comprised only of
/// ASCII characters.
pub fn from_bytes_with_nul<'b>(bytes: &'b [u8]) -> Result<&'b Self> {
pub fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self> {
let cstr = CStr::from_bytes_with_nul(bytes).map_err(|_| Error::NotCStr)?;
Self::from_cstr(cstr)
}
Expand All @@ -40,7 +40,7 @@ impl Path {
///
/// The string will be checked to be comprised only of ASCII characters
// XXX should we reject empty paths (`""`) here?
pub fn from_cstr<'s>(cstr: &'s CStr) -> Result<&'s Self> {
pub fn from_cstr(cstr: &CStr) -> Result<&Self> {
let bytes = cstr.to_bytes();
let n = cstr.to_bytes().len();
if n > consts::PATH_MAX {
Expand Down Expand Up @@ -277,7 +277,7 @@ impl From<&[u8]> for PathBuf {
fn from(bytes: &[u8]) -> Self {
// NB: This needs to set the final NUL byte, unless it already has one
// It also checks that there are no inner NUL bytes
let bytes = if bytes.len() > 0 && bytes[bytes.len() - 1] == b'\0' {
let bytes = if !bytes.is_empty() && bytes[bytes.len() - 1] == b'\0' {
&bytes[..bytes.len() - 1]
} else {
bytes
Expand Down Expand Up @@ -347,7 +347,7 @@ impl<'de> serde::Deserialize<'de> for PathBuf
E: serde::de::Error,
{
if v.len() > consts::PATH_MAX {
return Err(E::invalid_length(v.len(), &self))?;
return Err(E::invalid_length(v.len(), &self));
}
Ok(PathBuf::from(v))
}
Expand Down
6 changes: 3 additions & 3 deletions src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ fn test_create() {

// alternative approach
file.seek(SeekFrom::Start(0))?;
let mut contents_vec = heapless::Vec::<u8, consts::U3>::new();
let mut contents_vec = heapless::Vec::<u8, 3>::new();
assert!(file.read_to_end(&mut contents_vec).unwrap() == 3);
Ok(())
})?;
Expand Down Expand Up @@ -273,7 +273,7 @@ fn test_unbind() {

let mut storage = RamStorage::new(&mut backend);
Filesystem::mount_and_then(&mut storage, |fs| {
let contents: heapless::Vec<_, consts::U37> = fs.read(b"test_unbind.txt\0".try_into().unwrap())?;
let contents: heapless::Vec<_, 37> = fs.read(b"test_unbind.txt\0".try_into().unwrap())?;
assert_eq!(contents, b"hello world");
Ok(())
}).unwrap();
Expand Down Expand Up @@ -358,7 +358,7 @@ fn attributes() {
fs.write(filename, &[])?;
assert!(fs.attribute(filename, 37)?.is_none());

let mut attribute = Attribute::<RamStorage>::new(37);
let mut attribute = Attribute::new(37);
attribute.set_data(b"top secret");

fs.set_attribute(filename, &attribute).unwrap();
Expand Down

0 comments on commit cdcb99f

Please sign in to comment.