Idiomatic Rust API for littlefs

Idiomatic Rust API for the Chris Haster

littlefs2


What is this?

Idiomatic Rust API for the littlefs microcontroller filesystem by Chris Haster.

Number 2 refers to the on-disk format version, supporting inline files, custom attributes and dynamic wear-leveling.

We follow std::fs as much as reasonable.

The low-level bindings are provided by the littlefs2-sys library.

Upstream release: v2.1.4

License

littlefs is licensed under BSD-3-Clause. This API for littlefs is licensed under either of Apache License, Version 2.0 or MIT License at your option. Previous bindings exist in the rust-littlefs repository, also dual-licensed under Apache-2.0 and MIT.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Issues

Collection of the latest Issues

gauteh

gauteh

6

Hi, just discovered this lib. Seems like something very useful for storing data on an sd card on a microcontroller. When I try to add this library to a no_std binary I get errors with memchr, does it require std with an allocator?

nickray

nickray

0

The path::{Filename,Path} objects are not very well-developed yet. I am aware of the following issues:

  • It would be nice to use heapless::Vec for paths, and handle back and forth with C strings in littlefs-sys ergonomically
  • Our Path is more like std::path::PathBuf, we want to "follow std::path as much as appropriate"
  • Upstream has no notion (I believe) of maximum path, whereas we should
  • Upstream uses LFS_NAME_MAX in lfs_info_t (https://github.com/ARMmbed/littlefs/blob/master/lfs.h#L257), which we can only override via littlefs2-sys features. If we don't, then FILENAME_MAX_PLUS_ONE should be removed (set to its default of 256)
  • From the path machinery (ancestors etc.), at least join (or try_join) needs a clean implementation, need to decide how to handle length overflows (maybe just truncate?)
nickray

nickray

0

There seems to be some flexibility in what can be done while iterating over a directory, for instance the current file can be read, and it can even be deleted.

However, some things must be prevented. E.g. in a setup like

if c.txt is deleted while the iterator is at b.txt, there's a crash: thread 'fsc::tests::todo' panicked at 'slice index starts at 4294966960 but ends at 4096', src/libcore/slice/mod.rs:2680:5

The plan is then to have read_dir_and_then expose a RestrictedFilesystem, that e.g. might prevent Filesystem::remove (mark as unsafe, or remove method completely).

We do want to keep Filesystem::remove_dir_all for instance, though.

japaric

japaric

0

test/ui/sync-fail.rs shows how trying to close a file on a different filesystem fails at compile time. That compile time protection holds in that example because each filesystem instance has a different type but one can, in safe code, create multiple FS instances of the same type and then close a file on a different filesystem instance (that's still the same type). Variation of test/ui/sync-fail.rs that shows this:

Here ram1 and ram2 point to different to different memory blocks. The above example doesn't appear to trigger UB but it's probably corrupting the second filesystem. A more complex variation of the above example may cause UB though.

A potential solution to this is to make trait Storage unsafe and require that's implemented on singleton types. This way all instances of Ram are handles to the same memory (but then you have be careful about Rust aliasing rules and will likely have to make Ram !Send and !Sync ...)

japaric

japaric

6

UPDATE: Added Steps To Reproduce (STR) on x86_64

STR1

asan: fs and File clash


STR2

msan: fs clashes with itself


Original report

Given this directory structure:

I'm observing the following pseudo-code hang:

And a slightly different program causes the device to hard fault:


If I'm reading https://github.com/ARMmbed/littlefs/issues/164#issuecomment-481553076 correctly not closing either a file or a directory can result in UB.

In the case of ReadDir, the lfs_dir_create C function is called but its counterpart, lfs_dir_close, is never called.

Because mem::forget (and other ways of leaking memory) are considered "safe" (don't require unsafe to call), calling lfs_dir_close from ReadDir's destructor is not going to be sufficient to fix this soundness hole. See below:

I think the API would need to become closure-based to ensure lfs_dir_close is always called. Something like this:

If the same issue (forget to close == UB) applies to Files then a closure-based API would also be needed there to avoid UB in safe code.

As an additional note: is one allowed to modify the directory structure (e.g. call Filesystem::remove) while iterating it with read_dir? It's possible to overlap these operations with the current ReadDir API but the overlap of those actions could be rejected at compile time if ReadDir mutably borrowed Filesystem. I couldn't find an answer to this question myself -- where is littlefs API documented? One of the header files contains what appear to be doc comments but those don't describe what one is allowed to or not to do with the API.

jonas-schievink

jonas-schievink

2

Currently the user has to statically know the device size since BLOCK_COUNT is an associated constant. It would be useful if it would be possible to dynamically determine the device size instead.

ryankurte

ryankurte

6

Hi hi, thanks for making a neat thing ^_^

I'm about to use littlefs in a project and I was just wondering whether there are outstanding issues / what you're waiting for for a non-alpha v0.x release?

Cheers,

Ryan

Versions

Find the latest versions by id

Information - Updated Apr 01, 2022

Stars: 19
Forks: 3
Issues: 8

Repositories & Extras

rust_embedded_starter

Boilerplate für Embedded Entwicklung mit Rust mit Flash und Debug automatik

rust_embedded_starter

Embedded rust HAL (hardware abstraction layer) for the STM32WL

This is a work in progress, it is unstable, incomplete, and (mostly) untested

Embedded rust HAL (hardware abstraction layer) for the STM32WL

Embedded Rust Template

This template is based on stm32f4xx-hal

Embedded Rust Template

A Rust embedded-hal HAL for all MCUs in the STM32 F7 family

This crate is largely inspired by the awesome work done here:

A Rust embedded-hal HAL for all MCUs in the STM32 F7 family

For use with the AnyLeaf pH and RTD sensors in Rust on embedded systems, and...

For use with the AnyLeaf pH and RTD sensors in Rust on embedded systems, and single-board computers

For use with the AnyLeaf pH and RTD sensors in Rust on embedded systems, and...

An embedded rust no_std driver for the AHT20 temperature and humidity sensor, forked from Anthony...

An embedded rust no_std driver for the AHT20 temperature and humidity sensor, forked from Anthony Romano's docs

An embedded rust no_std driver for the AHT20 temperature and humidity sensor, forked from Anthony...

embedded-rust-H2AL

Hardware abstraction layer - abstraction layer

embedded-rust-H2AL

cargo-pio = Cargo + PlatformIO

Build Rust embedded projects with PlatformIO!

cargo-pio = Cargo + PlatformIO
Facebook Instagram Twitter GitHub Dribbble
Privacy