Skip to content

Commit

Permalink
core: Move size constants into associated constants
Browse files Browse the repository at this point in the history
To reduce the number of global items and for consistency with constants
like u8::MAX, this patch replaces the size constants ATTRBYTES_MAX,
PATH_MAX and PATH_MAX_PLUS_ONE with associated constants
Attribute::MAX_SIZE, PathBuf::MAX_SIZE and PathBuf::MAX_SIZE_PLUS_ONE.
  • Loading branch information
robin-nitrokey committed Aug 8, 2024
1 parent 1fa16c9 commit 31eff35
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 37 deletions.
3 changes: 0 additions & 3 deletions core/src/consts.rs

This file was deleted.

10 changes: 6 additions & 4 deletions core/src/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,16 +90,18 @@ impl Metadata {
/// [`Filesystem::clear_attribute`](struct.Filesystem.html#method.clear_attribute).
pub struct Attribute {
id: u8,
data: [u8; crate::consts::ATTRBYTES_MAX as _],
data: [u8; Attribute::MAX_SIZE as _],
// invariant: size <= data.len()
size: usize,
}

impl Attribute {
pub const MAX_SIZE: u32 = 1_022;

pub fn new(id: u8) -> Self {
Attribute {
id,
data: [0; crate::consts::ATTRBYTES_MAX as _],
data: [0; Self::MAX_SIZE as _],
size: 0,
}
}
Expand All @@ -109,7 +111,7 @@ impl Attribute {
}

pub fn data(&self) -> &[u8] {
let attr_max = crate::consts::ATTRBYTES_MAX as _;
let attr_max = Self::MAX_SIZE as _;
let len = cmp::min(attr_max, self.size);
&self.data[..len]
}
Expand All @@ -119,7 +121,7 @@ impl Attribute {
}

pub fn set_data(&mut self, data: &[u8]) -> &mut Self {
let attr_max = crate::consts::ATTRBYTES_MAX as _;
let attr_max = Self::MAX_SIZE as _;
let len = cmp::min(attr_max, data.len());
self.data[..len].copy_from_slice(&data[..len]);
self.size = len;
Expand Down
2 changes: 0 additions & 2 deletions core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,11 @@
//!
//! [`littlefs2`]: https://docs.rs/littlefs2

mod consts;
mod fs;
mod io;
mod object_safe;
mod path;

pub use consts::{ATTRBYTES_MAX, PATH_MAX, PATH_MAX_PLUS_ONE};
pub use fs::{Attribute, DirEntry, FileOpenFlags, FileType, Metadata};
pub use io::{Error, OpenSeekFrom, Read, Result, Seek, SeekFrom, Write};
pub use object_safe::{DirEntriesCallback, DynFile, DynFilesystem, FileCallback, Predicate};
Expand Down
55 changes: 29 additions & 26 deletions core/src/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ use core::{
ops, ptr, slice, str,
};

use crate::{consts, path};
use crate::path;

/// A path
///
/// Paths must be null terminated ASCII strings with at most [`PATH_MAX`](`consts::PATH_MAX`) bytes
/// (not including the trailing null).
/// Paths must be null terminated ASCII strings with at most [`PathBuf::MAX_SIZE`][] bytes (not
/// including the trailing null).
// Invariants:
// 1. inner.to_bytes().is_ascii()
// 2. inner.to_bytes().len() <= consts::PATH_MAX
// 2. inner.to_bytes().len() <= PathBuf::MAX_SIZE
#[derive(PartialEq, Eq)]
#[repr(transparent)]
pub struct Path {
Expand Down Expand Up @@ -235,17 +235,17 @@ impl Path {
/// Creates a path from a string.
///
/// The string must only consist of ASCII characters. The last character must be null. It
/// must contain at most [`PATH_MAX`](`consts::PATH_MAX`) bytes, not including the trailing
/// null. If these conditions are not met, this function returns an error.
/// must contain at most [`PathBuf::MAX_SIZE`][] bytes, not including the trailing null. If
/// these conditions are not met, this function returns an error.
pub const fn from_str_with_nul(s: &str) -> Result<&Self> {
Self::from_bytes_with_nul(s.as_bytes())
}

/// Creates a path from a byte buffer.
///
/// The byte buffer must only consist of ASCII characters. The last character must be null.
/// It must contain at most [`PATH_MAX`](`consts::PATH_MAX`) bytes, not including the trailing
/// null. If these conditions are not met, this function returns an error.
/// It must contain at most [`PathBuf::MAX_SIZE`][] bytes, not including the trailing null. If
/// these conditions are not met, this function returns an error.
pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self> {
match CStr::from_bytes_with_nul(bytes) {
Ok(cstr) => Self::from_cstr(cstr),
Expand All @@ -256,13 +256,13 @@ impl Path {
/// Creates a path from a C string.
///
/// The string must only consist of ASCII characters. It must contain at most
/// [`PATH_MAX`](`consts::PATH_MAX`) bytes, not including the trailing null. If these
/// conditions are not met, this function returns an error.
/// [`PathBuf::MAX_SIZE`][] bytes, not including the trailing null. If these conditions are
/// not met, this function returns an error.
// XXX should we reject empty paths (`""`) here?
pub const fn from_cstr(cstr: &CStr) -> Result<&Self> {
let bytes = cstr.to_bytes();
let n = cstr.to_bytes().len();
if n > consts::PATH_MAX {
if n > PathBuf::MAX_SIZE {
Err(PathError::TooLarge)
} else if bytes.is_ascii() {
Ok(unsafe { Self::from_cstr_unchecked(cstr) })
Expand All @@ -275,7 +275,7 @@ impl Path {
///
/// # Safety
/// The string must only consist of ASCII characters. It must contain at most
/// [`PATH_MAX`](`consts::PATH_MAX`) bytes, not including the trailing null.
/// [`PathBuf::MAX_SIZE`][] bytes, not including the trailing null.
pub const unsafe fn from_cstr_unchecked(cstr: &CStr) -> &Self {
&*(cstr as *const CStr as *const Path)
}
Expand Down Expand Up @@ -393,15 +393,15 @@ array_impls!(

/// An owned, mutable path
///
/// Paths must be null terminated ASCII strings with at most [`PATH_MAX`](`consts::PATH_MAX`) bytes
/// (not including the trailing null).
/// Paths must be null terminated ASCII strings with at most [`PathBuf::MAX_SIZE`][] bytes (not
/// including the trailing null).
// Invariants:
// 1. 0 < len <= consts::PATH_MAX_PLUS_ONE
// 1. 0 < len <= PathBuf::MAX_SIZE_PLUS_ONE
// 2. buf[len - 1] == 0
// 3. buf[i].is_ascii() for 0 <= i < len - 1
#[derive(Clone)]
pub struct PathBuf {
buf: [c_char; consts::PATH_MAX_PLUS_ONE],
buf: [c_char; PathBuf::MAX_SIZE_PLUS_ONE],
// NOTE `len` DOES include the final null byte
len: usize,
}
Expand All @@ -424,15 +424,18 @@ impl Default for PathBuf {
}

impl PathBuf {
pub const MAX_SIZE: usize = 255;
pub const MAX_SIZE_PLUS_ONE: usize = Self::MAX_SIZE + 1;

pub const fn new() -> Self {
Self {
buf: [0; consts::PATH_MAX_PLUS_ONE],
buf: [0; Self::MAX_SIZE_PLUS_ONE],
len: 1,
}
}

pub fn clear(&mut self) {
self.buf = [0; consts::PATH_MAX_PLUS_ONE];
self.buf = [0; Self::MAX_SIZE_PLUS_ONE];
self.len = 1;
}

Expand All @@ -441,7 +444,7 @@ impl PathBuf {
/// # Safety
///
/// The buffer must contain only ASCII characters and at least one null byte.
pub unsafe fn from_buffer_unchecked(buf: [c_char; consts::PATH_MAX_PLUS_ONE]) -> Self {
pub unsafe fn from_buffer_unchecked(buf: [c_char; Self::MAX_SIZE_PLUS_ONE]) -> Self {
let len = strlen(buf.as_ptr()) + 1 /* null byte */;
PathBuf { buf, len }
}
Expand Down Expand Up @@ -481,7 +484,7 @@ impl PathBuf {
} else {
0
}
<= consts::PATH_MAX_PLUS_ONE
<= Self::MAX_SIZE_PLUS_ONE
);

let len = self.len;
Expand All @@ -503,9 +506,9 @@ impl From<&Path> for PathBuf {
fn from(path: &Path) -> Self {
let bytes = path.as_ref().as_bytes();

let mut buf = [0; consts::PATH_MAX_PLUS_ONE];
let mut buf = [0; Self::MAX_SIZE_PLUS_ONE];
let len = bytes.len();
assert!(len <= consts::PATH_MAX);
assert!(len <= Self::MAX_SIZE_PLUS_ONE);
unsafe { ptr::copy_nonoverlapping(bytes.as_ptr(), buf.as_mut_ptr().cast(), len + 1) }
Self { buf, len: len + 1 }
}
Expand All @@ -523,7 +526,7 @@ impl TryFrom<&[u8]> for PathBuf {
} else {
bytes
};
if bytes.len() > consts::PATH_MAX {
if bytes.len() > Self::MAX_SIZE {
return Err(PathError::TooLarge);
}
for byte in bytes {
Expand All @@ -535,7 +538,7 @@ impl TryFrom<&[u8]> for PathBuf {
}
}

let mut buf = [0; consts::PATH_MAX_PLUS_ONE];
let mut buf = [0; Self::MAX_SIZE_PLUS_ONE];
let len = bytes.len();
unsafe { ptr::copy_nonoverlapping(bytes.as_ptr(), buf.as_mut_ptr().cast(), len) }
Ok(Self { buf, len: len + 1 })
Expand Down Expand Up @@ -594,7 +597,7 @@ impl<'de> serde::Deserialize<'de> for PathBuf {
where
E: serde::de::Error,
{
if v.len() > consts::PATH_MAX {
if v.len() > PathBuf::MAX_SIZE {
return Err(E::invalid_length(v.len(), &self));
}
PathBuf::try_from(v).map_err(|_| E::custom("invalid path buffer"))
Expand Down Expand Up @@ -653,7 +656,7 @@ pub enum PathError {
NotAscii,
/// Byte buffer is not a C string
NotCStr,
/// Byte buffer is too long (longer than `consts::PATH_MAX_PLUS_ONE`)
/// Byte buffer is too long (longer than [`PathBuf::MAX_SIZE_PLUS_ONE`][])
TooLarge,
}

Expand Down
5 changes: 3 additions & 2 deletions src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
/// Re-export of `typenum::consts`.
pub use generic_array::typenum::consts::*;

pub use littlefs2_core::{ATTRBYTES_MAX, PATH_MAX, PATH_MAX_PLUS_ONE};

pub const PATH_MAX: usize = littlefs2_core::PathBuf::MAX_SIZE;
pub const PATH_MAX_PLUS_ONE: usize = littlefs2_core::PathBuf::MAX_SIZE_PLUS_ONE;
pub const FILENAME_MAX_PLUS_ONE: u32 = 255 + 1;
pub const FILEBYTES_MAX: u32 = crate::ll::LFS_FILE_MAX as _;
pub const ATTRBYTES_MAX: u32 = littlefs2_core::Attribute::MAX_SIZE;
pub const LOOKAHEADWORDS_SIZE: u32 = 16;

0 comments on commit 31eff35

Please sign in to comment.