diff --git a/Cargo.lock b/Cargo.lock index bc2c84e..42708e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,21 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - [[package]] name = "anyhow" version = "1.0.98" @@ -35,21 +20,6 @@ version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" -[[package]] -name = "bumpalo" -version = "3.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" - -[[package]] -name = "cc" -version = "1.2.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7" -dependencies = [ - "shlex", -] - [[package]] name = "cfg-if" version = "1.0.1" @@ -68,18 +38,9 @@ version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" dependencies = [ - "android-tzdata", - "iana-time-zone", "num-traits", - "windows-link", ] -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - [[package]] name = "enum_dispatch" version = "0.3.13" @@ -117,7 +78,6 @@ name = "fat-fuse" version = "0.1.0" dependencies = [ "anyhow", - "chrono", "fat-bits", "fuser", "libc", @@ -141,40 +101,6 @@ dependencies = [ "zerocopy", ] -[[package]] -name = "iana-time-zone" -version = "0.1.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "log", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "js-sys" -version = "0.3.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" -dependencies = [ - "once_cell", - "wasm-bindgen", -] - [[package]] name = "libc" version = "0.2.174" @@ -254,18 +180,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "rustversion" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - [[package]] name = "smallvec" version = "1.15.1" @@ -315,64 +229,6 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" -[[package]] -name = "wasm-bindgen" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" -dependencies = [ - "unicode-ident", -] - [[package]] name = "winapi" version = "0.3.9" @@ -395,65 +251,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-core" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-link", - "windows-result", - "windows-strings", -] - -[[package]] -name = "windows-implement" -version = "0.60.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "windows-interface" -version = "0.59.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "windows-link" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" - -[[package]] -name = "windows-result" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-strings" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" -dependencies = [ - "windows-link", -] - [[package]] name = "zerocopy" version = "0.8.26" diff --git a/fat-bits/src/dir.rs b/fat-bits/src/dir.rs index bc8e7a4..98ff94c 100644 --- a/fat-bits/src/dir.rs +++ b/fat-bits/src/dir.rs @@ -192,30 +192,10 @@ impl DirEntry { self.is_dot() || self.is_dotdot() || self.attr.contains(Attr::Hidden) } - pub fn is_readonly(&self) -> bool { - self.attr.contains(Attr::ReadOnly) - } - pub fn name(&self) -> &[u8] { &self.name } - pub fn stem(&self) -> &[u8] { - &self.name()[..8] - } - - pub fn stem_str(&self) -> Option<&str> { - std::str::from_utf8(self.stem()).ok() - } - - pub fn extension(&self) -> &[u8] { - &self.name()[8..] - } - - pub fn extension_str(&self) -> Option<&str> { - std::str::from_utf8(self.extension()).ok() - } - pub fn name_string(&self) -> Option { if let Some(long_filename) = self.long_name() { return Some(long_filename.to_owned()); diff --git a/fat-bits/src/iter.rs b/fat-bits/src/iter.rs index 8a6f775..2e34765 100644 --- a/fat-bits/src/iter.rs +++ b/fat-bits/src/iter.rs @@ -1,17 +1,17 @@ use std::io::Read; -use crate::FatFs; use crate::subslice::SubSlice; use crate::utils::replace; +use crate::{FatFs, SliceLike}; -pub struct ClusterChainReader<'a> { - sub_slice: SubSlice<'a>, +pub struct ClusterChainReader<'a, S: SliceLike> { + sub_slice: SubSlice<'a, S>, next_cluster: Option, } -impl<'a> ClusterChainReader<'a> { - pub fn new(fat_fs: &'a FatFs, first_cluster: u32) -> ClusterChainReader<'a> { +impl<'a, S: SliceLike> ClusterChainReader<'a, S> { + pub fn new(fat_fs: &'a FatFs, first_cluster: u32) -> ClusterChainReader<'a, S> { let next_cluster = fat_fs.next_cluster(first_cluster).unwrap_or(None); let sub_slice = fat_fs.cluster_as_subslice(first_cluster); @@ -39,7 +39,7 @@ impl<'a> ClusterChainReader<'a> { } } -impl<'a> Read for ClusterChainReader<'a> { +impl<'a, S: SliceLike> Read for ClusterChainReader<'a, S> { fn read(&mut self, buf: &mut [u8]) -> std::io::Result { if self.sub_slice.is_empty() { if !self.next_cluster() { diff --git a/fat-bits/src/lib.rs b/fat-bits/src/lib.rs index 0709cce..5591bd5 100644 --- a/fat-bits/src/lib.rs +++ b/fat-bits/src/lib.rs @@ -26,6 +26,14 @@ pub trait SliceLike { fn read_at_offset(&mut self, offset: u64, buf: &mut [u8]) -> std::io::Result<()>; fn write_at_offset(&mut self, offset: u64, bytes: &[u8]) -> std::io::Result<()>; + + fn read_array_at_offset(&mut self, offset: u64) -> std::io::Result<[u8; N]> { + let mut buf = [0; N]; + + self.read_at_offset(offset, &mut buf)?; + + Ok(buf) + } } impl SliceLike for &mut [u8] { @@ -79,8 +87,8 @@ impl SliceLike for std::fs::File { } #[allow(dead_code)] -pub struct FatFs { - inner: Rc>, +pub struct FatFs { + inner: Rc>, fat_offset: u64, fat_size: usize, @@ -98,18 +106,15 @@ pub struct FatFs { fat: fat::Fat, } -impl FatFs { - pub fn load(data: Rc>) -> anyhow::Result { - let mut bpb_bytes = [0; 512]; - - data.borrow_mut().read_at_offset(0, &mut bpb_bytes)?; +impl FatFs { + pub fn load(mut data: S) -> anyhow::Result> { + let bpb_bytes: [u8; 512] = data.read_array_at_offset(0)?; let bpb = bpb::Bpb::load(&bpb_bytes)?; let mut fat_buf = vec![0; bpb.fat_len_bytes()]; - data.borrow_mut() - .read_at_offset(bpb.fat_offset(), &mut fat_buf)?; + data.read_at_offset(bpb.fat_offset(), &mut fat_buf)?; let fat = fat::Fat::new(bpb.fat_type(), &fat_buf, bpb.count_of_clusters()); @@ -139,6 +144,8 @@ impl FatFs { let bytes_per_cluster = bpb.bytes_per_cluster(); + let data = Rc::new(RefCell::new(data)); + Ok(FatFs { inner: data, fat_offset, @@ -177,13 +184,13 @@ impl FatFs { self.fat().get_next_cluster(cluster) } - pub fn cluster_as_subslice_mut(&mut self, cluster: u32) -> SubSliceMut<'_> { + pub fn cluster_as_subslice_mut(&mut self, cluster: u32) -> SubSliceMut<'_, S> { let offset = self.data_cluster_to_offset(cluster); SubSliceMut::new(self, offset, self.bytes_per_cluster) } - pub fn cluster_as_subslice(&self, cluster: u32) -> SubSlice<'_> { + pub fn cluster_as_subslice(&self, cluster: u32) -> SubSlice<'_, S> { let offset = self.data_cluster_to_offset(cluster); SubSlice::new(self, offset, self.bytes_per_cluster) diff --git a/fat-bits/src/subslice.rs b/fat-bits/src/subslice.rs index a710974..b16a417 100644 --- a/fat-bits/src/subslice.rs +++ b/fat-bits/src/subslice.rs @@ -1,16 +1,16 @@ use std::fmt::Debug; use std::io::{Read, Write}; -use crate::FatFs; +use crate::{FatFs, SliceLike}; -pub struct SubSliceMut<'a> { - fat_fs: &'a mut FatFs, +pub struct SubSliceMut<'a, S: SliceLike> { + fat_fs: &'a mut FatFs, offset: u64, len: usize, } -impl Debug for SubSliceMut<'_> { +impl Debug for SubSliceMut<'_, S> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("SubSliceMut") .field("offset", &self.offset) @@ -19,8 +19,8 @@ impl Debug for SubSliceMut<'_> { } } -impl SubSliceMut<'_> { - pub fn new(fat_fs: &mut FatFs, offset: u64, len: usize) -> SubSliceMut<'_> { +impl SubSliceMut<'_, S> { + pub fn new(fat_fs: &mut FatFs, offset: u64, len: usize) -> SubSliceMut<'_, S> { SubSliceMut { fat_fs, offset, @@ -29,7 +29,7 @@ impl SubSliceMut<'_> { } } -impl SubSliceMut<'_> { +impl SubSliceMut<'_, S> { pub fn len(&self) -> usize { self.len } @@ -39,7 +39,7 @@ impl SubSliceMut<'_> { } } -impl Read for SubSliceMut<'_> { +impl Read for SubSliceMut<'_, S> { fn read(&mut self, buf: &mut [u8]) -> std::io::Result { let bytes_to_read = self.len.min(buf.len()); @@ -55,7 +55,7 @@ impl Read for SubSliceMut<'_> { } } -impl Write for SubSliceMut<'_> { +impl Write for SubSliceMut<'_, S> { fn write(&mut self, buf: &[u8]) -> std::io::Result { let bytes_to_write = self.len.min(buf.len()); @@ -75,14 +75,14 @@ impl Write for SubSliceMut<'_> { } } -pub struct SubSlice<'a> { - fat_fs: &'a FatFs, +pub struct SubSlice<'a, S: SliceLike> { + fat_fs: &'a FatFs, offset: u64, len: usize, } -impl Debug for SubSlice<'_> { +impl Debug for SubSlice<'_, S> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("SubSliceMut") .field("offset", &self.offset) @@ -91,8 +91,8 @@ impl Debug for SubSlice<'_> { } } -impl SubSlice<'_> { - pub fn new(fat_fs: &FatFs, offset: u64, len: usize) -> SubSlice<'_> { +impl SubSlice<'_, S> { + pub fn new(fat_fs: &FatFs, offset: u64, len: usize) -> SubSlice<'_, S> { SubSlice { fat_fs, offset, @@ -100,11 +100,11 @@ impl SubSlice<'_> { } } - pub fn fat_fs(&self) -> &FatFs { + pub fn fat_fs(&self) -> &FatFs { self.fat_fs } - pub fn fat_fs_mut(&self) -> &FatFs { + pub fn fat_fs_mut(&self) -> &FatFs { self.fat_fs } @@ -116,14 +116,14 @@ impl SubSlice<'_> { } } -impl<'a> SubSlice<'a> { +impl<'a, S: SliceLike> SubSlice<'a, S> { /// releases the inner &FatFs, consuming self in the process - pub fn release(self) -> &'a FatFs { + pub fn release(self) -> &'a FatFs { self.fat_fs } } -impl Read for SubSlice<'_> { +impl Read for SubSlice<'_, S> { fn read(&mut self, buf: &mut [u8]) -> std::io::Result { let bytes_to_read = self.len.min(buf.len()); diff --git a/fat-dump/src/main.rs b/fat-dump/src/main.rs index 3cb84eb..1407e9e 100644 --- a/fat-dump/src/main.rs +++ b/fat-dump/src/main.rs @@ -1,9 +1,6 @@ -use std::cell::RefCell; -use std::rc::Rc; - -use fat_bits::FatFs; -use fat_bits::dir::{DirEntry, DirIter}; +use fat_bits::dir::{DirIter, DirEntry}; use fat_bits::fat::Fatty as _; +use fat_bits::{FatFs, SliceLike}; pub fn main() -> anyhow::Result<()> { let args = std::env::args(); @@ -22,7 +19,7 @@ pub fn main() -> anyhow::Result<()> { // println!("{}", bpb); - let fat_fs = FatFs::load(Rc::new(RefCell::new(file)))?; + let fat_fs = FatFs::load(file)?; println!("{}", fat_fs.bpb()); println!(); @@ -44,15 +41,15 @@ pub fn main() -> anyhow::Result<()> { Ok(()) } -fn tree(fat_fs: &FatFs, show_hidden: bool) { +fn tree(fat_fs: &FatFs, show_hidden: bool) { fn do_indent(indent: u32) { for _ in 0..indent { print!(" "); } } - fn tree_impl( - fat_fs: &FatFs, + fn tree_impl( + fat_fs: &FatFs, iter: impl Iterator, show_hidden: bool, indent: u32, diff --git a/fat-fuse/Cargo.toml b/fat-fuse/Cargo.toml index 5e60917..f92e1df 100644 --- a/fat-fuse/Cargo.toml +++ b/fat-fuse/Cargo.toml @@ -5,7 +5,6 @@ edition = "2024" [dependencies] anyhow = "1.0.98" -chrono = { version = "0.4.41", default-features = false, features = ["alloc", "clock", "std"] } fat-bits = { version = "0.1.0", path = "../fat-bits" } fuser = "0.15.1" libc = "0.2.174" diff --git a/fat-fuse/src/inode.rs b/fat-fuse/src/inode.rs deleted file mode 100644 index 66307e5..0000000 --- a/fat-fuse/src/inode.rs +++ /dev/null @@ -1,107 +0,0 @@ -use std::alloc::System; -use std::time::SystemTime; - -use chrono::{NaiveDateTime, NaiveTime}; -use fat_bits::FatFs; -use fat_bits::dir::DirEntry; -use fuser::FileAttr; - -#[derive(Debug, Clone, Copy)] -pub enum Kind { - File, - Dir, -} - -impl From for fuser::FileType { - fn from(value: Kind) -> Self { - match value { - Kind::File => fuser::FileType::RegularFile, - Kind::Dir => fuser::FileType::Directory, - } - } -} - -#[derive(Debug)] -#[allow(dead_code)] -pub struct Inode { - ino: u64, - - size: u64, - // blocks: u64, - block_size: u32, - - kind: Kind, - - read_only: bool, - - atime: SystemTime, - mtime: SystemTime, - // ctime: SystemTime, - crtime: SystemTime, - - uid: u32, - gid: u32, - - first_cluster: u32, -} - -#[allow(dead_code)] -impl Inode { - pub fn new(fat_fs: &FatFs, dir_entry: DirEntry, uid: u32, gid: u32) -> Inode { - assert!(dir_entry.is_file() || dir_entry.is_dir()); - - let kind = if dir_entry.is_dir() { - Kind::Dir - } else { - Kind::File - }; - - let datetime_to_system = |datetime: NaiveDateTime| -> SystemTime { - datetime - .and_local_timezone(chrono::Local) - .single() - .map(|x| -> SystemTime { x.into() }) - .unwrap_or(SystemTime::UNIX_EPOCH) - }; - - let atime = datetime_to_system(dir_entry.last_access_date().and_time(NaiveTime::default())); - let mtime = datetime_to_system(dir_entry.write_time()); - let crtime = datetime_to_system(dir_entry.create_time()); - - Inode { - ino: dir_entry.first_cluster() as u64, - size: dir_entry.file_size() as u64, - block_size: fat_fs.bpb().bytes_per_sector() as u32, - kind, - read_only: dir_entry.is_readonly(), - atime, - mtime, - crtime, - uid, - gid, - first_cluster: dir_entry.first_cluster(), - } - } - - pub fn file_attr(&self) -> FileAttr { - let perm = if self.read_only { 0o555 } else { 0o777 }; - - FileAttr { - ino: self.ino, - size: self.size, - blocks: self.size / self.block_size as u64, - atime: self.atime, - mtime: self.mtime, - ctime: self.mtime, - crtime: self.crtime, - kind: self.kind.into(), - perm, - nlink: 1, - uid: self.uid, - gid: self.gid, - rdev: 0, - blksize: self.block_size, - flags: 0, - } - } -} diff --git a/fat-fuse/src/lib.rs b/fat-fuse/src/lib.rs index 83b2a34..fdaef8c 100644 --- a/fat-fuse/src/lib.rs +++ b/fat-fuse/src/lib.rs @@ -1,44 +1,52 @@ -mod inode; - -use std::cell::RefCell; -use std::collections::BTreeMap; use std::ffi::c_int; -use std::rc::Rc; +use fat_bits::dir::DirEntry; use fat_bits::{FatFs, SliceLike}; -use fuser::Filesystem; +use fuser::{FileAttr, Filesystem}; use libc::{ENOSYS, EPERM}; use log::{debug, warn}; -use crate::inode::Inode; +#[allow(dead_code)] +fn dir_entry_to_attr(dir_entry: &DirEntry, ino: u64) -> FileAttr { + FileAttr { + ino, + size: dir_entry.file_size() as u64, + blocks: todo!(), + atime: todo!(), + mtime: todo!(), + ctime: todo!(), + crtime: todo!(), + kind: todo!(), + perm: todo!(), + nlink: todo!(), + uid: todo!(), + gid: todo!(), + rdev: todo!(), + blksize: todo!(), + flags: todo!(), + } +} #[allow(dead_code)] -pub struct FatFuse { - fat_fs: FatFs, +pub struct FatFuse { + fat_fs: FatFs, uid: u32, gid: u32, - - inode_table: BTreeMap, } -impl FatFuse { - pub fn new(data: Rc>) -> anyhow::Result { +impl FatFuse { + pub fn new(data: S) -> anyhow::Result> { let uid = unsafe { libc::getuid() }; let gid = unsafe { libc::getgid() }; let fat_fs = FatFs::load(data)?; - Ok(FatFuse { - fat_fs, - uid, - gid, - inode_table: BTreeMap::new(), - }) + Ok(FatFuse { fat_fs, uid, gid }) } } -impl Filesystem for FatFuse { +impl Filesystem for FatFuse { fn init( &mut self, _req: &fuser::Request<'_>,