tried to implement file cluster extension (bug it's still bugged)
This commit is contained in:
parent
343e8c6c77
commit
9cb6ee6446
8 changed files with 253 additions and 77 deletions
|
|
@ -8,6 +8,7 @@ anyhow = "1.0.98"
|
|||
bitflags = "2.9.1"
|
||||
chrono = { version = "0.4.41", default-features = false, features = [
|
||||
"alloc",
|
||||
"clock",
|
||||
"std",
|
||||
] }
|
||||
compact_str = "0.9.0"
|
||||
|
|
|
|||
|
|
@ -213,7 +213,8 @@ impl DirEntry {
|
|||
|
||||
buf[28..].copy_from_slice(&self.file_size.to_le_bytes());
|
||||
|
||||
eprintln!("writing new dir entry: {:?}", buf);
|
||||
debug!("self: {self:?}");
|
||||
debug!("writing new dir entry: {:?}", buf);
|
||||
|
||||
writer.write_all(&buf)?;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,10 +4,13 @@ use std::mem::MaybeUninit;
|
|||
use std::ops::RangeInclusive;
|
||||
|
||||
use enum_dispatch::enum_dispatch;
|
||||
use log::debug;
|
||||
|
||||
use crate::FatType;
|
||||
use crate::subslice::SubSliceMut;
|
||||
|
||||
const FREE_ENTRY: u32 = 0;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum FatError {
|
||||
#[error("can't get next cluster of free cluster")]
|
||||
|
|
@ -21,7 +24,7 @@ pub enum FatError {
|
|||
}
|
||||
|
||||
#[enum_dispatch]
|
||||
pub trait FatOps {
|
||||
trait FatOps {
|
||||
// get the next cluster
|
||||
// assumes the cluster is valid, i.e. allocated
|
||||
fn get_entry(&self, cluster: u32) -> u32;
|
||||
|
|
@ -33,23 +36,12 @@ pub trait FatOps {
|
|||
fn reserved_eof_entries(&self) -> RangeInclusive<u32>;
|
||||
fn eof_entry(&self) -> u32;
|
||||
|
||||
fn count_free_clusters(&self) -> u32 {
|
||||
self.valid_entries()
|
||||
.map(|cluster| self.get_entry(cluster))
|
||||
.filter(|&entry| entry == 0)
|
||||
.count() as u32
|
||||
}
|
||||
|
||||
fn first_free_cluster(&self) -> Option<u32> {
|
||||
self.valid_entries()
|
||||
.map(|cluster| self.get_entry(cluster))
|
||||
.find(|&entry| entry == 0)
|
||||
}
|
||||
|
||||
fn write_to_disk(&self, sub_slice: SubSliceMut) -> std::io::Result<()>;
|
||||
}
|
||||
|
||||
#[enum_dispatch(FatOps)]
|
||||
// others should never touch the inner FatNs directly, but instead go through the Fat type
|
||||
#[allow(private_interfaces)]
|
||||
pub enum Fat {
|
||||
Fat12(Fat12),
|
||||
Fat16(Fat16),
|
||||
|
|
@ -75,8 +67,16 @@ impl Fat {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn fat_type(&self) -> FatType {
|
||||
match self {
|
||||
Fat::Fat12(_) => FatType::Fat12,
|
||||
Fat::Fat16(_) => FatType::Fat16,
|
||||
Fat::Fat32(_) => FatType::Fat32,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_next_cluster(&self, cluster: u32) -> Result<Option<u32>, FatError> {
|
||||
if cluster == 0x000 {
|
||||
if cluster == FREE_ENTRY {
|
||||
// can't get next cluster for free cluster
|
||||
return Err(FatError::FreeCluster);
|
||||
}
|
||||
|
|
@ -104,21 +104,117 @@ impl Fat {
|
|||
|
||||
let entry = self.get_entry(cluster);
|
||||
|
||||
// interpret second reserved block as EOF here
|
||||
if entry == self.eof_entry() || self.reserved_eof_entries().contains(&entry) {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
// entry should be in the valid cluster range here; otherwise something went wrong
|
||||
if !self.valid_entries().contains(&entry) {
|
||||
return Err(FatError::InvalidEntry(entry));
|
||||
}
|
||||
|
||||
if entry == FREE_ENTRY {
|
||||
Ok(None)
|
||||
} else if entry == self.eof_entry() {
|
||||
Ok(None)
|
||||
} else if self.valid_entries().contains(&entry) {
|
||||
Ok(Some(entry))
|
||||
} else if self.reserved_entries().contains(&entry) || entry == 1 {
|
||||
Err(FatError::ReservedCluster(entry))
|
||||
} else if entry == self.defective_entry() {
|
||||
Err(FatError::DefectiveCluster)
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
/// set the next cluster of `cluster` to either some `next_cluster` or EOF
|
||||
///
|
||||
/// if `cluster` currently points to another cluster, that cluster MUST be the EOF and will be
|
||||
/// freed
|
||||
pub fn set_next_cluster(&mut self, cluster: u32, next_cluster: Option<u32>) {
|
||||
assert!(self.valid_entries().contains(&cluster));
|
||||
|
||||
let cur_next_cluster = self.get_entry(cluster);
|
||||
|
||||
// can't be defective
|
||||
assert_ne!(cur_next_cluster, self.defective_entry());
|
||||
|
||||
if self.valid_entries().contains(&cur_next_cluster) {
|
||||
// cluster currently points to a valid cluster, so we free it
|
||||
|
||||
log::debug!("freeing chain beginning at {cluster}");
|
||||
self.free_chain(cluster);
|
||||
}
|
||||
|
||||
if let Some(next_cluster) = next_cluster {
|
||||
assert!(self.valid_entries().contains(&next_cluster));
|
||||
}
|
||||
|
||||
if let Some(next_cluster) = next_cluster {
|
||||
log::debug!("setting {cluster} -> {next_cluster}");
|
||||
} else {
|
||||
log::debug!("setting {cluster} EOF");
|
||||
}
|
||||
|
||||
self.set_entry(cluster, next_cluster.unwrap_or(self.eof_entry()));
|
||||
}
|
||||
|
||||
/// free a cluster
|
||||
///
|
||||
/// must be EOF
|
||||
pub fn free_cluster(&mut self, cluster: u32) {
|
||||
debug!("freeing cluster {cluster}");
|
||||
|
||||
let entry = self.get_entry(cluster);
|
||||
|
||||
if entry == FREE_ENTRY {
|
||||
// nothing to be done here
|
||||
debug!("cluster was already free");
|
||||
return;
|
||||
}
|
||||
|
||||
// can't be reserved or defective
|
||||
// can't be pointing to another cluster (we'd orphan that one)
|
||||
// use free_chain to free a chain of clusters iteratively
|
||||
assert!(self.is_eof(entry));
|
||||
|
||||
self.set_entry(cluster, FREE_ENTRY);
|
||||
}
|
||||
|
||||
/// free `first_cluster` and all following clusters
|
||||
pub fn free_chain(&mut self, mut first_cluster: u32) {
|
||||
debug!("freeing chaing at {first_cluster}");
|
||||
|
||||
loop {
|
||||
let entry = self.get_entry(first_cluster);
|
||||
|
||||
// assert cluster either points to another cluster of is the EOF
|
||||
assert!(self.valid_entries().contains(&entry) || self.is_eof(entry));
|
||||
|
||||
self.set_entry(first_cluster, FREE_ENTRY);
|
||||
|
||||
if self.valid_entries().contains(&entry) {
|
||||
first_cluster = entry;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn count_free_clusters(&self) -> u32 {
|
||||
self.valid_entries()
|
||||
.map(|cluster| self.get_entry(cluster))
|
||||
.filter(|&entry| entry == FREE_ENTRY)
|
||||
.count() as u32
|
||||
}
|
||||
|
||||
pub fn first_free_cluster(&self) -> Option<u32> {
|
||||
self.valid_entries()
|
||||
.find(|&cluster| self.get_entry(cluster) == FREE_ENTRY)
|
||||
}
|
||||
|
||||
fn is_eof(&self, entry: u32) -> bool {
|
||||
entry == self.eof_entry() || self.reserved_eof_entries().contains(&entry)
|
||||
}
|
||||
|
||||
pub fn write_back(&self, sub_slice: SubSliceMut) -> std::io::Result<()> {
|
||||
self.write_to_disk(sub_slice)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Fat12 {
|
||||
struct Fat12 {
|
||||
max: u32,
|
||||
|
||||
next_sectors: Box<[u16]>,
|
||||
|
|
@ -129,7 +225,7 @@ impl Display for Fat12 {
|
|||
writeln!(f, "Fat 12 {{")?;
|
||||
|
||||
for (i, &x) in self.next_sectors.iter().enumerate() {
|
||||
if x != 0 {
|
||||
if x != FREE_ENTRY as u16 {
|
||||
writeln!(f, " 0x{:03X} -> 0x{:03X}", i, x)?;
|
||||
}
|
||||
}
|
||||
|
|
@ -155,7 +251,10 @@ impl Fat12 {
|
|||
|
||||
// assume bytes.len() is multiple of 3
|
||||
// TODO: fix later
|
||||
assert_eq!(bytes.len() % 3, 0);
|
||||
// assert_eq!(bytes.len() % 3, 0);
|
||||
assert_eq!(max % 2, 0);
|
||||
|
||||
let bytes = &bytes[..next_sectors.len() / 2 * 3];
|
||||
|
||||
let (chunks, rem) = bytes.as_chunks::<3>();
|
||||
|
||||
|
|
@ -222,11 +321,9 @@ impl FatOps for Fat12 {
|
|||
}
|
||||
|
||||
fn write_to_disk(&self, mut sub_slice: SubSliceMut) -> std::io::Result<()> {
|
||||
// TODO: currently assumed FAT has even number of entries
|
||||
assert!(2 * sub_slice.len() > 3 * self.next_sectors.len());
|
||||
|
||||
assert_eq!(3 * sub_slice.len(), self.next_sectors.len());
|
||||
|
||||
let mut iter = self.next_sectors.chunks_exact(3);
|
||||
let mut iter = self.next_sectors.chunks_exact(2);
|
||||
|
||||
let mut buf: [u8; 3];
|
||||
|
||||
|
|
@ -255,13 +352,18 @@ impl FatOps for Fat12 {
|
|||
sub_slice.write_all(&buf)?;
|
||||
}
|
||||
|
||||
assert_eq!(iter.remainder().len(), 0);
|
||||
match iter.remainder() {
|
||||
[] => {}
|
||||
[x] => sub_slice.write_all(&x.to_le_bytes())?,
|
||||
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Fat16 {
|
||||
struct Fat16 {
|
||||
max: u32,
|
||||
|
||||
next_sectors: Box<[u16]>,
|
||||
|
|
@ -272,7 +374,7 @@ impl Display for Fat16 {
|
|||
writeln!(f, "Fat 16 {{")?;
|
||||
|
||||
for (i, &x) in self.next_sectors.iter().enumerate() {
|
||||
if x != 0 {
|
||||
if x != FREE_ENTRY as u16 {
|
||||
writeln!(f, " 0x{:03X} -> 0x{:03X}", i, x)?;
|
||||
}
|
||||
}
|
||||
|
|
@ -359,7 +461,7 @@ impl FatOps for Fat16 {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct Fat32 {
|
||||
struct Fat32 {
|
||||
max: u32,
|
||||
|
||||
next_sectors: Box<[u32]>,
|
||||
|
|
@ -370,7 +472,7 @@ impl Display for Fat32 {
|
|||
writeln!(f, "Fat 32 {{")?;
|
||||
|
||||
for (i, &x) in self.next_sectors.iter().enumerate() {
|
||||
if x != 0 {
|
||||
if x != FREE_ENTRY {
|
||||
writeln!(f, " 0x{:03X} -> 0x{:03X}", i, x)?;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
use std::io::{Read, Write};
|
||||
|
||||
use log::debug;
|
||||
|
||||
use crate::subslice::{SubSlice, SubSliceMut};
|
||||
use crate::{FatFs, FatType};
|
||||
|
||||
|
|
@ -96,27 +98,28 @@ impl Read for ClusterChainReader<'_> {
|
|||
}
|
||||
|
||||
pub struct ClusterChainWriter<'a> {
|
||||
fat_fs: &'a FatFs,
|
||||
fat_fs: &'a mut FatFs,
|
||||
|
||||
sub_slice: SubSliceMut,
|
||||
|
||||
next_cluster: Option<u32>,
|
||||
// next_cluster: Option<u32>,
|
||||
cur_cluster: u32,
|
||||
}
|
||||
|
||||
impl<'a> ClusterChainWriter<'a> {
|
||||
pub fn new(fat_fs: &'a FatFs, first_cluster: u32) -> Self {
|
||||
let next_cluster = fat_fs.next_cluster(first_cluster).unwrap_or(None);
|
||||
pub fn new(fat_fs: &'a mut FatFs, first_cluster: u32) -> Self {
|
||||
// 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,
|
||||
cur_cluster: first_cluster,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn root_dir_writer(fat_fs: &'a FatFs) -> Self {
|
||||
pub fn root_dir_writer(fat_fs: &'a mut FatFs) -> Self {
|
||||
match fat_fs.fat_type() {
|
||||
FatType::Fat12 | FatType::Fat16 => {
|
||||
// fixed root dir, so no need to chain
|
||||
|
|
@ -127,7 +130,7 @@ impl<'a> ClusterChainWriter<'a> {
|
|||
ClusterChainWriter {
|
||||
fat_fs,
|
||||
sub_slice,
|
||||
next_cluster: None,
|
||||
cur_cluster: 0,
|
||||
}
|
||||
}
|
||||
FatType::Fat32 => {
|
||||
|
|
@ -140,12 +143,38 @@ impl<'a> ClusterChainWriter<'a> {
|
|||
|
||||
fn move_to_next_cluster(&mut self) -> bool {
|
||||
// TODO: should allocate a new cluster here!
|
||||
let Some(next_cluster) = self.next_cluster else {
|
||||
// let Some(next_cluster) = self.next_cluster else {
|
||||
// let Some(new_cluster) = self.fat_fs.alloc_cluster() else {
|
||||
// // cluster allocation failed
|
||||
// return false;
|
||||
// };
|
||||
|
||||
// return false;
|
||||
// };
|
||||
|
||||
let Some(next_cluster) = self
|
||||
.fat_fs
|
||||
.next_cluster(self.cur_cluster)
|
||||
.map_err(|err| {
|
||||
debug!("failed to get next cluster: {err}");
|
||||
err
|
||||
})
|
||||
.unwrap_or(None)
|
||||
.or_else(|| {
|
||||
debug!("allocating new cluster");
|
||||
|
||||
self.fat_fs.alloc_cluster(Some(self.cur_cluster))
|
||||
})
|
||||
else {
|
||||
debug!("failed to allocate next cluster");
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
self.next_cluster = self.fat_fs.next_cluster(next_cluster).unwrap_or(None);
|
||||
debug!("next cluster: {next_cluster}");
|
||||
|
||||
self.fat_fs.cluster_as_subslice_mut(next_cluster);
|
||||
self.cur_cluster = next_cluster;
|
||||
|
||||
true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,10 @@ use std::cell::RefCell;
|
|||
use std::fmt::Display;
|
||||
use std::rc::Rc;
|
||||
|
||||
use log::debug;
|
||||
|
||||
use crate::dir::DirIter;
|
||||
use crate::fat::{FatError, FatOps};
|
||||
use crate::fat::FatError;
|
||||
use crate::iter::ClusterChainReader;
|
||||
pub use crate::slice_like::SliceLike;
|
||||
use crate::subslice::{SubSlice, SubSliceMut};
|
||||
|
|
@ -57,6 +59,20 @@ impl Display for FatFs {
|
|||
|
||||
unsafe impl Send for FatFs {}
|
||||
|
||||
impl Drop for FatFs {
|
||||
fn drop(&mut self) {
|
||||
let fat_slice = SubSliceMut::new(
|
||||
Rc::clone(&self.inner),
|
||||
self.bpb.fat_offset(),
|
||||
self.bpb.fat_len_bytes(),
|
||||
);
|
||||
|
||||
if let Err(err) = self.fat.write_back(fat_slice) {
|
||||
debug!("writing FAT back to disk failed: {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FatFs {
|
||||
pub fn load<S>(data: S) -> anyhow::Result<FatFs>
|
||||
where
|
||||
|
|
@ -123,18 +139,14 @@ impl FatFs {
|
|||
}
|
||||
|
||||
pub fn fat_type(&self) -> FatType {
|
||||
match &self.fat {
|
||||
fat::Fat::Fat12(_) => FatType::Fat12,
|
||||
fat::Fat::Fat16(_) => FatType::Fat16,
|
||||
fat::Fat::Fat32(_) => FatType::Fat32,
|
||||
}
|
||||
self.fat.fat_type()
|
||||
}
|
||||
|
||||
/// byte offset of data cluster
|
||||
fn data_cluster_to_offset(&self, cluster: u32) -> u64 {
|
||||
// assert!(cluster >= 2);
|
||||
|
||||
assert!(self.fat.valid_entries().contains(&cluster));
|
||||
// assert!(self.fat.valid_entries().contains(&cluster));
|
||||
|
||||
self.data_offset + (cluster - 2) as u64 * self.bytes_per_cluster as u64
|
||||
}
|
||||
|
|
@ -144,14 +156,20 @@ impl FatFs {
|
|||
self.free_count
|
||||
}
|
||||
|
||||
pub fn alloc_cluster(&mut self) -> Option<u32> {
|
||||
let Some(cluster) = self.next_free else {
|
||||
pub fn alloc_cluster(&mut self, prev_cluster: Option<u32>) -> Option<u32> {
|
||||
let Some(new_cluster) = self.next_free else {
|
||||
// no free cluster
|
||||
return None;
|
||||
};
|
||||
|
||||
// set cluster as taken
|
||||
self.fat.set_entry(cluster, self.fat.eof_entry());
|
||||
debug!("next free cluster: {new_cluster}");
|
||||
|
||||
// set cluster as EOF
|
||||
self.fat.set_next_cluster(new_cluster, None);
|
||||
|
||||
if let Some(prev_cluster) = prev_cluster {
|
||||
self.fat.set_next_cluster(prev_cluster, Some(new_cluster));
|
||||
}
|
||||
|
||||
// something went terribly wrong
|
||||
assert_ne!(self.free_count, 0);
|
||||
|
|
@ -161,18 +179,12 @@ impl FatFs {
|
|||
// find next free cluster
|
||||
self.next_free = self.fat.first_free_cluster();
|
||||
|
||||
Some(cluster)
|
||||
Some(new_cluster)
|
||||
}
|
||||
|
||||
pub fn dealloc_cluster(&mut self, cluster: u32) {
|
||||
// assert cluster is actually valid
|
||||
assert!(
|
||||
self.fat
|
||||
.valid_entries()
|
||||
.contains(&self.fat.get_entry(cluster))
|
||||
);
|
||||
|
||||
self.fat.set_entry(cluster, 0);
|
||||
self.fat.free_cluster(cluster);
|
||||
|
||||
if self.next_free.is_none() || self.next_free.unwrap() > cluster {
|
||||
self.next_free = Some(cluster);
|
||||
|
|
@ -240,7 +252,7 @@ impl FatFs {
|
|||
iter::ClusterChainReader::new(self, first_cluster)
|
||||
}
|
||||
|
||||
fn chain_writer(&'_ self, first_cluster: u32) -> iter::ClusterChainWriter<'_> {
|
||||
fn chain_writer(&'_ mut self, first_cluster: u32) -> iter::ClusterChainWriter<'_> {
|
||||
iter::ClusterChainWriter::new(self, first_cluster)
|
||||
}
|
||||
|
||||
|
|
@ -263,7 +275,7 @@ impl FatFs {
|
|||
self.chain_reader(first_cluster)
|
||||
}
|
||||
|
||||
pub fn file_writer(&self, first_cluster: u32) -> iter::ClusterChainWriter<'_> {
|
||||
pub fn file_writer(&mut self, first_cluster: u32) -> iter::ClusterChainWriter<'_> {
|
||||
// TODO: needs to take file size into account
|
||||
assert!(first_cluster >= 2);
|
||||
|
||||
|
|
|
|||
|
|
@ -6,12 +6,19 @@ edition = "2024"
|
|||
[dependencies]
|
||||
anyhow = "1.0.98"
|
||||
bitflags = "2.9.1"
|
||||
chrono = { version = "0.4.41", default-features = false, features = ["alloc", "clock", "std"] }
|
||||
chrono = { version = "0.4.41", default-features = false, features = [
|
||||
"alloc",
|
||||
"clock",
|
||||
"std",
|
||||
] }
|
||||
compact_string = "0.1.0"
|
||||
fat-bits = { version = "0.1.0", path = "../fat-bits" }
|
||||
fuser = "0.15.1"
|
||||
fxhash = "0.2.1"
|
||||
libc = "0.2.174"
|
||||
log = "0.4.27"
|
||||
rand = { version = "0.9.2", default-features = false, features = ["os_rng", "small_rng"] }
|
||||
rand = { version = "0.9.2", default-features = false, features = [
|
||||
"os_rng",
|
||||
"small_rng",
|
||||
] }
|
||||
thiserror = "2.0.12"
|
||||
|
|
|
|||
|
|
@ -117,11 +117,11 @@ impl Filesystem for FatFuse {
|
|||
let attr = inode.file_attr();
|
||||
let generation = inode.generation();
|
||||
|
||||
debug!("attr: {attr:?}");
|
||||
|
||||
reply.entry(&TTL, &attr, generation as u64);
|
||||
|
||||
inode.inc_ref_count();
|
||||
|
||||
// TODO: update access time
|
||||
}
|
||||
|
||||
fn forget(&mut self, _req: &fuser::Request<'_>, ino: u64, nlookup: u64) {
|
||||
|
|
@ -165,6 +165,14 @@ impl Filesystem for FatFuse {
|
|||
let attr = inode.file_attr();
|
||||
|
||||
inode.update_atime(SystemTime::now());
|
||||
if let Err(err) = inode.write_back(&self.fat_fs) {
|
||||
debug!("error while writing back inode: {err}");
|
||||
|
||||
reply.error(EIO);
|
||||
return;
|
||||
}
|
||||
|
||||
debug!("attr: {attr:?}");
|
||||
|
||||
reply.attr(&TTL, &attr);
|
||||
}
|
||||
|
|
@ -515,7 +523,7 @@ impl Filesystem for FatFuse {
|
|||
|
||||
let offset = offset as u64;
|
||||
|
||||
let Some(inode) = self.get_inode_by_fh(fh) else {
|
||||
let Some(inode) = self.get_inode_by_fh(fh).cloned() else {
|
||||
debug!("no inode associated with fh {fh} (given ino: {ino}");
|
||||
|
||||
reply.error(EBADF);
|
||||
|
|
@ -544,7 +552,7 @@ impl Filesystem for FatFuse {
|
|||
return;
|
||||
}
|
||||
|
||||
let mut writer = match inode.file_writer(&self.fat_fs) {
|
||||
let mut writer = match inode.file_writer(&mut self.fat_fs) {
|
||||
Ok(writer) => writer,
|
||||
Err(err) => {
|
||||
reply.error(err);
|
||||
|
|
@ -552,11 +560,6 @@ impl Filesystem for FatFuse {
|
|||
}
|
||||
};
|
||||
|
||||
// if writer.skip(offset) != offset {
|
||||
// // writer is at EOF, bail
|
||||
|
||||
// }
|
||||
|
||||
let cur_offset = writer.skip(offset);
|
||||
|
||||
// can't seek more than we requested
|
||||
|
|
|
|||
|
|
@ -320,7 +320,7 @@ impl Inode {
|
|||
Ok(fat_fs.file_reader(self.first_cluster()))
|
||||
}
|
||||
|
||||
pub fn file_writer<'a>(&'a self, fat_fs: &'a FatFs) -> Result<ClusterChainWriter<'a>, i32> {
|
||||
pub fn file_writer<'a>(&'a self, fat_fs: &'a mut FatFs) -> Result<ClusterChainWriter<'a>, i32> {
|
||||
if self.is_dir() {
|
||||
return Err(EISDIR);
|
||||
}
|
||||
|
|
@ -329,16 +329,30 @@ impl Inode {
|
|||
}
|
||||
|
||||
pub fn update_size(&mut self, new_size: u64) {
|
||||
debug!("updating size to {new_size}");
|
||||
|
||||
if new_size == self.size {
|
||||
return;
|
||||
}
|
||||
|
||||
self.size = new_size;
|
||||
self.dirty = true;
|
||||
}
|
||||
|
||||
pub fn update_atime(&mut self, atime: SystemTime) {
|
||||
if self.atime == atime {
|
||||
return;
|
||||
}
|
||||
|
||||
self.atime = atime;
|
||||
self.dirty = true;
|
||||
}
|
||||
|
||||
pub fn update_mtime(&mut self, mtime: SystemTime) {
|
||||
if self.mtime == mtime {
|
||||
return;
|
||||
}
|
||||
|
||||
self.mtime = mtime;
|
||||
self.dirty = true;
|
||||
}
|
||||
|
|
@ -348,6 +362,13 @@ impl Inode {
|
|||
return Ok(());
|
||||
}
|
||||
|
||||
if self.is_root() {
|
||||
// root dir has no attributes
|
||||
|
||||
self.dirty = false;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let Some(parent_inode) = self.parent() else {
|
||||
anyhow::bail!("parent inode of {} does not exist", self.ino);
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue