so much rewriting
This commit is contained in:
parent
fe18eb56ef
commit
e584061d2e
3 changed files with 5529 additions and 5565 deletions
336
src/littlefs.rs
336
src/littlefs.rs
|
@ -1,6 +1,6 @@
|
|||
use std::{cmp::Ordering, mem::size_of};
|
||||
|
||||
use crate::util::{self, lfs_aligndown, lfs_alignup, lfs_min};
|
||||
use crate::util::{self, lfs_aligndown, lfs_alignup, lfs_crc, lfs_fromle32, lfs_max, lfs_min, lfs_tole32};
|
||||
|
||||
/// Software library version
|
||||
/// Major (top-nibble), incremented on backwards incompatible changes
|
||||
|
@ -41,9 +41,6 @@ pub const LFS_ATTR_MAX: u32 = 1022;
|
|||
/// Possible error codes, these are negative to allow
|
||||
/// valid positive return values
|
||||
pub enum LfsError {
|
||||
/// No error
|
||||
Ok = 0,
|
||||
|
||||
/// Error during device operation
|
||||
Io = -5,
|
||||
|
||||
|
@ -202,7 +199,7 @@ pub struct LfsConfig {
|
|||
offset: LfsOff,
|
||||
buffer: &mut [u8],
|
||||
size: LfsSize,
|
||||
) -> LfsError,
|
||||
) -> Result<(), LfsError>,
|
||||
|
||||
/// Program a region in a block. The block must have previously
|
||||
/// been erased. Negative error codes are propagated to the user.
|
||||
|
@ -213,23 +210,17 @@ pub struct LfsConfig {
|
|||
offset: LfsOff,
|
||||
buffer: &[u8],
|
||||
size: LfsSize,
|
||||
) -> LfsError,
|
||||
) -> Result<(), LfsError>,
|
||||
|
||||
/// Erase a block. A block must be erased before being programmed.
|
||||
/// The state of an erased block is undefined. Negative error codes
|
||||
/// are propagated to the user.
|
||||
/// May return LFS_ERR_CORRUPT if the block should be considered bad.
|
||||
erase: fn(config: &LfsConfig, block: LfsBlock) -> LfsError,
|
||||
erase: fn(config: &LfsConfig, block: LfsBlock) -> Result<(), LfsError>,
|
||||
|
||||
/// Sync the state of the underlying block device. Negative error codes
|
||||
/// are propagated to the user.
|
||||
sync: fn(
|
||||
config: &LfsConfig,
|
||||
block: LfsBlock,
|
||||
offset: LfsOff,
|
||||
buffer: &mut [u8],
|
||||
size: LfsSize,
|
||||
) -> LfsError,
|
||||
sync: fn(config: &LfsConfig) -> Result<(), LfsError>,
|
||||
|
||||
/// Lock the underlying block device. Negative error codes
|
||||
/// are propagated to the user.
|
||||
|
@ -513,7 +504,23 @@ struct Lfs {
|
|||
/// Caching block device operations ///
|
||||
|
||||
const LFS_BLOCK_NULL: u32 = 0x00;
|
||||
// const LFS_BLOCK_NULL = 0x01;
|
||||
const LFS_BLOCK_INLINE: u32 = 0x01;
|
||||
|
||||
// === TEMPORARY METHODS ===
|
||||
|
||||
fn memcmp(buffer: &[u8], other: &[u8], size: impl TryInto<usize>) -> i32 {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn memcpy(buffer: &[u8], other: &[u8], size: impl TryInto<usize>) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn memset(buffer: &[u8], with: u8, size: impl TryInto<usize>) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
// === ACTUAL CODE ===
|
||||
|
||||
fn lfs_cache_drop(lfs: &Lfs, rcache: &mut LfsCache) {
|
||||
// do not zero, cheaper if cache is readonly or only going to be
|
||||
|
@ -529,17 +536,17 @@ fn lfs_cache_zero(lfs: &Lfs, pcache: &mut LfsCache) {
|
|||
|
||||
fn lfs_bd_read(
|
||||
lfs: &Lfs,
|
||||
pcache: &LfsCache,
|
||||
rcache: &LfsCache,
|
||||
pcache: &mut LfsCache,
|
||||
rcache: &mut LfsCache,
|
||||
hint: LfsSize,
|
||||
block: LfsBlock,
|
||||
mut off: LfsOff,
|
||||
buffer: &mut [u8],
|
||||
mut size: LfsSize,
|
||||
) -> LfsError {
|
||||
) -> Result<(), LfsError> {
|
||||
let mut data: &[u8] = buffer;
|
||||
if (off + size > lfs.cfg.block_size || (lfs.block_count != 0 && block >= lfs.block_count)) {
|
||||
return LfsError::Corrupt;
|
||||
return Err(LfsError::Corrupt);
|
||||
}
|
||||
|
||||
while size > 0 {
|
||||
|
@ -589,17 +596,13 @@ fn lfs_bd_read(
|
|||
if (size >= hint && off % lfs.cfg.read_size == 0 && size >= lfs.cfg.read_size) {
|
||||
// bypass cache?
|
||||
diff = lfs_aligndown(diff, lfs.cfg.read_size);
|
||||
let err: LfsError = (lfs.cfg.read)(
|
||||
(lfs.cfg.read)(
|
||||
&lfs.cfg,
|
||||
rcache.block,
|
||||
rcache.off,
|
||||
&mut rcache.buffer,
|
||||
rcache.size,
|
||||
);
|
||||
match err {
|
||||
LfsError::Ok => (),
|
||||
err => return err,
|
||||
}
|
||||
)?;
|
||||
|
||||
data = &data[diff as usize..];
|
||||
off += diff;
|
||||
|
@ -618,26 +621,22 @@ fn lfs_bd_read(
|
|||
) - rcache.off,
|
||||
lfs.cfg.cache_size,
|
||||
);
|
||||
let err: LfsError = (lfs.cfg.read)(
|
||||
(lfs.cfg.read)(
|
||||
&lfs.cfg,
|
||||
rcache.block,
|
||||
rcache.off,
|
||||
&mut rcache.buffer,
|
||||
rcache.size,
|
||||
);
|
||||
match err {
|
||||
LfsError::Ok => (),
|
||||
err => return err,
|
||||
}
|
||||
)?;
|
||||
}
|
||||
|
||||
return LfsError::Ok;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn lfs_bd_cmp(
|
||||
lfs: &Lfs,
|
||||
pcache: &LfsCache,
|
||||
rcache: &LfsCache,
|
||||
pcache: &mut LfsCache,
|
||||
rcache: &mut LfsCache,
|
||||
hint: LfsSize,
|
||||
block: LfsBlock,
|
||||
off: LfsOff,
|
||||
|
@ -652,7 +651,7 @@ fn lfs_bd_cmp(
|
|||
let mut dat = [0u8; 8];
|
||||
|
||||
diff = lfs_min(size - i, 0);
|
||||
let err = lfs_bd_read(
|
||||
lfs_bd_read(
|
||||
lfs,
|
||||
pcache,
|
||||
rcache,
|
||||
|
@ -661,11 +660,7 @@ fn lfs_bd_cmp(
|
|||
off + i,
|
||||
&mut dat,
|
||||
diff,
|
||||
);
|
||||
match err {
|
||||
LfsError::Ok => (),
|
||||
err => return Err(err),
|
||||
};
|
||||
)?;
|
||||
|
||||
let res: i32 = memcmp(&dat, &data[i as usize..], diff);
|
||||
if (res != 0) {
|
||||
|
@ -685,14 +680,263 @@ fn lfs_bd_cmp(
|
|||
Ok(Ordering::Equal)
|
||||
}
|
||||
|
||||
fn memcmp(buffer: &[u8], other: &[u8], size: impl TryInto<usize>) -> i32 {
|
||||
todo!()
|
||||
fn lfs_bd_crc(lfs: &Lfs,
|
||||
pcache: &mut LfsCache, rcache: &mut LfsCache, hint: LfsSize,
|
||||
block: LfsBlock, off: LfsOff, size: LfsSize, crc: &mut u32) -> Result<(), LfsError> {
|
||||
let mut diff: LfsSize = 0;
|
||||
|
||||
let mut i: LfsOff = 0;
|
||||
while (i < size) {
|
||||
let mut dat = [0u8; 8];
|
||||
diff = lfs_min(size-i, 8);
|
||||
lfs_bd_read(lfs,
|
||||
pcache, rcache, hint-i,
|
||||
block, off+i, &mut dat, diff)?;
|
||||
|
||||
*crc = lfs_crc(*crc, &dat, diff as usize);
|
||||
|
||||
i += diff;
|
||||
if i >= size {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn memcpy(buffer: &[u8], other: &[u8], size: impl TryInto<usize>) {
|
||||
todo!()
|
||||
const NULL: u32 = 0;
|
||||
|
||||
fn lfs_bd_flush(lfs: &Lfs, pcache: &mut LfsCache, rcache: &mut LfsCache, validate: bool) -> Result<(), LfsError> {
|
||||
if (pcache.block != LFS_BLOCK_NULL && pcache.block != LFS_BLOCK_INLINE) {
|
||||
assert!(pcache.block < lfs.block_count);
|
||||
let diff: LfsSize = lfs_alignup(pcache.size, lfs.cfg.prog_size);
|
||||
(lfs.cfg.prog)(&lfs.cfg, pcache.block, pcache.off, &pcache.buffer, diff)?;
|
||||
|
||||
if (validate) {
|
||||
// check data on disk
|
||||
lfs_cache_drop(lfs, rcache);
|
||||
let mut null: &mut LfsCache = unsafe { std::ptr::null_mut::<LfsCache>().as_mut().expect("this will always fail, TODO: fixme") };
|
||||
let order = lfs_bd_cmp(lfs,
|
||||
null, rcache, diff,
|
||||
pcache.block, pcache.off, &mut pcache.buffer, diff)?;
|
||||
|
||||
if (order != Ordering::Equal) {
|
||||
return Err(LfsError::Corrupt);
|
||||
}
|
||||
}
|
||||
|
||||
lfs_cache_zero(lfs, pcache);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn memset(buffer: &[u8], with: u8, size: impl TryInto<usize>) {
|
||||
todo!()
|
||||
fn lfs_bd_sync(lfs: &Lfs, pcache: &mut LfsCache, rcache: &mut LfsCache, validate: bool) -> Result<(), LfsError> {
|
||||
lfs_cache_drop(lfs, rcache);
|
||||
lfs_bd_flush(lfs, pcache, rcache, validate)?;
|
||||
(lfs.cfg.sync)(&lfs.cfg)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn lfs_bd_prog(lfs: &Lfs,
|
||||
pcache: &mut LfsCache, rcache: &mut LfsCache, validate: bool,
|
||||
block: LfsBlock, mut off: LfsOff,
|
||||
buffer: &[u8], mut size: LfsSize) -> Result<(), LfsError> {
|
||||
let mut data: &[u8] = buffer;
|
||||
assert!(block == LFS_BLOCK_INLINE || block < lfs.block_count);
|
||||
assert!(off + size <= lfs.cfg.block_size);
|
||||
|
||||
while (size > 0) {
|
||||
if (block == pcache.block &&
|
||||
off >= pcache.off &&
|
||||
off < pcache.off + lfs.cfg.cache_size) {
|
||||
// already fits in pcache?
|
||||
let diff: LfsSize = lfs_min(size,
|
||||
lfs.cfg.cache_size - (off-pcache.off));
|
||||
memcpy(&pcache.buffer[(off-pcache.off) as usize..], data, diff);
|
||||
|
||||
data = &data[diff as usize..];
|
||||
off += diff;
|
||||
size -= diff;
|
||||
|
||||
pcache.size = lfs_max(pcache.size, off - pcache.off);
|
||||
if (pcache.size == lfs.cfg.cache_size) {
|
||||
// eagerly flush out pcache if we fill up
|
||||
lfs_bd_flush(lfs, pcache, rcache, validate)?;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// pcache must have been flushed, either by programming and
|
||||
// entire block or manually flushing the pcache
|
||||
assert!(pcache.block == LFS_BLOCK_NULL);
|
||||
|
||||
// prepare pcache, first condition can no longer fail
|
||||
pcache.block = block;
|
||||
pcache.off = lfs_aligndown(off, lfs.cfg.prog_size);
|
||||
pcache.size = 0;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn lfs_bd_erase(lfs: &Lfs, block: LfsBlock) -> Result<(), LfsError> {
|
||||
assert!(block < lfs.block_count);
|
||||
(lfs.cfg.erase)(&lfs.cfg, block)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Small type-level utilities ///
|
||||
// operations on block pairs
|
||||
fn lfs_pair_swap(pair: &mut (LfsBlock, LfsBlock)) {
|
||||
std::mem::swap(&mut pair.0, &mut pair.1);
|
||||
}
|
||||
|
||||
fn lfs_pair_isnull(pair: (LfsBlock, LfsBlock)) -> bool {
|
||||
return pair.0 == LFS_BLOCK_NULL || pair.1 == LFS_BLOCK_NULL;
|
||||
}
|
||||
|
||||
fn lfs_pair_cmp(
|
||||
paira: (LfsBlock, LfsBlock),
|
||||
pairb: (LfsBlock, LfsBlock)) -> bool {
|
||||
return !(paira.0 == pairb.0 || paira.1 == pairb.1 ||
|
||||
paira.0 == pairb.1 || paira.1 == pairb.0);
|
||||
}
|
||||
|
||||
fn lfs_pair_issync(
|
||||
paira: (LfsBlock, LfsBlock),
|
||||
pairb: (LfsBlock, LfsBlock)) -> bool {
|
||||
return (paira.0 == pairb.0 && paira.1 == pairb.1) ||
|
||||
(paira.0 == pairb.1 && paira.1 == pairb.0);
|
||||
}
|
||||
|
||||
fn lfs_pair_fromle32(pair: &mut (LfsBlock, LfsBlock)) {
|
||||
pair.0 = lfs_fromle32(pair.0);
|
||||
pair.1 = lfs_fromle32(pair.1);
|
||||
}
|
||||
|
||||
fn lfs_pair_tole32(pair: &mut (LfsBlock, LfsBlock)) {
|
||||
pair.0 = lfs_tole32(pair.0);
|
||||
pair.1 = lfs_tole32(pair.1);
|
||||
}
|
||||
|
||||
// operations on 32-bit entry tags
|
||||
type LfsTag = u32;
|
||||
type LfsStag = i32;
|
||||
|
||||
// #define LFS_MKTAG(type, id, size) \
|
||||
// (((lfs_tag_t)(type) << 20) | ((lfs_tag_t)(id) << 10) | (lfs_tag_t)(size))
|
||||
|
||||
// #define LFS_MKTAG_IF(cond, type, id, size) \
|
||||
// ((cond) ? LFS_MKTAG(type, id, size) : LFS_MKTAG(LFS_FROM_NOOP, 0, 0))
|
||||
|
||||
// #define LFS_MKTAG_IF_ELSE(cond, type1, id1, size1, type2, id2, size2) \
|
||||
// ((cond) ? LFS_MKTAG(type1, id1, size1) : LFS_MKTAG(type2, id2, size2))
|
||||
|
||||
fn lfs_tag_isvalid(tag: LfsTag) -> bool {
|
||||
(tag & 0x80000000) != 0
|
||||
}
|
||||
|
||||
fn lfs_tag_isdelete(tag: LfsTag) -> bool {
|
||||
return (((tag as i32) << 22) >> 22) == -1;
|
||||
}
|
||||
|
||||
fn lfs_tag_type1(tag: LfsTag) -> u16 {
|
||||
((tag & 0x70000000) >> 20) as u16
|
||||
}
|
||||
|
||||
fn lfs_tag_type2(tag: LfsTag) -> u16 {
|
||||
((tag & 0x78000000) >> 20) as u16
|
||||
}
|
||||
|
||||
fn lfs_tag_type3(tag: LfsTag) -> u16 {
|
||||
((tag & 0x7ff00000) >> 20) as u16
|
||||
}
|
||||
|
||||
fn lfs_tag_chunk(tag: LfsTag) -> u8 {
|
||||
((tag & 0x0ff00000) >> 20) as u8
|
||||
}
|
||||
|
||||
fn lfs_tag_splice(tag: LfsTag) -> i8 {
|
||||
(lfs_tag_chunk(tag)) as i8
|
||||
}
|
||||
|
||||
fn lfs_tag_id(tag: LfsTag) -> u16 {
|
||||
((tag & 0x000ffc00) >> 10) as u16
|
||||
}
|
||||
|
||||
fn lfs_tag_size(tag: LfsTag) -> LfsSize {
|
||||
return tag & 0x000003ff;
|
||||
}
|
||||
|
||||
fn lfs_tag_dsize(tag: LfsTag) -> LfsSize {
|
||||
return size_of::<LfsTag>() as u32 + lfs_tag_size(tag + if lfs_tag_isdelete(tag) { 1 } else { 0 });
|
||||
}
|
||||
|
||||
// operations on attributes in attribute lists
|
||||
struct LfsMattr {
|
||||
tag: LfsTag,
|
||||
buffer: Vec<u8>,
|
||||
}
|
||||
|
||||
struct LfsDiskoff {
|
||||
block: LfsBlock,
|
||||
off: LfsOff,
|
||||
}
|
||||
|
||||
// #define LFS_MKATTRS(...) \
|
||||
// (struct lfs_mattr[]){__VA_ARGS__}, \
|
||||
// sizeof((struct lfs_mattr[]){__VA_ARGS__}) / sizeof(struct lfs_mattr)
|
||||
|
||||
// operations on global state
|
||||
fn lfs_gstate_xor(a: &mut LfsGstate, b: &mut LfsGstate) {
|
||||
let a: &mut [u8; 3] = unsafe { std::mem::transmute(a) };
|
||||
let b: &[u8; 3] = unsafe { std::mem::transmute(b) };
|
||||
for i in 0..3 {
|
||||
a[i] ^= b[i];
|
||||
}
|
||||
}
|
||||
|
||||
fn lfs_gstate_iszero(a: &LfsGstate) -> bool {
|
||||
let a: &[u8; 3] = unsafe { std::mem::transmute(a) };
|
||||
for byte in a {
|
||||
if (*byte != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
fn lfs_gstate_hasorphans(a: &LfsGstate) -> bool {
|
||||
lfs_tag_size(a.tag) != 0
|
||||
}
|
||||
|
||||
fn lfs_gstate_getorphans(a: &LfsGstate) -> u8 {
|
||||
(lfs_tag_size(a.tag) & 0x1ff) as u8
|
||||
}
|
||||
|
||||
fn lfs_gstate_hasmove(a: &LfsGstate) -> bool {
|
||||
lfs_tag_type1(a.tag) != 0
|
||||
}
|
||||
|
||||
fn lfs_gstate_needssuperblock(a: &LfsGstate) -> bool {
|
||||
(lfs_tag_size(a.tag) >> 9) != 0
|
||||
}
|
||||
|
||||
fn lfs_gstate_hasmovehere(a: &LfsGstate,
|
||||
pair: (LfsBlock, LfsBlock)) -> bool {
|
||||
return lfs_tag_type1(a.tag) != 0 && !lfs_pair_cmp(a.pair, pair);
|
||||
}
|
||||
|
||||
fn lfs_gstate_fromle32(a: &mut LfsGstate) {
|
||||
a.tag = lfs_fromle32(a.tag);
|
||||
a.pair.0 = lfs_fromle32(a.pair.0);
|
||||
a.pair.1 = lfs_fromle32(a.pair.1);
|
||||
}
|
||||
|
||||
fn lfs_gstate_tole32(a: &mut LfsGstate) {
|
||||
a.tag = lfs_tole32(a.tag);
|
||||
a.pair.0 = lfs_tole32(a.pair.0);
|
||||
a.pair.1 = lfs_tole32(a.pair.1);
|
||||
}
|
||||
|
|
|
@ -173,16 +173,16 @@ pub fn lfs_free(p: &[u8]) {
|
|||
|
||||
/// Software CRC implementation with small lookup table
|
||||
/// Calculate CRC-32 with polynomial = 0x04c11db7
|
||||
pub fn lfs_crc(mut crc: u32, data: &mut [u8], size: usize) -> u32 {
|
||||
static rtable: [u32; 16] = [
|
||||
pub fn lfs_crc(mut crc: u32, data: &[u8], size: usize) -> u32 {
|
||||
static RTABLE: [u32; 16] = [
|
||||
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158,
|
||||
0x5005713c, 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4,
|
||||
0xa00ae278, 0xbdbdf21c,
|
||||
];
|
||||
|
||||
for i in 0..size {
|
||||
crc = (crc >> 4) ^ rtable[((crc ^ (data[i] as u32 >> 0)) & 0xf) as usize];
|
||||
crc = (crc >> 4) ^ rtable[((crc ^ (data[i] as u32 >> 4)) & 0xf) as usize];
|
||||
crc = (crc >> 4) ^ RTABLE[((crc ^ (data[i] as u32 >> 0)) & 0xf) as usize];
|
||||
crc = (crc >> 4) ^ RTABLE[((crc ^ (data[i] as u32 >> 4)) & 0xf) as usize];
|
||||
}
|
||||
|
||||
return crc;
|
||||
|
|
10750
src/wip.rs
10750
src/wip.rs
File diff suppressed because it is too large
Load diff
Reference in a new issue