From ea3e2a76c4d284d31435e2a55c551d509b852319 Mon Sep 17 00:00:00 2001 From: Moritz Gmeiner Date: Fri, 1 Aug 2025 18:09:45 +0200 Subject: [PATCH] enter the Rc-RefCell madness --- fat-bits/src/datetime.rs | 8 ++ fat-bits/src/dir.rs | 62 ++++++++- fat-bits/src/fat.rs | 138 +++++++++++++++----- fat-bits/src/iter.rs | 90 +++++++++++-- fat-bits/src/lib.rs | 99 ++++++++------- fat-bits/src/subslice.rs | 74 +++++------ fat-bits/src/utils.rs | 17 +-- fat-dump/src/main.rs | 17 +-- fat-fuse/src/fuse.rs | 264 +++++++++++++++++++++++++++------------ fat-fuse/src/inode.rs | 59 +++++---- fat-fuse/src/lib.rs | 137 +++++++------------- fat-mount/src/main.rs | 7 +- 12 files changed, 619 insertions(+), 353 deletions(-) diff --git a/fat-bits/src/datetime.rs b/fat-bits/src/datetime.rs index b9672f2..ecc5309 100644 --- a/fat-bits/src/datetime.rs +++ b/fat-bits/src/datetime.rs @@ -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 } diff --git a/fat-bits/src/dir.rs b/fat-bits/src/dir.rs index 043ffae..eb7460b 100644 --- a/fat-bits/src/dir.rs +++ b/fat-bits/src/dir.rs @@ -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] { diff --git a/fat-bits/src/fat.rs b/fat-bits/src/fat.rs index bc475dd..8cdc5d0 100644 --- a/fat-bits/src/fat.rs +++ b/fat-bits/src/fat.rs @@ -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; - fn get_reserved_clusters(&self) -> RangeInclusive; - fn get_defective_cluster(&self) -> u32; - fn get_reserved_eof_clusters(&self) -> RangeInclusive; - fn get_eof_cluster(&self) -> u32; + fn valid_clusters(&self) -> RangeInclusive; + fn reserved_clusters(&self) -> RangeInclusive; + fn defective_cluster(&self) -> u32; + fn reserved_eof_clusters(&self) -> RangeInclusive; + 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 { + fn set_entry(&mut self, cluster: u32, entry: u32) { + self.next_sectors[cluster as usize] = entry as u16; + } + + fn valid_clusters(&self) -> RangeInclusive { 2..=self.max } - fn get_reserved_clusters(&self) -> RangeInclusive { + fn reserved_clusters(&self) -> RangeInclusive { (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 { + fn reserved_eof_clusters(&self) -> RangeInclusive { 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 { + fn set_entry(&mut self, cluster: u32, entry: u32) { + self.next_sectors[cluster as usize] = entry as u16; + } + + fn valid_clusters(&self) -> RangeInclusive { 2..=self.max } - fn get_reserved_clusters(&self) -> RangeInclusive { + fn reserved_clusters(&self) -> RangeInclusive { (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 { + fn reserved_eof_clusters(&self) -> RangeInclusive { 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 { + fn set_entry(&mut self, cluster: u32, entry: u32) { + self.next_sectors[cluster as usize] = entry; + } + + fn valid_clusters(&self) -> RangeInclusive { 2..=self.max } - fn get_reserved_clusters(&self) -> RangeInclusive { + fn reserved_clusters(&self) -> RangeInclusive { (self.max + 1)..=0xFFFFFFF6 } - fn get_defective_cluster(&self) -> u32 { + fn defective_cluster(&self) -> u32 { 0xFFFFFFF7 } - fn get_reserved_eof_clusters(&self) -> RangeInclusive { + fn reserved_eof_clusters(&self) -> RangeInclusive { 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(()) + } } diff --git a/fat-bits/src/iter.rs b/fat-bits/src/iter.rs index e5f6eb4..726198e 100644 --- a/fat-bits/src/iter.rs +++ b/fat-bits/src/iter.rs @@ -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, } @@ -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, +} + +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 { + 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(()) + } +} diff --git a/fat-bits/src/lib.rs b/fat-bits/src/lib.rs index 3c121cd..a2f0d7f 100644 --- a/fat-bits/src/lib.rs +++ b/fat-bits/src/lib.rs @@ -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 { + 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, 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> { - 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 + '_> // TODO: maybe wrap this in another RootDirIter enum, so we don't have to Box @@ -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) + } } diff --git a/fat-bits/src/subslice.rs b/fat-bits/src/subslice.rs index 3f388f4..798fc74 100644 --- a/fat-bits/src/subslice.rs +++ b/fat-bits/src/subslice.rs @@ -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>, 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>, 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 { 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 { 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>, 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>, 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 { 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])?; diff --git a/fat-bits/src/utils.rs b/fat-bits/src/utils.rs index 0fe9834..1e20e9d 100644 --- a/fat-bits/src/utils.rs +++ b/fat-bits/src/utils.rs @@ -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(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); - } -} diff --git a/fat-dump/src/main.rs b/fat-dump/src/main.rs index 539bfe0..e266352 100644 --- a/fat-dump/src/main.rs +++ b/fat-dump/src/main.rs @@ -1,6 +1,5 @@ use fat_bits::FatFs; use fat_bits::dir::DirEntry; -use fat_bits::fat::Fatty as _; pub fn main() -> anyhow::Result<()> { let args = std::env::args(); @@ -21,16 +20,18 @@ pub fn main() -> anyhow::Result<()> { let fat_fs = FatFs::load(file)?; - println!("{}", fat_fs.bpb()); - println!(); - println!("{}", fat_fs.fat()); + // println!("{}", fat_fs.bpb()); + // println!(); + // println!("{}", fat_fs.fat()); + + println!("{}", fat_fs); println!(); println!( "free clusters: {} ({} bytes)", - fat_fs.fat().count_free_clusters(), - fat_fs.fat().count_free_clusters() - * fat_fs.bpb().bytes_per_sector() as usize - * fat_fs.bpb().sectors_per_cluster() as usize + fat_fs.free_clusters(), + fat_fs.free_clusters() + * fat_fs.bytes_per_sector() as usize + * fat_fs.sectors_per_cluster() as usize ); println!(); diff --git a/fat-fuse/src/fuse.rs b/fat-fuse/src/fuse.rs index ed48352..938fe7c 100644 --- a/fat-fuse/src/fuse.rs +++ b/fat-fuse/src/fuse.rs @@ -1,5 +1,5 @@ use std::ffi::c_int; -use std::io::Read; +use std::io::{Read, Write}; use std::rc::Rc; use std::time::Duration; @@ -8,7 +8,7 @@ use fuser::{FileType, Filesystem}; use libc::{EBADF, EINVAL, EIO, EISDIR, ENOENT, ENOSYS, ENOTDIR}; use log::{debug, error}; -use crate::{FatFuse, Inode}; +use crate::FatFuse; const TTL: Duration = Duration::from_secs(1); @@ -50,56 +50,34 @@ impl Filesystem for FatFuse { debug!("looking up file {} with parent ino {}", name, parent); - let Some(parent_inode) = self.get_inode(parent) else { + let Some(parent_inode) = self.get_inode(parent).cloned() else { // parent inode does not exist // TODO: how can we make sure this does not happed? // TODO: panic? debug!("could not find inode for parent ino {}", parent); - reply.error(EIO); + reply.error(ENOENT); return; }; - // let Ok(mut dir_iter) = parent_inode.dir_iter(&self.fat_fs) else { - // reply.error(ENOTDIR); - // return; - // }; + let parent_inode = parent_inode.borrow(); - // let Some(dir_entry) = - // dir_iter.find(|dir_entry| dir_entry.name_string().as_deref() == Some(name)) - // else { - // reply.error(ENOENT); - // return; - // }; + let dir_entry: DirEntry = + match parent_inode + .dir_iter(&self.fat_fs) + .and_then(|mut dir_iter| { + dir_iter + .find(|dir_entry| &dir_entry.name_string() == name) + .ok_or(ENOENT) + }) { + Ok(dir_entry) => dir_entry, + Err(err) => { + debug!("error: {}", err); + reply.error(err); - let dir_entry: DirEntry = match parent_inode - .dir_iter(&self.fat_fs) - // .map_err(|_| ENOTDIR) - .and_then(|mut dir_iter| { - dir_iter - .find(|dir_entry| &dir_entry.name_string() == name) - .ok_or(ENOENT) - }) { - Ok(dir_entry) => dir_entry, - Err(err) => { - debug!("error: {}", err); - reply.error(err); - - return; - } - }; - - // let inode = match self.get_inode_by_first_cluster(dir_entry.first_cluster()) { - // Some(inode) => inode, - // None => { - // // no inode found, make a new one - // let ino = self.next_ino(); - - // let inode = Inode::new(&self.fat_fs, &dir_entry, ino, self.uid, self.gid); - - // self.insert_inode(inode) - // } - // }; + return; + } + }; let inode = self.get_or_make_inode_by_dir_entry( &dir_entry, @@ -107,6 +85,8 @@ impl Filesystem for FatFuse { parent_inode.path(), ); + let mut inode = inode.borrow_mut(); + let attr = inode.file_attr(); let generation = inode.generation(); @@ -118,19 +98,21 @@ impl Filesystem for FatFuse { fn forget(&mut self, _req: &fuser::Request<'_>, ino: u64, nlookup: u64) { debug!("forgetting ino {} ({} times)", ino, nlookup); - let Some(inode) = self.get_inode_mut(ino) else { + let Some(inode) = self.get_inode(ino).cloned() else { debug!("tried to forget {} refs of inode {}, but was not found", ino, nlookup); return; }; - // *ref_count = ref_count.saturating_sub(nlookup); + let mut inode_ref = inode.borrow_mut(); - if inode.dec_ref_count(nlookup) == 0 { - debug!("dropping inode with ino {}", inode.ino()); + if inode_ref.dec_ref_count(nlookup) == 0 { + debug!("dropping inode {}", inode_ref.ino()); + + drop(inode_ref); // no more references, drop inode - self.drop_inode(ino); + self.drop_inode(inode); } } @@ -146,20 +128,20 @@ impl Filesystem for FatFuse { let inode = if let Some(fh) = fh { let Some(inode) = self.get_inode_by_fh(fh) else { - reply.error(EIO); - + reply.error(EBADF); return; }; inode - } else if let Some(inode) = self.get_inode(ino) { + } else if let Some(inode) = self.get_inode(ino).cloned() { inode } else { - reply.error(EIO); - + reply.error(ENOENT); return; }; + let inode = inode.borrow(); + let attr = inode.file_attr(); reply.attr(&TTL, &attr); @@ -189,6 +171,17 @@ impl Filesystem for FatFuse { ino, mode, uid, gid, size, fh, flags ); reply.error(ENOSYS); + return; + + // TODO: implement this properly + // let Some(inode) = self.get_inode(ino) else { + // debug!("tried to get inode {ino}, but not found"); + // + // reply.error(ENOENT); + // return; + // }; + // + // reply.attr(&TTL, &inode.file_attr()); } fn readlink(&mut self, _req: &fuser::Request<'_>, ino: u64, reply: fuser::ReplyData) { @@ -272,7 +265,7 @@ impl Filesystem for FatFuse { fn open(&mut self, _req: &fuser::Request<'_>, ino: u64, _flags: i32, reply: fuser::ReplyOpen) { if !self.inode_table.contains_key(&ino) { - reply.error(EINVAL); + reply.error(ENOENT); return; } @@ -321,10 +314,12 @@ impl Filesystem for FatFuse { return; }; + let inode = inode.borrow(); + if inode.ino() != ino { debug!("fh {fh} is associated with inode {} instead of {ino}", inode.ino()); - reply.error(EIO); + reply.error(EINVAL); return; } @@ -361,6 +356,8 @@ impl Filesystem for FatFuse { } }; + debug!("read {n} bytes"); + reply.data(&buf[..n]); } @@ -371,23 +368,102 @@ impl Filesystem for FatFuse { fh: u64, offset: i64, data: &[u8], - write_flags: u32, - flags: i32, - lock_owner: Option, + _write_flags: u32, + _flags: i32, + _lock_owner: Option, reply: fuser::ReplyWrite, ) { - debug!( - "[Not Implemented] write(ino: {:#x?}, fh: {}, offset: {}, data.len(): {}, \ - write_flags: {:#x?}, flags: {:#x?}, lock_owner: {:?})", - ino, - fh, - offset, - data.len(), - write_flags, - flags, - lock_owner - ); - reply.error(ENOSYS); + debug!("new write request: ino={ino} fh={fh} offset={offset} data={data:?}"); + + if offset < 0 { + debug!("tried to write with negative offset {offset}"); + + reply.error(EINVAL); + return; + } + + let offset = offset as u64; + + let Some(inode) = self.get_inode_by_fh(fh) else { + debug!("no inode associated with fh {fh} (given ino: {ino}"); + + reply.error(EBADF); + return; + }; + + let inode = inode.borrow(); + + if inode.is_read_only() { + reply.error(EBADF); + return; + } + + if inode.ino() != ino { + debug!("fh {fh} points to ino {}, but ino {ino} was given", inode.ino()); + + reply.error(EINVAL); + return; + } + + if !inode.is_file() { + debug!("tried to use read on directory {ino}"); + + reply.error(EISDIR); + return; + } + + let mut writer = match inode.file_writer(&self.fat_fs) { + Ok(writer) => writer, + Err(err) => { + reply.error(err); + return; + } + }; + + // if writer.skip(offset) != offset { + // // writer is at EOF, bail + + // } + + let cur_offset = writer.skip(offset); + + // can't seek more than we requested + assert!(cur_offset <= offset); + + let mut bytes_written = 0; + + if cur_offset < offset { + // tried to set offset beyond EOF + // fill with zeros + let zeros = vec![0; (offset - cur_offset) as usize]; + + debug!("writing {} zeros", zeros.len()); + + if let Err(err) = writer.write_all(&zeros) { + debug!("writing zeros returned error: {err}"); + + reply.error(EIO); + return; + } + + bytes_written += zeros.len(); + } + + if let Err(err) = writer.write_all(&data) { + debug!("writing data returned error: {err}"); + + reply.error(EIO); + return; + } + + bytes_written += data.len(); + + reply.written(bytes_written as u32); + + // TODO: update file size + if offset + bytes_written as u64 > inode.size() { + todo!() + } } fn flush( @@ -395,14 +471,34 @@ impl Filesystem for FatFuse { _req: &fuser::Request<'_>, ino: u64, fh: u64, - lock_owner: u64, + _lock_owner: u64, reply: fuser::ReplyEmpty, ) { - debug!( - "[Not Implemented] flush(ino: {:#x?}, fh: {}, lock_owner: {:?})", - ino, fh, lock_owner - ); - reply.error(ENOSYS); + // debug!( + // "[Not Implemented] flush(ino: {:#x?}, fh: {}, lock_owner: {:?})", + // ino, fh, lock_owner + // ); + // reply.error(ENOSYS); + + debug!("flushing ino={ino} fh={fh}"); + + let Some(&found_ino) = self.ino_by_fh.get(&fh) else { + debug!("expected fh {fh} to be mapped to ino {ino}, but not found instead"); + + reply.error(EBADF); + return; + }; + + if found_ino != ino { + debug!( + "expected fh {fh} to be mapped to ino {ino}, but was mapped to {found_ino} instead" + ); + + reply.error(EBADF); + return; + } + + reply.ok(); } fn release( @@ -418,14 +514,14 @@ impl Filesystem for FatFuse { let Some(found_ino) = self.ino_by_fh.remove(&fh) else { debug!("tried to release fh {fh} with ino {ino}, but no ino was found in mapping"); - reply.error(EINVAL); + reply.error(EBADF); return; }; if found_ino != ino { debug!("tried to release fh {fh} with ino {ino}, but found ino is {found_ino} instead"); - reply.error(EIO); + reply.error(EINVAL); return; } @@ -475,10 +571,12 @@ impl Filesystem for FatFuse { let Some(dir_inode) = self.get_inode_by_fh(fh) else { debug!("could not find inode accociated with fh {} (ino: {})", fh, ino); - reply.error(EINVAL); + reply.error(EBADF); return; }; + let dir_inode = dir_inode.borrow(); + if dir_inode.ino() != ino { debug!( "ino {} of inode associated with fh {} does not match given ino {}", @@ -533,9 +631,11 @@ impl Filesystem for FatFuse { for dir_entry in dirs { let name = dir_entry.name_string(); - let inode: &Inode = + let inode = self.get_or_make_inode_by_dir_entry(&dir_entry, dir_ino, Rc::clone(&dir_path)); + let inode = inode.borrow(); + debug!("adding entry {} (ino: {})", name, inode.ino()); if reply.add(ino, next_offset(), inode.kind().into(), name) { return; @@ -571,17 +671,19 @@ impl Filesystem for FatFuse { let Some(ino) = self.ino_by_fh.remove(&fh) else { debug!("can't find inode {} by fh {}", ino, fh); - reply.error(EIO); + reply.error(EBADF); return; }; - let Some(inode) = self.inode_table.get(&ino) else { + let Some(inode) = self.get_inode(ino) else { debug!("ino {} not associated with an inode", ino); reply.ok(); return; }; + let inode = inode.borrow(); + if inode.ino() != ino { debug!( "inode with ino {}, associated with fh {}, does not have expected ino {}", diff --git a/fat-fuse/src/inode.rs b/fat-fuse/src/inode.rs index c8da0b1..6cce26f 100644 --- a/fat-fuse/src/inode.rs +++ b/fat-fuse/src/inode.rs @@ -1,11 +1,11 @@ use std::cell::{LazyCell, RefCell}; -use std::rc::Rc; +use std::rc::{Rc, Weak}; use std::time::SystemTime; use chrono::{NaiveDateTime, NaiveTime}; use fat_bits::FatFs; use fat_bits::dir::DirEntry; -use fat_bits::iter::ClusterChainReader; +use fat_bits::iter::{ClusterChainReader, ClusterChainWriter}; use fuser::FileAttr; use libc::{EISDIR, ENOTDIR}; use log::debug; @@ -27,12 +27,6 @@ fn get_random() -> T where rand::distr::StandardUniform: rand::distr::Distribution, { - // RNG.with(|x| unsafe { - // let rng = &mut (*x.get()); - - // rng.random::() - // }) - RNG.with(|rng| rng.borrow_mut().random()) } @@ -53,6 +47,9 @@ impl From for fuser::FileType { pub const ROOT_INO: u64 = 1; +pub type InodeRef = Rc>; +pub type InodeWeak = Weak>; + #[derive(Debug)] #[allow(dead_code)] pub struct Inode { @@ -63,7 +60,7 @@ pub struct Inode { ref_count: u64, - parent_ino: u64, + parent: Option, size: u64, block_size: u32, @@ -105,7 +102,7 @@ impl Inode { uid: u32, gid: u32, path: impl Into>, - parent_ino: u64, + parent: InodeRef, ) -> Inode { assert!(dir_entry.is_file() || dir_entry.is_dir()); @@ -142,9 +139,9 @@ impl Inode { ino, generation, ref_count: 0, - parent_ino, + parent: Some(parent), size: dir_entry.file_size() as u64, - block_size: fat_fs.bpb().bytes_per_sector() as u32, + block_size: fat_fs.bytes_per_sector() as u32, kind, read_only: dir_entry.is_readonly(), atime, @@ -158,17 +155,15 @@ impl Inode { } pub fn root_inode(fat_fs: &FatFs, uid: u32, gid: u32) -> Inode { - // let generation = Self::new_generation(); - - let root_cluster = fat_fs.bpb().root_cluster().unwrap_or(0); + let root_cluster = fat_fs.root_cluster().unwrap_or(0); Inode { - ino: 1, - generation: 0, + ino: ROOT_INO, + generation: 0, // root cluster always has constant generation of 0 ref_count: 0, - parent_ino: ROOT_INO, // parent is self + parent: None, // parent is self size: 0, - block_size: fat_fs.bpb().bytes_per_sector() as u32, + block_size: fat_fs.bytes_per_sector() as u32, kind: Kind::Dir, read_only: false, atime: SystemTime::UNIX_EPOCH, @@ -225,8 +220,18 @@ impl Inode { self.ref_count } - pub fn parent_ino(&self) -> u64 { - self.parent_ino + pub fn parent(&self) -> Option { + self.parent.clone() + } + + pub fn size(&self) -> u64 { + self.size + } + + pub fn update_size(&mut self, new_size: u64) { + self.size = new_size; + + todo!("update dir entry") } pub fn kind(&self) -> Kind { @@ -241,6 +246,10 @@ impl Inode { self.kind == Kind::Dir } + pub fn is_read_only(&self) -> bool { + self.read_only + } + pub fn first_cluster(&self) -> u32 { self.first_cluster } @@ -298,4 +307,12 @@ impl Inode { Ok(fat_fs.file_reader(self.first_cluster())) } + + pub fn file_writer<'a>(&'a self, fat_fs: &'a FatFs) -> Result, i32> { + if self.is_dir() { + return Err(EISDIR); + } + + Ok(fat_fs.file_writer(self.first_cluster())) + } } diff --git a/fat-fuse/src/lib.rs b/fat-fuse/src/lib.rs index 5291746..4aa53eb 100644 --- a/fat-fuse/src/lib.rs +++ b/fat-fuse/src/lib.rs @@ -1,15 +1,16 @@ mod fuse; mod inode; +use std::cell::RefCell; use std::collections::BTreeMap; use std::rc::Rc; use fat_bits::dir::DirEntry; use fat_bits::{FatFs, SliceLike}; use fxhash::FxHashMap; -use log::debug; +use log::{debug, error}; -use crate::inode::Inode; +use crate::inode::{Inode, InodeRef}; #[allow(dead_code)] pub struct FatFuse { @@ -21,7 +22,7 @@ pub struct FatFuse { next_ino: u64, next_fh: u64, - inode_table: BTreeMap, + inode_table: BTreeMap, ino_by_first_cluster: BTreeMap, ino_by_fh: BTreeMap, @@ -84,26 +85,28 @@ impl FatFuse { fh } - fn insert_inode(&mut self, inode: Inode) -> &mut Inode { + fn insert_inode(&mut self, inode: Inode) -> InodeRef { let ino = inode.ino(); let generation = inode.generation(); let first_cluster = inode.first_cluster(); // let old_inode = self.inode_table.insert(ino, inode); + let inode = Rc::new(RefCell::new(inode)); + let entry = self.inode_table.entry(ino); - let (new_inode, old_inode): (&mut Inode, Option) = match entry { + let (new_inode, old_inode) = match entry { std::collections::btree_map::Entry::Vacant(vacant_entry) => { let new_inode = vacant_entry.insert(inode); - (new_inode, None) + (Rc::clone(new_inode), None) } std::collections::btree_map::Entry::Occupied(occupied_entry) => { let entry_ref = occupied_entry.into_mut(); let old_inode = std::mem::replace(entry_ref, inode); - (entry_ref, Some(old_inode)) + (Rc::clone(entry_ref), Some(old_inode)) } }; @@ -113,6 +116,8 @@ impl FatFuse { ); if let Some(old_inode) = old_inode { + let old_inode = old_inode.borrow(); + debug!("ejected inode {} {}", old_inode.ino(), old_inode.generation()); } @@ -122,22 +127,32 @@ impl FatFuse { } } - if let Some(old_ino) = self.ino_by_path.insert(new_inode.path(), ino) { - debug!("ejected old {} -> {} path to ino mapping", new_inode.path(), old_ino); + let path = new_inode.borrow().path(); + + if let Some(old_ino) = self.ino_by_path.insert(Rc::clone(&path), ino) { + debug!("ejected old {} -> {} path to ino mapping", path, old_ino); } new_inode } - fn drop_inode(&mut self, ino: u64) { - debug!("dropping ino {}", ino); + fn drop_inode(&mut self, inode: InodeRef) { + let inode = inode.borrow(); - let Some(inode) = self.inode_table.remove(&ino) else { - debug!("tried to drop inode with ino {}, but was not in table", ino); + let ino = inode.ino(); + + debug!("dropping inode {}", ino); + + let Some(removed_inode) = self.inode_table.remove(&ino) else { + error!("tried to drop inode with ino {}, but was not in table", ino); return; }; + if removed_inode.borrow().ino() != ino { + error!("removed inode was not expected inode"); + } + let first_cluster = inode.first_cluster(); if first_cluster != 0 { @@ -189,39 +204,28 @@ impl FatFuse { } } } - - let Some(parent_inode) = self.get_inode_mut(inode.parent_ino()) else { - panic!("parent inode {} does not exists anymore", inode.parent_ino()); - }; - - // dec refcount - parent_inode.dec_ref_count(1); } - fn get_inode(&self, ino: u64) -> Option<&Inode> { + fn get_inode(&self, ino: u64) -> Option<&InodeRef> { self.inode_table.get(&ino) } - fn get_inode_mut(&mut self, ino: u64) -> Option<&mut Inode> { - self.inode_table.get_mut(&ino) - } - fn get_or_make_inode_by_dir_entry( &mut self, dir_entry: &DirEntry, parent_ino: u64, parent_path: Rc, - ) -> &mut Inode { + ) -> InodeRef { + // try to find inode by first cluster first if dir_entry.first_cluster() != 0 - && self - .get_inode_by_first_cluster_mut(dir_entry.first_cluster()) - .is_some() + && let Some(inode) = self.get_inode_by_first_cluster(dir_entry.first_cluster()) { - return self - .get_inode_by_first_cluster_mut(dir_entry.first_cluster()) - .unwrap(); + return inode; } + // try to find inode by path + // mostly for empty files/directories which have a first cluster of 0 + let path = { let mut path = parent_path.as_ref().to_owned(); @@ -235,27 +239,25 @@ impl FatFuse { path }; - if self.get_inode_by_path_mut(&path).is_some() { - return self.get_inode_by_path_mut(&path).unwrap(); + if let Some(inode) = self.get_inode_by_path(&path) { + return inode; } // no inode found, make a new one let ino = self.next_ino(); - let Some(parent_inode) = self.get_inode_mut(parent_ino) else { + let Some(parent_inode) = self.get_inode(parent_ino).cloned() else { // TODO: what do we do here? should not happen panic!("parent_ino {} does not lead to inode", parent_ino); }; - // inc ref of parent - parent_inode.inc_ref_count(); - - let inode = Inode::new(&self.fat_fs, dir_entry, ino, self.uid, self.gid, path, parent_ino); + let inode = + Inode::new(&self.fat_fs, dir_entry, ino, self.uid, self.gid, path, parent_inode); self.insert_inode(inode) } - pub fn get_inode_by_first_cluster(&self, first_cluster: u32) -> Option<&Inode> { + pub fn get_inode_by_first_cluster(&self, first_cluster: u32) -> Option { if first_cluster == 0 { debug!("trying to get inode by first cluster 0"); @@ -265,7 +267,7 @@ impl FatFuse { let ino = self.ino_by_first_cluster.get(&first_cluster)?; if let Some(inode) = self.inode_table.get(ino) { - Some(inode) + Some(Rc::clone(inode)) } else { debug!( "first cluster {} is mapped to ino {}, but inode is not in table", @@ -276,31 +278,10 @@ impl FatFuse { } } - pub fn get_inode_by_first_cluster_mut(&mut self, first_cluster: u32) -> Option<&mut Inode> { - if first_cluster == 0 { - debug!("trying to get inode by first cluster 0"); - - return None; - } - - let ino = self.ino_by_first_cluster.get(&first_cluster)?; - - if let Some(inode) = self.inode_table.get_mut(ino) { - Some(inode) - } else { - debug!( - "first cluster {} is mapped to ino {}, but inode is not in table", - first_cluster, ino - ); - - None - } - } - - pub fn get_inode_by_fh(&self, fh: u64) -> Option<&Inode> { + pub fn get_inode_by_fh(&self, fh: u64) -> Option { let ino = *self.ino_by_fh.get(&fh)?; - if let Some(inode) = self.get_inode(ino) { + if let Some(inode) = self.get_inode(ino).cloned() { Some(inode) } else { debug!("fh {} is mapped to ino {}, but inode is not in table", fh, ino); @@ -309,34 +290,10 @@ impl FatFuse { } } - pub fn get_inode_by_fh_mut(&mut self, fh: u64) -> Option<&mut Inode> { - let ino = *self.ino_by_fh.get(&fh)?; - - if let Some(inode) = self.get_inode_mut(ino) { - Some(inode) - } else { - debug!("fh {} is mapped to ino {}, but inode is not in table", fh, ino); - - None - } - } - - pub fn get_inode_by_path(&self, path: &str) -> Option<&Inode> { + pub fn get_inode_by_path(&self, path: &str) -> Option { let ino = *self.ino_by_path.get(path)?; - if let Some(inode) = self.get_inode(ino) { - Some(inode) - } else { - debug!("path {} is mapped to ino {}, but inode is not in table", path, ino); - - None - } - } - - pub fn get_inode_by_path_mut(&mut self, path: &str) -> Option<&mut Inode> { - let ino = *self.ino_by_path.get(path)?; - - if let Some(inode) = self.get_inode_mut(ino) { + if let Some(inode) = self.get_inode(ino).cloned() { Some(inode) } else { debug!("path {} is mapped to ino {}, but inode is not in table", path, ino); diff --git a/fat-mount/src/main.rs b/fat-mount/src/main.rs index c7ad1c9..5a85ce6 100644 --- a/fat-mount/src/main.rs +++ b/fat-mount/src/main.rs @@ -1,4 +1,4 @@ -use std::fs::File; +use std::fs::OpenOptions; use std::sync::mpsc::channel; use fat_fuse::FatFuse; @@ -13,12 +13,13 @@ fn main() -> anyhow::Result<()> { let path = args.next().ok_or(anyhow::anyhow!("missing fs path"))?; let mountpoint = args.next().ok_or(anyhow::anyhow!("missing mount point"))?; - let file = File::open(path)?; + // let file = File::open(path)?; + let file = OpenOptions::new().read(true).write(true).open(path)?; let fat_fuse = FatFuse::new(file)?; let options = vec![ - MountOption::RO, + // MountOption::RO, MountOption::FSName("fat-fuse".to_owned()), MountOption::AutoUnmount, ];