so much rewriting

This commit is contained in:
tezlm 2024-02-11 18:49:55 -08:00
parent fe18eb56ef
commit e584061d2e
Signed by: tezlm
GPG key ID: 649733FCD94AFBBA
3 changed files with 5529 additions and 5565 deletions

View file

@ -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);
}

View file

@ -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

File diff suppressed because it is too large Load diff