mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-11-24 22:56:52 +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
|
||||
|
||||
!**/.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",
|
||||
]
|
||||
|
||||
[[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]]
|
||||
name = "getrandom"
|
||||
version = "0.2.15"
|
||||
@ -559,6 +586,12 @@ version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.4.3"
|
||||
@ -745,9 +778,9 @@ checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.155"
|
||||
version = "0.2.161"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
|
||||
checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1"
|
||||
|
||||
[[package]]
|
||||
name = "libflate"
|
||||
@ -1010,6 +1043,16 @@ dependencies = [
|
||||
"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]]
|
||||
name = "once_cell"
|
||||
version = "1.19.0"
|
||||
@ -1026,6 +1069,16 @@ dependencies = [
|
||||
"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]]
|
||||
name = "panic-message"
|
||||
version = "0.3.0"
|
||||
@ -1304,11 +1357,14 @@ dependencies = [
|
||||
"crc32fast",
|
||||
"ctrlc",
|
||||
"encoding_rs",
|
||||
"fuse_mt",
|
||||
"hex",
|
||||
"image",
|
||||
"include-flate",
|
||||
"libc",
|
||||
"libftdi1-sys",
|
||||
"libusb1-sys",
|
||||
"log",
|
||||
"md5",
|
||||
"panic-message",
|
||||
"rand",
|
||||
@ -1485,6 +1541,15 @@ dependencies = [
|
||||
"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]]
|
||||
name = "tiff"
|
||||
version = "0.9.1"
|
||||
@ -1825,6 +1890,27 @@ dependencies = [
|
||||
"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]]
|
||||
name = "zune-core"
|
||||
version = "0.4.12"
|
||||
|
@ -30,6 +30,11 @@ rust-ini = "0.18.0"
|
||||
serial2 = "0.2.26"
|
||||
serialport = "4.4.0"
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
fuse_mt = "0.6.1"
|
||||
libc = "0.2.161"
|
||||
log = "0.4.22"
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
strip = true
|
||||
|
@ -272,6 +272,14 @@ enum SDCommands {
|
||||
/// Format the SD card
|
||||
#[command(name = "mkfs")]
|
||||
Format,
|
||||
|
||||
/// Mount the SD card
|
||||
#[command(name = "fuse")]
|
||||
#[cfg(unix)]
|
||||
Fuse {
|
||||
/// Path to the directory
|
||||
mount_path: PathBuf,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
@ -990,6 +998,12 @@ fn handle_sd_command(connection: Connection, command: &SDCommands) -> Result<(),
|
||||
}
|
||||
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(())
|
||||
|
@ -1,5 +1,24 @@
|
||||
use super::{SdCardResult, SC64, SD_CARD_SECTOR_SIZE};
|
||||
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 {
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(non_snake_case)]
|
||||
@ -138,8 +157,104 @@ fn uninstall_driver() -> Result<(), Error> {
|
||||
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 {
|
||||
fs: Box<fatfs::FATFS>,
|
||||
#[cfg(unix)]
|
||||
helper: FatFsHelper,
|
||||
}
|
||||
|
||||
impl FatFs {
|
||||
@ -147,6 +262,8 @@ impl FatFs {
|
||||
install_driver(driver)?;
|
||||
let mut ff = Self {
|
||||
fs: Box::new(unsafe { std::mem::zeroed() }),
|
||||
#[cfg(unix)]
|
||||
helper: FatFsHelper::new(),
|
||||
};
|
||||
ff.mount(false)?;
|
||||
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(
|
||||
path,
|
||||
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() };
|
||||
match unsafe { fatfs::f_stat(fatfs::path(path)?.as_ptr(), &mut fno) } {
|
||||
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)
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
fn drop(&mut self) {
|
||||
self.unmount().ok();
|
||||
@ -439,7 +810,7 @@ unsafe extern "C" fn get_fattime() -> fatfs::DWORD {
|
||||
| (second << 1)
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone)]
|
||||
pub struct Entry {
|
||||
pub info: EntryInfo,
|
||||
pub name: String,
|
||||
@ -521,6 +892,7 @@ impl From<fatfs::FILINFO> for Entry {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Directory {
|
||||
dir: fatfs::DIR,
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user