enter the Rc-RefCell madness
This commit is contained in:
parent
2b01b9ff0e
commit
ea3e2a76c4
12 changed files with 619 additions and 353 deletions
|
|
@ -46,6 +46,10 @@ impl Date {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn repr(&self) -> u16 {
|
||||
self.repr
|
||||
}
|
||||
|
||||
pub fn day(&self) -> u8 {
|
||||
(self.repr & 0x1F) as u8
|
||||
}
|
||||
|
|
@ -97,6 +101,10 @@ impl Time {
|
|||
Time::from_seconds_minutes_hours(seconds, time.minute() as u8, time.hour() as u8)
|
||||
}
|
||||
|
||||
pub fn repr(&self) -> u16 {
|
||||
self.repr
|
||||
}
|
||||
|
||||
pub fn second(&self) -> u8 {
|
||||
2 * (self.repr & 0x1F) as u8
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use std::fmt::Display;
|
||||
use std::io::Read;
|
||||
use std::io::{Read, Write};
|
||||
|
||||
use bitflags::bitflags;
|
||||
use chrono::{NaiveDate, NaiveDateTime, TimeDelta};
|
||||
|
|
@ -199,6 +199,58 @@ impl DirEntry {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn write(&self, mut writer: impl Write) -> std::io::Result<()> {
|
||||
let mut buf = [0; 32];
|
||||
|
||||
let mut name = self.name();
|
||||
|
||||
if name[0] == b'.' && self.is_hidden() {
|
||||
name = &name[1..];
|
||||
}
|
||||
|
||||
if let Some((idx, _)) = name
|
||||
.iter()
|
||||
.copied()
|
||||
.enumerate()
|
||||
.rev()
|
||||
.find(|&(_n, u)| u == b'.')
|
||||
{
|
||||
let (stem, ext) = name.split_at(idx);
|
||||
|
||||
buf[..8][..stem.len()].copy_from_slice(stem);
|
||||
buf[8..][..ext.len()].copy_from_slice(ext);
|
||||
|
||||
// (stem, Some(ext))
|
||||
} else {
|
||||
// all stem, no ext
|
||||
buf[..8][..name.len()].copy_from_slice(name);
|
||||
}
|
||||
|
||||
buf[11] = self.attr().bits();
|
||||
|
||||
buf[12] = 0;
|
||||
|
||||
buf[13] = self.create_time_tenths;
|
||||
buf[13..15].copy_from_slice(&self.create_time.repr().to_le_bytes());
|
||||
|
||||
buf[16..18].copy_from_slice(&self.create_date.repr().to_le_bytes());
|
||||
|
||||
buf[18..20].copy_from_slice(&self.last_access_date.repr().to_le_bytes());
|
||||
|
||||
buf[20..22].copy_from_slice(&((self.first_cluster() >> 16) as u16).to_le_bytes());
|
||||
|
||||
buf[22..24].copy_from_slice(&self.write_time.repr().to_le_bytes());
|
||||
buf[24..26].copy_from_slice(&self.write_date.repr().to_le_bytes());
|
||||
|
||||
buf[26..28].copy_from_slice(&(self.first_cluster as u16).to_le_bytes());
|
||||
|
||||
buf[28..].copy_from_slice(&self.file_size.to_le_bytes());
|
||||
|
||||
writer.write_all(&buf)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// indicates this DirEntry is empty
|
||||
///
|
||||
/// can be either simply empty (0xe5) or the sentinel (0x00) that indicates that all following
|
||||
|
|
@ -247,7 +299,13 @@ impl DirEntry {
|
|||
}
|
||||
|
||||
pub fn name(&self) -> &[u8] {
|
||||
&self.name
|
||||
let mut name: &[u8] = &self.name;
|
||||
|
||||
while let Some(&0) = name.last() {
|
||||
name = &name[..name.len() - 1];
|
||||
}
|
||||
|
||||
name
|
||||
}
|
||||
|
||||
pub fn stem(&self) -> &[u8] {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
use std::fmt::Display;
|
||||
use std::io::Write as _;
|
||||
use std::mem::MaybeUninit;
|
||||
use std::ops::RangeInclusive;
|
||||
|
||||
use enum_dispatch::enum_dispatch;
|
||||
|
||||
use crate::FatType;
|
||||
use crate::subslice::SubSliceMut;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum FatError {
|
||||
|
|
@ -19,26 +21,29 @@ pub enum FatError {
|
|||
}
|
||||
|
||||
#[enum_dispatch]
|
||||
pub trait Fatty {
|
||||
pub trait FatOps {
|
||||
// get the next cluster
|
||||
// assumes the cluster is valid, i.e. allocated
|
||||
fn get_entry(&self, cluster: u32) -> u32;
|
||||
fn set_entry(&mut self, cluster: u32, entry: u32);
|
||||
|
||||
fn get_valid_clusters(&self) -> RangeInclusive<u32>;
|
||||
fn get_reserved_clusters(&self) -> RangeInclusive<u32>;
|
||||
fn get_defective_cluster(&self) -> u32;
|
||||
fn get_reserved_eof_clusters(&self) -> RangeInclusive<u32>;
|
||||
fn get_eof_cluster(&self) -> u32;
|
||||
fn valid_clusters(&self) -> RangeInclusive<u32>;
|
||||
fn reserved_clusters(&self) -> RangeInclusive<u32>;
|
||||
fn defective_cluster(&self) -> u32;
|
||||
fn reserved_eof_clusters(&self) -> RangeInclusive<u32>;
|
||||
fn eof_cluster(&self) -> u32;
|
||||
|
||||
fn count_free_clusters(&self) -> usize {
|
||||
self.get_valid_clusters()
|
||||
self.valid_clusters()
|
||||
.map(|cluster| self.get_entry(cluster))
|
||||
.filter(|&entry| entry == 0)
|
||||
.count()
|
||||
}
|
||||
|
||||
fn write_to_disk(&self, sub_slice: SubSliceMut) -> std::io::Result<()>;
|
||||
}
|
||||
|
||||
#[enum_dispatch(Fatty)]
|
||||
#[enum_dispatch(FatOps)]
|
||||
pub enum Fat {
|
||||
Fat12(Fat12),
|
||||
Fat16(Fat16),
|
||||
|
|
@ -70,18 +75,18 @@ impl Fat {
|
|||
return Err(FatError::FreeCluster);
|
||||
}
|
||||
|
||||
if self.get_reserved_clusters().contains(&cluster) {
|
||||
if self.reserved_clusters().contains(&cluster) {
|
||||
// can't get next cluster for reserved cluster
|
||||
return Err(FatError::ReservedCluster(cluster));
|
||||
}
|
||||
|
||||
// defective cluster
|
||||
if cluster == self.get_defective_cluster() {
|
||||
if cluster == self.defective_cluster() {
|
||||
// can't get next cluster for defective cluster
|
||||
return Err(FatError::DefectiveCluster);
|
||||
}
|
||||
|
||||
if self.get_reserved_eof_clusters().contains(&cluster) {
|
||||
if self.reserved_eof_clusters().contains(&cluster) {
|
||||
// Reserved and should not be used. May be interpreted as an allocated cluster and the
|
||||
// final cluster in the file (indicating end-of-file condition).
|
||||
//
|
||||
|
|
@ -94,12 +99,12 @@ impl Fat {
|
|||
let entry = self.get_entry(cluster);
|
||||
|
||||
// interpret second reserved block as EOF here
|
||||
if entry == self.get_eof_cluster() || self.get_reserved_eof_clusters().contains(&entry) {
|
||||
if entry == self.eof_cluster() || self.reserved_eof_clusters().contains(&entry) {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
// entry should be in the valid cluster range here; otherwise something went wrong
|
||||
if !self.get_valid_clusters().contains(&entry) {
|
||||
if !self.valid_clusters().contains(&entry) {
|
||||
return Err(FatError::InvalidEntry(entry));
|
||||
}
|
||||
|
||||
|
|
@ -178,7 +183,7 @@ impl Fat12 {
|
|||
}
|
||||
}
|
||||
|
||||
impl Fatty for Fat12 {
|
||||
impl FatOps for Fat12 {
|
||||
fn get_entry(&self, cluster: u32) -> u32 {
|
||||
let cluster = cluster as usize;
|
||||
assert!(cluster < self.next_sectors.len());
|
||||
|
|
@ -186,25 +191,68 @@ impl Fatty for Fat12 {
|
|||
self.next_sectors[cluster] as u32
|
||||
}
|
||||
|
||||
fn get_valid_clusters(&self) -> RangeInclusive<u32> {
|
||||
fn set_entry(&mut self, cluster: u32, entry: u32) {
|
||||
self.next_sectors[cluster as usize] = entry as u16;
|
||||
}
|
||||
|
||||
fn valid_clusters(&self) -> RangeInclusive<u32> {
|
||||
2..=self.max
|
||||
}
|
||||
|
||||
fn get_reserved_clusters(&self) -> RangeInclusive<u32> {
|
||||
fn reserved_clusters(&self) -> RangeInclusive<u32> {
|
||||
(self.max as u32 + 1)..=0xFF6
|
||||
}
|
||||
|
||||
fn get_defective_cluster(&self) -> u32 {
|
||||
fn defective_cluster(&self) -> u32 {
|
||||
0xFF7
|
||||
}
|
||||
|
||||
fn get_reserved_eof_clusters(&self) -> RangeInclusive<u32> {
|
||||
fn reserved_eof_clusters(&self) -> RangeInclusive<u32> {
|
||||
0xFF8..=0xFFE
|
||||
}
|
||||
|
||||
fn get_eof_cluster(&self) -> u32 {
|
||||
fn eof_cluster(&self) -> u32 {
|
||||
0xFFF
|
||||
}
|
||||
|
||||
fn write_to_disk(&self, mut sub_slice: SubSliceMut) -> std::io::Result<()> {
|
||||
// TODO: currently assumed FAT has even number of entries
|
||||
|
||||
assert_eq!(3 * sub_slice.len(), self.next_sectors.len());
|
||||
|
||||
let mut iter = self.next_sectors.chunks_exact(3);
|
||||
|
||||
let mut buf: [u8; 3];
|
||||
|
||||
for chunk in &mut iter {
|
||||
// first (even) entry gets truncated
|
||||
// let first = u16::from_le_bytes(triple[..2].try_into().unwrap()) & 0xFFF;
|
||||
// second (odd) entry gets shifted
|
||||
// let second = u16::from_le_bytes(triple[1..].try_into().unwrap()) >> 4;
|
||||
|
||||
// assert!(idx + 1 < next_sectors.len());
|
||||
|
||||
// next_sectors[2 * idx] = first;
|
||||
// next_sectors[2 * idx + 1] = second;
|
||||
|
||||
// sub_slice.write_all(&entry.to_le_bytes())?;
|
||||
|
||||
let first = chunk[0];
|
||||
let second = chunk[1];
|
||||
|
||||
buf = [0; 3];
|
||||
|
||||
// buf[..2] |= &first.to_le_bytes();
|
||||
buf[0] = first.to_le_bytes()[0];
|
||||
buf[1] = first.to_le_bytes()[1] | (second << 4).to_le_bytes()[0];
|
||||
buf[2] = (second << 4).to_le_bytes()[1];
|
||||
sub_slice.write_all(&buf)?;
|
||||
}
|
||||
|
||||
assert_eq!(iter.remainder().len(), 0);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Fat16 {
|
||||
|
|
@ -262,7 +310,7 @@ impl Fat16 {
|
|||
}
|
||||
}
|
||||
|
||||
impl Fatty for Fat16 {
|
||||
impl FatOps for Fat16 {
|
||||
fn get_entry(&self, cluster: u32) -> u32 {
|
||||
let cluster = cluster as usize;
|
||||
assert!(cluster < self.next_sectors.len());
|
||||
|
|
@ -270,25 +318,39 @@ impl Fatty for Fat16 {
|
|||
self.next_sectors[cluster] as u32
|
||||
}
|
||||
|
||||
fn get_valid_clusters(&self) -> RangeInclusive<u32> {
|
||||
fn set_entry(&mut self, cluster: u32, entry: u32) {
|
||||
self.next_sectors[cluster as usize] = entry as u16;
|
||||
}
|
||||
|
||||
fn valid_clusters(&self) -> RangeInclusive<u32> {
|
||||
2..=self.max
|
||||
}
|
||||
|
||||
fn get_reserved_clusters(&self) -> RangeInclusive<u32> {
|
||||
fn reserved_clusters(&self) -> RangeInclusive<u32> {
|
||||
(self.max as u32 + 1)..=0xFFF6
|
||||
}
|
||||
|
||||
fn get_defective_cluster(&self) -> u32 {
|
||||
fn defective_cluster(&self) -> u32 {
|
||||
0xFFF7
|
||||
}
|
||||
|
||||
fn get_reserved_eof_clusters(&self) -> RangeInclusive<u32> {
|
||||
fn reserved_eof_clusters(&self) -> RangeInclusive<u32> {
|
||||
0xFFF8..=0xFFFE
|
||||
}
|
||||
|
||||
fn get_eof_cluster(&self) -> u32 {
|
||||
fn eof_cluster(&self) -> u32 {
|
||||
0xFFFF
|
||||
}
|
||||
|
||||
fn write_to_disk(&self, mut sub_slice: SubSliceMut) -> std::io::Result<()> {
|
||||
assert_eq!(2 * sub_slice.len(), self.next_sectors.len());
|
||||
|
||||
for &entry in self.next_sectors.iter() {
|
||||
sub_slice.write_all(&entry.to_le_bytes())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Fat32 {
|
||||
|
|
@ -346,7 +408,7 @@ impl Fat32 {
|
|||
}
|
||||
}
|
||||
|
||||
impl Fatty for Fat32 {
|
||||
impl FatOps for Fat32 {
|
||||
fn get_entry(&self, cluster: u32) -> u32 {
|
||||
let cluster = cluster as usize;
|
||||
assert!(cluster < self.next_sectors.len());
|
||||
|
|
@ -354,23 +416,37 @@ impl Fatty for Fat32 {
|
|||
self.next_sectors[cluster] as u32
|
||||
}
|
||||
|
||||
fn get_valid_clusters(&self) -> RangeInclusive<u32> {
|
||||
fn set_entry(&mut self, cluster: u32, entry: u32) {
|
||||
self.next_sectors[cluster as usize] = entry;
|
||||
}
|
||||
|
||||
fn valid_clusters(&self) -> RangeInclusive<u32> {
|
||||
2..=self.max
|
||||
}
|
||||
|
||||
fn get_reserved_clusters(&self) -> RangeInclusive<u32> {
|
||||
fn reserved_clusters(&self) -> RangeInclusive<u32> {
|
||||
(self.max + 1)..=0xFFFFFFF6
|
||||
}
|
||||
|
||||
fn get_defective_cluster(&self) -> u32 {
|
||||
fn defective_cluster(&self) -> u32 {
|
||||
0xFFFFFFF7
|
||||
}
|
||||
|
||||
fn get_reserved_eof_clusters(&self) -> RangeInclusive<u32> {
|
||||
fn reserved_eof_clusters(&self) -> RangeInclusive<u32> {
|
||||
0xFFFFFFF8..=0xFFFFFFFE
|
||||
}
|
||||
|
||||
fn get_eof_cluster(&self) -> u32 {
|
||||
fn eof_cluster(&self) -> u32 {
|
||||
0xFFFFFFFF
|
||||
}
|
||||
|
||||
fn write_to_disk(&self, mut sub_slice: SubSliceMut) -> std::io::Result<()> {
|
||||
assert_eq!(4 * sub_slice.len(), self.next_sectors.len());
|
||||
|
||||
for &entry in self.next_sectors.iter() {
|
||||
sub_slice.write_all(&entry.to_le_bytes())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
use std::io::Read;
|
||||
use std::io::{Read, Write};
|
||||
|
||||
use crate::FatFs;
|
||||
use crate::subslice::SubSlice;
|
||||
use crate::utils::replace;
|
||||
use crate::subslice::{SubSlice, SubSliceMut};
|
||||
|
||||
pub struct ClusterChainReader<'a> {
|
||||
sub_slice: SubSlice<'a>,
|
||||
fat_fs: &'a FatFs,
|
||||
|
||||
sub_slice: SubSlice,
|
||||
|
||||
next_cluster: Option<u32>,
|
||||
}
|
||||
|
|
@ -17,6 +18,7 @@ impl<'a> ClusterChainReader<'a> {
|
|||
let sub_slice = fat_fs.cluster_as_subslice(first_cluster);
|
||||
|
||||
ClusterChainReader {
|
||||
fat_fs,
|
||||
sub_slice,
|
||||
next_cluster,
|
||||
}
|
||||
|
|
@ -27,13 +29,8 @@ impl<'a> ClusterChainReader<'a> {
|
|||
return false;
|
||||
};
|
||||
|
||||
replace(&mut self.sub_slice, |sub_slice| {
|
||||
let fat_fs = sub_slice.release();
|
||||
|
||||
self.next_cluster = fat_fs.next_cluster(next_cluster).unwrap_or(None);
|
||||
|
||||
fat_fs.cluster_as_subslice(next_cluster)
|
||||
});
|
||||
self.next_cluster = self.fat_fs.next_cluster(next_cluster).unwrap_or(None);
|
||||
self.sub_slice = self.fat_fs.cluster_as_subslice(next_cluster);
|
||||
|
||||
true
|
||||
}
|
||||
|
|
@ -71,3 +68,74 @@ impl Read for ClusterChainReader<'_> {
|
|||
self.sub_slice.read(buf)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ClusterChainWriter<'a> {
|
||||
fat_fs: &'a FatFs,
|
||||
|
||||
sub_slice: SubSliceMut,
|
||||
|
||||
next_cluster: Option<u32>,
|
||||
}
|
||||
|
||||
impl<'a> ClusterChainWriter<'a> {
|
||||
pub fn new(fat_fs: &'a FatFs, first_cluster: u32) -> ClusterChainWriter<'a> {
|
||||
let next_cluster = fat_fs.next_cluster(first_cluster).unwrap_or(None);
|
||||
|
||||
let sub_slice = fat_fs.cluster_as_subslice_mut(first_cluster);
|
||||
|
||||
ClusterChainWriter {
|
||||
fat_fs,
|
||||
sub_slice,
|
||||
next_cluster,
|
||||
}
|
||||
}
|
||||
|
||||
fn move_to_next_cluster(&mut self) -> bool {
|
||||
// TODO: should allocate a new cluster here!
|
||||
let Some(next_cluster) = self.next_cluster else {
|
||||
return false;
|
||||
};
|
||||
|
||||
self.next_cluster = self.fat_fs.next_cluster(next_cluster).unwrap_or(None);
|
||||
self.fat_fs.cluster_as_subslice_mut(next_cluster);
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
pub fn skip(&mut self, n: u64) -> u64 {
|
||||
let mut bytes_to_skip = n;
|
||||
|
||||
while bytes_to_skip > self.sub_slice.len() as u64 {
|
||||
bytes_to_skip -= self.sub_slice.len() as u64;
|
||||
if !self.move_to_next_cluster() {
|
||||
// ran out of bytes to seek
|
||||
return n - bytes_to_skip;
|
||||
}
|
||||
}
|
||||
|
||||
if bytes_to_skip != 0 {
|
||||
bytes_to_skip -= self.sub_slice.skip(bytes_to_skip as usize) as u64;
|
||||
}
|
||||
|
||||
// n should absolutely be zero here
|
||||
assert_eq!(bytes_to_skip, 0);
|
||||
|
||||
n
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for ClusterChainWriter<'_> {
|
||||
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||
if self.sub_slice.is_empty() {
|
||||
if !(self.move_to_next_cluster()) {
|
||||
return Ok(0);
|
||||
}
|
||||
}
|
||||
|
||||
self.sub_slice.write(buf)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> std::io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
use std::cell::RefCell;
|
||||
use std::fmt::Display;
|
||||
use std::io::{Read, Seek, SeekFrom, Write};
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::dir::DirIter;
|
||||
use crate::fat::{FatError, Fatty};
|
||||
use crate::fat::{FatError, FatOps};
|
||||
use crate::subslice::{SubSlice, SubSliceMut};
|
||||
|
||||
pub mod bpb;
|
||||
|
|
@ -98,6 +99,16 @@ pub struct FatFs {
|
|||
fat: fat::Fat,
|
||||
}
|
||||
|
||||
impl Display for FatFs {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
writeln!(f, "{}", self.bpb)?;
|
||||
writeln!(f, "")?;
|
||||
writeln!(f, "{}", self.fat)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for FatFs {}
|
||||
|
||||
impl FatFs {
|
||||
|
|
@ -160,90 +171,74 @@ impl FatFs {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn bpb(&self) -> &bpb::Bpb {
|
||||
&self.bpb
|
||||
}
|
||||
|
||||
pub fn fat(&self) -> &fat::Fat {
|
||||
&self.fat
|
||||
}
|
||||
|
||||
/// byte offset of data cluster
|
||||
pub fn data_cluster_to_offset(&self, cluster: u32) -> u64 {
|
||||
fn data_cluster_to_offset(&self, cluster: u32) -> u64 {
|
||||
// assert!(cluster >= 2);
|
||||
|
||||
assert!(self.fat().get_valid_clusters().contains(&cluster));
|
||||
assert!(self.fat.valid_clusters().contains(&cluster));
|
||||
|
||||
self.data_offset + (cluster - 2) as u64 * self.bytes_per_cluster as u64
|
||||
}
|
||||
|
||||
pub fn free_clusters(&self) -> usize {
|
||||
self.fat.count_free_clusters()
|
||||
}
|
||||
|
||||
pub fn bytes_per_sector(&self) -> u16 {
|
||||
self.bpb.bytes_per_sector()
|
||||
}
|
||||
|
||||
pub fn sectors_per_cluster(&self) -> u8 {
|
||||
self.bpb.sectors_per_cluster()
|
||||
}
|
||||
|
||||
pub fn root_cluster(&self) -> Option<u32> {
|
||||
self.bpb.root_cluster()
|
||||
}
|
||||
|
||||
/// next data cluster or None is cluster is EOF
|
||||
///
|
||||
/// giving an invalid cluster (free, reserved, or defective) returns an appropriate error
|
||||
pub fn next_cluster(&self, cluster: u32) -> Result<Option<u32>, FatError> {
|
||||
self.fat().get_next_cluster(cluster)
|
||||
self.fat.get_next_cluster(cluster)
|
||||
}
|
||||
|
||||
pub fn cluster_as_subslice_mut(&mut self, cluster: u32) -> SubSliceMut<'_> {
|
||||
pub fn cluster_as_subslice_mut(&self, cluster: u32) -> SubSliceMut {
|
||||
if cluster == 0 {
|
||||
// for cluster 0 simply return empty subslice
|
||||
// this makes things a bit easier, since cluster 0 is used as a marker that a file/dir
|
||||
// is empty
|
||||
|
||||
SubSliceMut::new(self, 0, 0);
|
||||
SubSliceMut::new(self.inner.clone(), 0, 0);
|
||||
}
|
||||
|
||||
let offset = self.data_cluster_to_offset(cluster);
|
||||
|
||||
SubSliceMut::new(self, offset, self.bytes_per_cluster)
|
||||
SubSliceMut::new(self.inner.clone(), offset, self.bytes_per_cluster)
|
||||
}
|
||||
|
||||
pub fn cluster_as_subslice(&self, cluster: u32) -> SubSlice<'_> {
|
||||
pub fn cluster_as_subslice(&self, cluster: u32) -> SubSlice {
|
||||
if cluster == 0 {
|
||||
// for cluster 0 simply return empty subslice
|
||||
// this makes things a bit easier, since cluster 0 is used as a marker that a file/dir
|
||||
// is empty
|
||||
|
||||
SubSlice::new(self, 0, 0);
|
||||
SubSlice::new(self.inner.clone(), 0, 0);
|
||||
}
|
||||
|
||||
let offset = self.data_cluster_to_offset(cluster);
|
||||
|
||||
SubSlice::new(self, offset, self.bytes_per_cluster)
|
||||
}
|
||||
|
||||
pub fn root_dir_bytes(&mut self) -> std::io::Result<Vec<u8>> {
|
||||
if let Some(root_dir_offset) = self.root_dir_offset {
|
||||
let mut data = Vec::new();
|
||||
|
||||
let mut subslice = SubSliceMut::new(self, root_dir_offset, self.root_dir_size);
|
||||
|
||||
subslice.read_to_end(&mut data)?;
|
||||
|
||||
return Ok(data);
|
||||
}
|
||||
|
||||
let mut cluster = self.bpb().root_cluster().unwrap();
|
||||
|
||||
let mut data = vec![0; self.bytes_per_cluster];
|
||||
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
|
||||
inner.read_at_offset(self.data_cluster_to_offset(cluster), &mut data)?;
|
||||
|
||||
while let Ok(Some(next_cluster)) = self.next_cluster(cluster) {
|
||||
cluster = next_cluster;
|
||||
|
||||
inner.read_at_offset(self.data_cluster_to_offset(cluster), &mut data)?;
|
||||
}
|
||||
|
||||
Ok(data)
|
||||
SubSlice::new(self.inner.clone(), offset, self.bytes_per_cluster)
|
||||
}
|
||||
|
||||
fn chain_reader(&'_ self, first_cluster: u32) -> iter::ClusterChainReader<'_> {
|
||||
iter::ClusterChainReader::new(self, first_cluster)
|
||||
}
|
||||
|
||||
fn chain_writer(&'_ self, first_cluster: u32) -> iter::ClusterChainWriter<'_> {
|
||||
iter::ClusterChainWriter::new(self, first_cluster)
|
||||
}
|
||||
|
||||
pub fn root_dir_iter<'a>(&'a self) -> DirIter<Box<dyn Read + 'a>> {
|
||||
// Box<dyn Iterator<Item = DirEntry> + '_>
|
||||
// TODO: maybe wrap this in another RootDirIter enum, so we don't have to Box<dyn>
|
||||
|
|
@ -251,7 +246,7 @@ impl FatFs {
|
|||
if let Some(root_dir_offset) = self.root_dir_offset {
|
||||
// FAT12/FAT16
|
||||
|
||||
let sub_slice = SubSlice::new(self, root_dir_offset, self.root_dir_size);
|
||||
let sub_slice = SubSlice::new(self.inner.clone(), root_dir_offset, self.root_dir_size);
|
||||
|
||||
return DirIter::new(Box::new(sub_slice));
|
||||
}
|
||||
|
|
@ -259,7 +254,7 @@ impl FatFs {
|
|||
// FAT32
|
||||
|
||||
// can't fail; we're in the FAT32 case
|
||||
let root_cluster = self.bpb().root_cluster().unwrap();
|
||||
let root_cluster = self.bpb.root_cluster().unwrap();
|
||||
|
||||
let cluster_iter = iter::ClusterChainReader::new(self, root_cluster);
|
||||
|
||||
|
|
@ -276,8 +271,16 @@ impl FatFs {
|
|||
}
|
||||
|
||||
pub fn file_reader(&self, first_cluster: u32) -> iter::ClusterChainReader<'_> {
|
||||
// TODO: needs to take file size into account
|
||||
assert!(first_cluster >= 2);
|
||||
|
||||
self.chain_reader(first_cluster)
|
||||
}
|
||||
|
||||
pub fn file_writer(&self, first_cluster: u32) -> iter::ClusterChainWriter<'_> {
|
||||
// TODO: needs to take file size into account
|
||||
assert!(first_cluster >= 2);
|
||||
|
||||
self.chain_writer(first_cluster)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,19 @@
|
|||
use std::cell::RefCell;
|
||||
use std::fmt::Debug;
|
||||
use std::io::{Read, Write};
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::FatFs;
|
||||
use crate::SliceLike;
|
||||
|
||||
pub struct SubSliceMut<'a> {
|
||||
fat_fs: &'a mut FatFs,
|
||||
pub struct SubSliceMut {
|
||||
// fat_fs: &'a FatFs,
|
||||
data: Rc<RefCell<dyn SliceLike>>,
|
||||
|
||||
offset: u64,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
impl Debug for SubSliceMut<'_> {
|
||||
impl Debug for SubSliceMut {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("SubSliceMut")
|
||||
.field("offset", &self.offset)
|
||||
|
|
@ -19,17 +22,13 @@ impl Debug for SubSliceMut<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
impl SubSliceMut<'_> {
|
||||
pub fn new(fat_fs: &mut FatFs, offset: u64, len: usize) -> SubSliceMut<'_> {
|
||||
SubSliceMut {
|
||||
fat_fs,
|
||||
offset,
|
||||
len,
|
||||
}
|
||||
impl SubSliceMut {
|
||||
pub fn new(data: Rc<RefCell<dyn SliceLike>>, offset: u64, len: usize) -> SubSliceMut {
|
||||
SubSliceMut { data, offset, len }
|
||||
}
|
||||
}
|
||||
|
||||
impl SubSliceMut<'_> {
|
||||
impl<'a> SubSliceMut {
|
||||
pub fn len(&self) -> usize {
|
||||
self.len
|
||||
}
|
||||
|
|
@ -37,14 +36,22 @@ impl SubSliceMut<'_> {
|
|||
pub fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
pub fn skip(&mut self, n: usize) -> usize {
|
||||
let n = n.min(self.len());
|
||||
|
||||
self.offset += n as u64;
|
||||
self.len -= n;
|
||||
|
||||
n
|
||||
}
|
||||
}
|
||||
|
||||
impl Read for SubSliceMut<'_> {
|
||||
impl Read for SubSliceMut {
|
||||
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||
let bytes_to_read = self.len.min(buf.len());
|
||||
|
||||
self.fat_fs
|
||||
.inner
|
||||
self.data
|
||||
.borrow_mut()
|
||||
.read_at_offset(self.offset, &mut buf[..bytes_to_read])?;
|
||||
|
||||
|
|
@ -55,12 +62,11 @@ impl Read for SubSliceMut<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
impl Write for SubSliceMut<'_> {
|
||||
impl Write for SubSliceMut {
|
||||
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||
let bytes_to_write = self.len.min(buf.len());
|
||||
|
||||
self.fat_fs
|
||||
.inner
|
||||
self.data
|
||||
.borrow_mut()
|
||||
.write_at_offset(self.offset, &buf[..bytes_to_write])?;
|
||||
|
||||
|
|
@ -75,14 +81,14 @@ impl Write for SubSliceMut<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct SubSlice<'a> {
|
||||
fat_fs: &'a FatFs,
|
||||
pub struct SubSlice {
|
||||
data: Rc<RefCell<dyn SliceLike>>,
|
||||
|
||||
offset: u64,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
impl Debug for SubSlice<'_> {
|
||||
impl Debug for SubSlice {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("SubSliceMut")
|
||||
.field("offset", &self.offset)
|
||||
|
|
@ -91,17 +97,9 @@ impl Debug for SubSlice<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
impl SubSlice<'_> {
|
||||
pub fn new(fat_fs: &FatFs, offset: u64, len: usize) -> SubSlice<'_> {
|
||||
SubSlice {
|
||||
fat_fs,
|
||||
offset,
|
||||
len,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fat_fs(&self) -> &FatFs {
|
||||
self.fat_fs
|
||||
impl<'a> SubSlice {
|
||||
pub fn new(data: Rc<RefCell<dyn SliceLike>>, offset: u64, len: usize) -> SubSlice {
|
||||
SubSlice { data, offset, len }
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
|
|
@ -121,19 +119,11 @@ impl SubSlice<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> SubSlice<'a> {
|
||||
/// releases the inner &FatFs, consuming self in the process
|
||||
pub fn release(self) -> &'a FatFs {
|
||||
self.fat_fs
|
||||
}
|
||||
}
|
||||
|
||||
impl Read for SubSlice<'_> {
|
||||
impl Read for SubSlice {
|
||||
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||
let bytes_to_read = self.len.min(buf.len());
|
||||
|
||||
self.fat_fs
|
||||
.inner
|
||||
self.data
|
||||
.borrow_mut()
|
||||
.read_at_offset(self.offset, &mut buf[..bytes_to_read])?;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,24 +3,9 @@ pub fn load_u16_le(bytes: &[u8]) -> u16 {
|
|||
|
||||
u16::from_le_bytes(bytes.try_into().unwrap())
|
||||
}
|
||||
|
||||
pub fn load_u32_le(bytes: &[u8]) -> u32 {
|
||||
assert_eq!(bytes.len(), 4);
|
||||
|
||||
u32::from_le_bytes(bytes.try_into().unwrap())
|
||||
}
|
||||
|
||||
/// replace the value at x with f(x)
|
||||
///
|
||||
/// SAFETY:
|
||||
/// should be safe, I guess? MIRI didn't complain about it
|
||||
pub fn replace<T>(x: &mut T, f: impl FnOnce(T) -> T) {
|
||||
unsafe {
|
||||
let x_ptr = x as *mut T;
|
||||
|
||||
let old_x = std::ptr::read(x_ptr);
|
||||
|
||||
let new_x = f(old_x);
|
||||
|
||||
std::ptr::write(x_ptr, new_x);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue