mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-11-21 21:49:15 +01:00
[SC64][SW] Add inital fuse support. ReadOnly and unix only.
This commit is contained in:
parent
e2c100ae7f
commit
517d75f65d
2
.gitignore
vendored
2
.gitignore
vendored
@ -5,3 +5,5 @@
|
|||||||
**/*.zip
|
**/*.zip
|
||||||
|
|
||||||
!**/.vscode/tasks.json
|
!**/.vscode/tasks.json
|
||||||
|
sw/deployer/.idea/
|
||||||
|
.idea/
|
||||||
|
90
sw/deployer/Cargo.lock
generated
90
sw/deployer/Cargo.lock
generated
@ -501,6 +501,33 @@ dependencies = [
|
|||||||
"spin",
|
"spin",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fuse_mt"
|
||||||
|
version = "0.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e098b8dc4cd32e9ba31d9c8cdfef11271d8191233c64c2a671432ff19d354948"
|
||||||
|
dependencies = [
|
||||||
|
"fuser",
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"threadpool",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fuser"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "21370f84640642c8ea36dfb2a6bfc4c55941f476fcf431f6fef25a5ddcf0169b"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"memchr",
|
||||||
|
"page_size",
|
||||||
|
"pkg-config",
|
||||||
|
"smallvec",
|
||||||
|
"zerocopy",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.15"
|
version = "0.2.15"
|
||||||
@ -559,6 +586,12 @@ version = "0.5.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hermit-abi"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hex"
|
name = "hex"
|
||||||
version = "0.4.3"
|
version = "0.4.3"
|
||||||
@ -745,9 +778,9 @@ checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.155"
|
version = "0.2.161"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
|
checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libflate"
|
name = "libflate"
|
||||||
@ -1010,6 +1043,16 @@ dependencies = [
|
|||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num_cpus"
|
||||||
|
version = "1.16.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.19.0"
|
version = "1.19.0"
|
||||||
@ -1026,6 +1069,16 @@ dependencies = [
|
|||||||
"hashbrown 0.12.3",
|
"hashbrown 0.12.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "page_size"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1b7663cbd190cfd818d08efa8497f6cd383076688c49a391ef7c0d03cd12b561"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "panic-message"
|
name = "panic-message"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
@ -1304,11 +1357,14 @@ dependencies = [
|
|||||||
"crc32fast",
|
"crc32fast",
|
||||||
"ctrlc",
|
"ctrlc",
|
||||||
"encoding_rs",
|
"encoding_rs",
|
||||||
|
"fuse_mt",
|
||||||
"hex",
|
"hex",
|
||||||
"image",
|
"image",
|
||||||
"include-flate",
|
"include-flate",
|
||||||
|
"libc",
|
||||||
"libftdi1-sys",
|
"libftdi1-sys",
|
||||||
"libusb1-sys",
|
"libusb1-sys",
|
||||||
|
"log",
|
||||||
"md5",
|
"md5",
|
||||||
"panic-message",
|
"panic-message",
|
||||||
"rand",
|
"rand",
|
||||||
@ -1485,6 +1541,15 @@ dependencies = [
|
|||||||
"syn 2.0.77",
|
"syn 2.0.77",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "threadpool"
|
||||||
|
version = "1.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa"
|
||||||
|
dependencies = [
|
||||||
|
"num_cpus",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tiff"
|
name = "tiff"
|
||||||
version = "0.9.1"
|
version = "0.9.1"
|
||||||
@ -1825,6 +1890,27 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy"
|
||||||
|
version = "0.6.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "854e949ac82d619ee9a14c66a1b674ac730422372ccb759ce0c39cabcf2bf8e6"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
"zerocopy-derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy-derive"
|
||||||
|
version = "0.6.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "125139de3f6b9d625c39e2efdd73d41bdac468ccd556556440e322be0e1bbd91"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.77",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zune-core"
|
name = "zune-core"
|
||||||
version = "0.4.12"
|
version = "0.4.12"
|
||||||
|
@ -30,6 +30,11 @@ rust-ini = "0.18.0"
|
|||||||
serial2 = "0.2.26"
|
serial2 = "0.2.26"
|
||||||
serialport = "4.4.0"
|
serialport = "4.4.0"
|
||||||
|
|
||||||
|
[target.'cfg(unix)'.dependencies]
|
||||||
|
fuse_mt = "0.6.1"
|
||||||
|
libc = "0.2.161"
|
||||||
|
log = "0.4.22"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
lto = true
|
||||||
strip = true
|
strip = true
|
||||||
|
@ -272,6 +272,14 @@ enum SDCommands {
|
|||||||
/// Format the SD card
|
/// Format the SD card
|
||||||
#[command(name = "mkfs")]
|
#[command(name = "mkfs")]
|
||||||
Format,
|
Format,
|
||||||
|
|
||||||
|
/// Mount the SD card
|
||||||
|
#[command(name = "fuse")]
|
||||||
|
#[cfg(unix)]
|
||||||
|
Fuse {
|
||||||
|
/// Path to the directory
|
||||||
|
mount_path: PathBuf,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Subcommand)]
|
#[derive(Subcommand)]
|
||||||
@ -990,6 +998,12 @@ fn handle_sd_command(connection: Connection, command: &SDCommands) -> Result<(),
|
|||||||
}
|
}
|
||||||
log_wait(format!("Formatting the SD card"), || ff.mkfs())?;
|
log_wait(format!("Formatting the SD card"), || ff.mkfs())?;
|
||||||
}
|
}
|
||||||
|
#[cfg(unix)]
|
||||||
|
SDCommands::Fuse { mount_path } => {
|
||||||
|
let fuse_args = [std::ffi::OsStr::new("-o"), std::ffi::OsStr::new("fsname=passthrufs,allow_other,auto_unmount")];
|
||||||
|
|
||||||
|
fuse_mt::mount(fuse_mt::FuseMT::new(ff, 1), mount_path, &fuse_args[..])?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1,5 +1,24 @@
|
|||||||
use super::{SdCardResult, SC64, SD_CARD_SECTOR_SIZE};
|
use super::{SdCardResult, SC64, SD_CARD_SECTOR_SIZE};
|
||||||
use chrono::{Datelike, Timelike};
|
use chrono::{Datelike, Timelike};
|
||||||
|
#[cfg(unix)]
|
||||||
|
use fuse_mt::{
|
||||||
|
CallbackResult, DirectoryEntry, FileAttr, FileType, FilesystemMT, RequestInfo,
|
||||||
|
ResultEmpty, ResultEntry, ResultOpen, ResultReaddir, ResultSlice, ResultStatfs, Statfs
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
use std::{
|
||||||
|
cell::RefCell,
|
||||||
|
collections::HashMap,
|
||||||
|
io::{Read, Seek, SeekFrom},
|
||||||
|
sync::{Arc, Mutex},
|
||||||
|
time::{Duration, SystemTime}
|
||||||
|
};
|
||||||
|
#[cfg(unix)]
|
||||||
|
use log::{debug, error};
|
||||||
|
#[cfg(unix)]
|
||||||
|
use chrono::{Utc};
|
||||||
|
|
||||||
mod fatfs {
|
mod fatfs {
|
||||||
#![allow(non_camel_case_types)]
|
#![allow(non_camel_case_types)]
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
@ -138,8 +157,104 @@ fn uninstall_driver() -> Result<(), Error> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
struct HandleMap<T> {
|
||||||
|
mutex: Mutex<u32>,
|
||||||
|
counter: RefCell<u64>,
|
||||||
|
map: RefCell<HashMap<u64, Arc<Mutex<T>>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
impl<T> HandleMap<T> {
|
||||||
|
pub fn new(start_counter: u64) -> Self {
|
||||||
|
HandleMap {
|
||||||
|
mutex: Mutex::new(0),
|
||||||
|
counter: RefCell::new(start_counter),
|
||||||
|
map: RefCell::new(HashMap::new()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert(&self, item: T) -> u64 {
|
||||||
|
let _lock = self.mutex.lock();
|
||||||
|
let mut counter = self.counter.borrow_mut();
|
||||||
|
*counter += 1;
|
||||||
|
self.map.borrow_mut().insert(*counter, Arc::new(Mutex::new(item)));
|
||||||
|
*counter
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self, handle: u64) -> Result<Arc<Mutex<T>>, libc::c_int> {
|
||||||
|
let _lock = self.mutex.lock();
|
||||||
|
let map = self.map.borrow();
|
||||||
|
map.get(&handle)
|
||||||
|
.map(|item| Arc::clone(item))
|
||||||
|
.ok_or(libc::EEXIST)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn release(&self, handle: u64) {
|
||||||
|
let _lock = self.mutex.lock();
|
||||||
|
self.map.borrow_mut().retain(|&k, _| k != handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
pub struct FatFsHelper {
|
||||||
|
dirs: HandleMap<Directory>,
|
||||||
|
files: HandleMap<File>,
|
||||||
|
stat_cache: StatCache<Entry>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
pub struct StatCache<T> {
|
||||||
|
mutex: Mutex<u64>,
|
||||||
|
cache: RefCell<HashMap<std::path::PathBuf, T>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
impl<T: Clone> StatCache<T> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
StatCache {
|
||||||
|
mutex: Mutex::new(0),
|
||||||
|
cache: RefCell::new(HashMap::new()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Inserts an entry into the cache, returning the previous entry if it existed.
|
||||||
|
pub fn insert(&self, path: &std::path::Path, entry: T) -> Option<T> {
|
||||||
|
let _lock = self.mutex.lock();
|
||||||
|
let mut cache = self.cache.borrow_mut();
|
||||||
|
cache.insert(path.to_path_buf(), entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Removes an entry from the cache, if it exists.
|
||||||
|
pub fn remove(&self, path: &std::path::PathBuf) {
|
||||||
|
let _lock = self.mutex.lock();
|
||||||
|
let mut cache = self.cache.borrow_mut();
|
||||||
|
cache.remove(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieves an entry from the cache, returning None if it doesn't exist.
|
||||||
|
pub fn get(&self, path: &std::path::Path) -> Option<T> {
|
||||||
|
let _lock = self.mutex.lock();
|
||||||
|
let cache = self.cache.borrow();
|
||||||
|
cache.get(path).cloned() // Clone the entry if it exists
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
impl FatFsHelper {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
FatFsHelper {
|
||||||
|
dirs: HandleMap::new(0),
|
||||||
|
files: HandleMap::new(u64::MAX / 2),
|
||||||
|
stat_cache: StatCache::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct FatFs {
|
pub struct FatFs {
|
||||||
fs: Box<fatfs::FATFS>,
|
fs: Box<fatfs::FATFS>,
|
||||||
|
#[cfg(unix)]
|
||||||
|
helper: FatFsHelper,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FatFs {
|
impl FatFs {
|
||||||
@ -147,6 +262,8 @@ impl FatFs {
|
|||||||
install_driver(driver)?;
|
install_driver(driver)?;
|
||||||
let mut ff = Self {
|
let mut ff = Self {
|
||||||
fs: Box::new(unsafe { std::mem::zeroed() }),
|
fs: Box::new(unsafe { std::mem::zeroed() }),
|
||||||
|
#[cfg(unix)]
|
||||||
|
helper: FatFsHelper::new(),
|
||||||
};
|
};
|
||||||
ff.mount(false)?;
|
ff.mount(false)?;
|
||||||
Ok(ff)
|
Ok(ff)
|
||||||
@ -167,7 +284,7 @@ impl FatFs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open<P: AsRef<std::path::Path>>(&mut self, path: P) -> Result<File, Error> {
|
pub fn open<P: AsRef<std::path::Path>>(&self, path: P) -> Result<File, Error> {
|
||||||
File::open(
|
File::open(
|
||||||
path,
|
path,
|
||||||
fatfs::FA_OPEN_EXISTING | fatfs::FA_READ | fatfs::FA_WRITE,
|
fatfs::FA_OPEN_EXISTING | fatfs::FA_READ | fatfs::FA_WRITE,
|
||||||
@ -181,7 +298,7 @@ impl FatFs {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stat<P: AsRef<std::path::Path>>(&mut self, path: P) -> Result<Entry, Error> {
|
pub fn stat<P: AsRef<std::path::Path>>(&self, path: P) -> Result<Entry, Error> {
|
||||||
let mut fno = unsafe { std::mem::zeroed() };
|
let mut fno = unsafe { std::mem::zeroed() };
|
||||||
match unsafe { fatfs::f_stat(fatfs::path(path)?.as_ptr(), &mut fno) } {
|
match unsafe { fatfs::f_stat(fatfs::path(path)?.as_ptr(), &mut fno) } {
|
||||||
fatfs::FRESULT_FR_OK => Ok(fno.into()),
|
fatfs::FRESULT_FR_OK => Ok(fno.into()),
|
||||||
@ -189,7 +306,7 @@ impl FatFs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn opendir<P: AsRef<std::path::Path>>(&mut self, path: P) -> Result<Directory, Error> {
|
pub fn opendir<P: AsRef<std::path::Path>>(&self, path: P) -> Result<Directory, Error> {
|
||||||
Directory::open(path)
|
Directory::open(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,6 +361,260 @@ impl FatFs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO, see https://github.com/wfraser/fuse-mt/issues/29
|
||||||
|
#[cfg(unix)]
|
||||||
|
unsafe impl Send for FatFs {}
|
||||||
|
#[cfg(unix)]
|
||||||
|
unsafe impl Sync for FatFs {}
|
||||||
|
#[cfg(unix)]
|
||||||
|
const TTL: Duration = Duration::from_secs(u64::MAX); // TTL can be high because currently it's RO anyway
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
fn stat_to_fuse(stat: &Entry) -> FileAttr {
|
||||||
|
let time = |secs: i64, nanos: i64|
|
||||||
|
SystemTime::UNIX_EPOCH + Duration::new(secs as u64, nanos as u32);
|
||||||
|
|
||||||
|
FileAttr {
|
||||||
|
size: match stat.info {
|
||||||
|
EntryInfo::Directory => { 0 }
|
||||||
|
EntryInfo::File { size } => { size }
|
||||||
|
},
|
||||||
|
blocks: match stat.info {
|
||||||
|
EntryInfo::Directory => { 0 }
|
||||||
|
EntryInfo::File { size } => { (size / 4096) + 1 } // https://github.com/wfraser/fuse-mt/blob/ee9d91d9003e5aa72877ca39b614ff7d84149f02/src/fusemt.rs#L49
|
||||||
|
},
|
||||||
|
atime: time(stat.datetime.and_utc().timestamp(), 0),
|
||||||
|
mtime: time(stat.datetime.and_utc().timestamp(), 0),
|
||||||
|
ctime: time(stat.datetime.and_utc().timestamp(), 0),
|
||||||
|
crtime: SystemTime::UNIX_EPOCH,
|
||||||
|
kind: match stat.info {
|
||||||
|
EntryInfo::Directory => { FileType::Directory }
|
||||||
|
EntryInfo::File { .. } => { FileType::RegularFile }
|
||||||
|
},
|
||||||
|
perm: 0o755, // TODO?
|
||||||
|
nlink: match stat.info {
|
||||||
|
EntryInfo::Directory => { 2 }
|
||||||
|
EntryInfo::File { .. } => { 1 }
|
||||||
|
},
|
||||||
|
// TODO ?!?!
|
||||||
|
uid: 501,
|
||||||
|
gid: 20,
|
||||||
|
rdev: 0,
|
||||||
|
flags: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
impl FilesystemMT for FatFs {
|
||||||
|
fn init(&self, _req: RequestInfo) -> ResultEmpty {
|
||||||
|
debug!("init");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn destroy(&self) {
|
||||||
|
debug!("destroy");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getattr(&self, _req: RequestInfo, path: &std::path::Path, _fh: Option<u64>) -> ResultEntry {
|
||||||
|
debug!("getattr: {:?}", path);
|
||||||
|
|
||||||
|
if let Some(entry) = self.helper.stat_cache.get(path) {
|
||||||
|
return Ok((TTL, stat_to_fuse(&entry)));
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("getattr: {:?}, no cache", path);
|
||||||
|
|
||||||
|
|
||||||
|
if path.as_os_str() == "/" {
|
||||||
|
let entry = Entry {
|
||||||
|
name: "name".to_string(),
|
||||||
|
datetime: Utc::now().naive_utc(),
|
||||||
|
info: EntryInfo::Directory,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.helper.stat_cache.insert(path, entry.clone());
|
||||||
|
return Ok((TTL, stat_to_fuse(&entry)));
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.stat(path) {
|
||||||
|
Ok(entry) => {
|
||||||
|
self.helper.stat_cache.insert(path, entry.clone());
|
||||||
|
Ok((TTL, stat_to_fuse(&entry)))
|
||||||
|
}
|
||||||
|
Err(e) => Err(e.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn open(&self, _req: RequestInfo, path: &std::path::Path, flags: u32) -> ResultOpen {
|
||||||
|
debug!("open: {:?} flags={:#x}", path, flags);
|
||||||
|
|
||||||
|
match FatFs::open(self, path) {
|
||||||
|
Ok(fh) => {
|
||||||
|
Ok((self.helper.files.insert(fh), 0))
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("open({:?}) failed: {}", path, libc::EEXIST);
|
||||||
|
Err(e.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read(&self, _req: RequestInfo, path: &std::path::Path, fh: u64, offset: u64, size: u32, callback: impl FnOnce(ResultSlice<'_>) -> CallbackResult) -> CallbackResult {
|
||||||
|
debug!("read attempt: {:?} {:#x} @ {:#x}", path, size, offset);
|
||||||
|
|
||||||
|
let file_arc = match self.helper.files.get(fh) {
|
||||||
|
Ok(dir) => { dir }
|
||||||
|
Err(_) => { return callback(Err(libc::EEXIST)); }
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut file = file_arc.lock().unwrap();
|
||||||
|
|
||||||
|
if let Err(e) = file.seek(SeekFrom::Start(offset)) {
|
||||||
|
error!("seek({:?}, {}) failed: {}", path, offset, e);
|
||||||
|
return callback(Err(e.raw_os_error().unwrap()));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut data = vec![0u8; size as usize];
|
||||||
|
match file.read(&mut data) {
|
||||||
|
Ok(read_size) => {
|
||||||
|
data.resize(read_size, 0);
|
||||||
|
callback(Ok(&data))
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
error!("read: {:?} {:#x} @ {:#x} failed.", path, size, offset);
|
||||||
|
callback(Err(libc::EFAULT))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn release(&self, _req: RequestInfo, path: &std::path::Path, fh: u64, _flags: u32, _lock_owner: u64, _flush: bool) -> ResultEmpty {
|
||||||
|
debug!("release: {:?}", path);
|
||||||
|
self.helper.files.release(fh);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn opendir(&self, _req: RequestInfo, path: &std::path::Path, _flags: u32) -> ResultOpen {
|
||||||
|
debug!("opendir: {:?} (flags = {:#o})", path, _flags);
|
||||||
|
|
||||||
|
match FatFs::opendir(self, path) {
|
||||||
|
Ok(fh) => {
|
||||||
|
Ok((self.helper.dirs.insert(fh), 0))
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
let new_e = e.into();
|
||||||
|
error!("opendir({:?}): failed {}", path, new_e);
|
||||||
|
Err(new_e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn readdir(&self, _req: RequestInfo, path: &std::path::Path, fh: u64) -> ResultReaddir {
|
||||||
|
debug!("readdir: {:?}", path);
|
||||||
|
let mut entries: Vec<DirectoryEntry> = vec![];
|
||||||
|
|
||||||
|
if fh == 0 {
|
||||||
|
error!("readdir: missing fh");
|
||||||
|
return Err(libc::EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
let dir_arc = match self.helper.dirs.get(fh) {
|
||||||
|
Ok(dir) => { dir }
|
||||||
|
Err(_) => { return Err(libc::EEXIST); }
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut dir = dir_arc.lock().unwrap();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match dir.read() {
|
||||||
|
Ok(Some(entry)) => {
|
||||||
|
let mut full_path = path.to_path_buf();
|
||||||
|
full_path.push(&entry.name);
|
||||||
|
|
||||||
|
if self.helper.stat_cache.get(full_path.as_path()).is_none() {
|
||||||
|
self.helper.stat_cache.insert(full_path.as_path(), entry.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
let name = entry.name;
|
||||||
|
|
||||||
|
let filetype = match entry.info {
|
||||||
|
EntryInfo::Directory => { FileType::Directory }
|
||||||
|
EntryInfo::File { .. } => { FileType::RegularFile }
|
||||||
|
};
|
||||||
|
|
||||||
|
entries.push(DirectoryEntry {
|
||||||
|
name: std::ffi::OsString::from(name),
|
||||||
|
kind: filetype,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Ok(None) => { break; }
|
||||||
|
Err(e) => {
|
||||||
|
let new_val = e.into();
|
||||||
|
error!("readdir failed: {:?}: {}", path, new_val);
|
||||||
|
return Err(new_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(entries)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn releasedir(&self, _req: RequestInfo, path: &std::path::Path, fh: u64, _flags: u32) -> ResultEmpty {
|
||||||
|
debug!("releasedir: {:?}", path);
|
||||||
|
self.helper.dirs.release(fh);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn statfs(&self, _req: RequestInfo, path: &std::path::Path) -> ResultStatfs {
|
||||||
|
debug!("statfs: {:?}", path);
|
||||||
|
// TODO which values to actually put here?
|
||||||
|
Ok(Statfs {
|
||||||
|
blocks: 10000,
|
||||||
|
bfree: 1000,
|
||||||
|
bavail: 1000,
|
||||||
|
files: 5000,
|
||||||
|
ffree: 5000,
|
||||||
|
bsize: 4096,
|
||||||
|
namelen: 255,
|
||||||
|
frsize: 4096,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
impl From<fatfs::Error> for libc::c_int {
|
||||||
|
fn from(value: fatfs::Error) -> Self {
|
||||||
|
// TODO almost all of these values are arbitrary set to EINVAL, correct mapping is needed
|
||||||
|
match value {
|
||||||
|
Error::DiskErr => { libc::EINVAL }
|
||||||
|
Error::IntErr => { libc::EINVAL }
|
||||||
|
Error::NotReady => { libc::EINVAL }
|
||||||
|
Error::NoFile => { libc::ENOENT }
|
||||||
|
Error::NoPath => { libc::ENOENT }
|
||||||
|
Error::InvalidName => { libc::ENOENT }
|
||||||
|
Error::Denied => { libc::EINVAL }
|
||||||
|
Error::Exist => { libc::EEXIST }
|
||||||
|
Error::InvalidObject => { libc::EFAULT }
|
||||||
|
Error::WriteProtected => { libc::EACCES }
|
||||||
|
Error::InvalidDrive => { libc::EINVAL }
|
||||||
|
Error::NotEnabled => { libc::EINVAL }
|
||||||
|
Error::NoFilesystem => { libc::EINVAL }
|
||||||
|
Error::MkfsAborted => { libc::EINVAL }
|
||||||
|
Error::Timeout => { libc::EINVAL }
|
||||||
|
Error::Locked => { libc::EINVAL }
|
||||||
|
Error::NotEnoughCore => { libc::EINVAL }
|
||||||
|
Error::TooManyOpenFiles => { libc::EINVAL }
|
||||||
|
Error::InvalidParameter => { libc::EINVAL }
|
||||||
|
Error::DriverInstalled => { libc::EINVAL }
|
||||||
|
Error::DriverNotInstalled => { libc::EINVAL }
|
||||||
|
Error::Unknown => { libc::EINVAL }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Drop for FatFs {
|
impl Drop for FatFs {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.unmount().ok();
|
self.unmount().ok();
|
||||||
@ -439,7 +810,7 @@ unsafe extern "C" fn get_fattime() -> fatfs::DWORD {
|
|||||||
| (second << 1)
|
| (second << 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone)]
|
||||||
pub struct Entry {
|
pub struct Entry {
|
||||||
pub info: EntryInfo,
|
pub info: EntryInfo,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@ -521,6 +892,7 @@ impl From<fatfs::FILINFO> for Entry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct Directory {
|
pub struct Directory {
|
||||||
dir: fatfs::DIR,
|
dir: fatfs::DIR,
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user