Compare commits
3 commits
619ba155c9
...
7921064ae2
| Author | SHA1 | Date | |
|---|---|---|---|
| 7921064ae2 | |||
| 372aa34022 | |||
| 3c977d2d42 |
8 changed files with 781 additions and 577 deletions
55
Cargo.lock
generated
55
Cargo.lock
generated
|
|
@ -122,6 +122,7 @@ dependencies = [
|
||||||
"fuser",
|
"fuser",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
|
"rand",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -141,6 +142,18 @@ dependencies = [
|
||||||
"zerocopy",
|
"zerocopy",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"r-efi",
|
||||||
|
"wasi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iana-time-zone"
|
name = "iana-time-zone"
|
||||||
version = "0.1.63"
|
version = "0.1.63"
|
||||||
|
|
@ -254,6 +267,30 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "r-efi"
|
||||||
|
version = "5.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.9.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.9.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustversion"
|
name = "rustversion"
|
||||||
version = "1.0.21"
|
version = "1.0.21"
|
||||||
|
|
@ -315,6 +352,15 @@ version = "1.0.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.14.2+wasi-0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
|
||||||
|
dependencies = [
|
||||||
|
"wit-bindgen-rt",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen"
|
name = "wasm-bindgen"
|
||||||
version = "0.2.100"
|
version = "0.2.100"
|
||||||
|
|
@ -454,6 +500,15 @@ dependencies = [
|
||||||
"windows-link",
|
"windows-link",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wit-bindgen-rt"
|
||||||
|
version = "0.39.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy"
|
name = "zerocopy"
|
||||||
version = "0.8.26"
|
version = "0.8.26"
|
||||||
|
|
|
||||||
|
|
@ -64,24 +64,30 @@ pub struct DirEntry {
|
||||||
|
|
||||||
file_size: u32,
|
file_size: u32,
|
||||||
|
|
||||||
|
// buffer for holding short name str representation
|
||||||
|
// initial dot if hidden (1)
|
||||||
|
// stem (8)
|
||||||
|
// dot (1)
|
||||||
|
// extension (3)
|
||||||
|
short_name: [u8; 13],
|
||||||
long_name: Option<String>,
|
long_name: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for DirEntry {
|
impl Display for DirEntry {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
let mut name = self.name_string().unwrap_or_else(|| "<unknown>".to_owned());
|
let name = self.name_str().unwrap_or("<unknown>");
|
||||||
|
|
||||||
if self.attr.contains(Attr::Directory) {
|
// add slash to end of dir_names
|
||||||
name.push('/');
|
let dir_slash = if self.is_dir() { "/" } else { " " };
|
||||||
}
|
|
||||||
|
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{} {}",
|
"{} {}{}",
|
||||||
self.attr,
|
self.attr,
|
||||||
// self.create_time().format("%a %b %d %H:%M:%S%.3f %Y"),
|
// self.create_time().format("%a %b %d %H:%M:%S%.3f %Y"),
|
||||||
// self.write_time().format("%a %b %d %H:%M:%S%.3f %Y"),
|
// self.write_time().format("%a %b %d %H:%M:%S%.3f %Y"),
|
||||||
name,
|
name,
|
||||||
|
dir_slash,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -92,7 +98,7 @@ impl DirEntry {
|
||||||
pub fn load(bytes: &[u8]) -> anyhow::Result<DirEntry> {
|
pub fn load(bytes: &[u8]) -> anyhow::Result<DirEntry> {
|
||||||
assert_eq!(bytes.len(), 32);
|
assert_eq!(bytes.len(), 32);
|
||||||
|
|
||||||
let name = bytes[..11].try_into().unwrap();
|
let name: [u8; 11] = bytes[..11].try_into().unwrap();
|
||||||
let attr = Attr::from_bits_truncate(bytes[11]);
|
let attr = Attr::from_bits_truncate(bytes[11]);
|
||||||
|
|
||||||
let create_time_tenths = bytes[13];
|
let create_time_tenths = bytes[13];
|
||||||
|
|
@ -130,6 +136,32 @@ impl DirEntry {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut short_name = [0; 13];
|
||||||
|
|
||||||
|
let mut short_name_iter = short_name.iter_mut();
|
||||||
|
|
||||||
|
if attr.contains(Attr::Hidden) {
|
||||||
|
// if hidden: lead with '.'
|
||||||
|
*short_name_iter.next().unwrap() = b'.';
|
||||||
|
}
|
||||||
|
|
||||||
|
if name[0] != 0 && name[0] != 0xe5 {
|
||||||
|
// dir_entry is not free
|
||||||
|
|
||||||
|
for c in name[..8].iter().filter(|&x| x != &0x20) {
|
||||||
|
*short_name_iter.next().unwrap() = *c;
|
||||||
|
}
|
||||||
|
|
||||||
|
if &name[8..] != &[0x20, 0x20, 0x20] {
|
||||||
|
// if extension is not empty: add dot and extension
|
||||||
|
*short_name_iter.next().unwrap() = b'.';
|
||||||
|
|
||||||
|
for c in name[8..].iter().filter(|&x| x != &0x20) {
|
||||||
|
*short_name_iter.next().unwrap() = *c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(DirEntry {
|
Ok(DirEntry {
|
||||||
name,
|
name,
|
||||||
attr,
|
attr,
|
||||||
|
|
@ -141,6 +173,7 @@ impl DirEntry {
|
||||||
write_time,
|
write_time,
|
||||||
write_date,
|
write_date,
|
||||||
file_size,
|
file_size,
|
||||||
|
short_name,
|
||||||
long_name: None,
|
long_name: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -216,29 +249,19 @@ impl DirEntry {
|
||||||
std::str::from_utf8(self.extension()).ok()
|
std::str::from_utf8(self.extension()).ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name_string(&self) -> Option<String> {
|
fn short_name(&self) -> &[u8] {
|
||||||
if let Some(long_filename) = self.long_name() {
|
&self.short_name
|
||||||
return Some(long_filename.to_owned());
|
}
|
||||||
|
|
||||||
|
fn short_name_str(&self) -> Option<&str> {
|
||||||
|
let mut short_name = self.short_name();
|
||||||
|
|
||||||
|
// remove trailing zeros
|
||||||
|
while short_name.last() == Some(&0) {
|
||||||
|
short_name = &short_name[..short_name.len() - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = std::str::from_utf8(&self.name[..8]).ok()?.trim_ascii_end();
|
std::str::from_utf8(short_name).ok()
|
||||||
let ext = std::str::from_utf8(&self.name[8..]).ok()?.trim_ascii_end();
|
|
||||||
|
|
||||||
let mut s = String::new();
|
|
||||||
|
|
||||||
if self.attr.contains(Attr::Hidden) {
|
|
||||||
s.push('.');
|
|
||||||
}
|
|
||||||
|
|
||||||
s += name;
|
|
||||||
|
|
||||||
if !ext.is_empty() {
|
|
||||||
s.push('.');
|
|
||||||
|
|
||||||
s += ext;
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(s)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn long_name(&self) -> Option<&str> {
|
pub fn long_name(&self) -> Option<&str> {
|
||||||
|
|
@ -249,6 +272,33 @@ impl DirEntry {
|
||||||
self.long_name = Some(long_name);
|
self.long_name = Some(long_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn name_str(&self) -> Option<&str> {
|
||||||
|
if let Some(long_filename) = self.long_name() {
|
||||||
|
return Some(long_filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.short_name_str()
|
||||||
|
|
||||||
|
// let name = std::str::from_utf8(&self.name[..8]).ok()?.trim_ascii_end();
|
||||||
|
// let ext = std::str::from_utf8(&self.name[8..]).ok()?.trim_ascii_end();
|
||||||
|
|
||||||
|
// let mut s = String::new();
|
||||||
|
|
||||||
|
// if self.attr.contains(Attr::Hidden) {
|
||||||
|
// s.push('.');
|
||||||
|
// }
|
||||||
|
|
||||||
|
// s += name;
|
||||||
|
|
||||||
|
// if !ext.is_empty() {
|
||||||
|
// s.push('.');
|
||||||
|
|
||||||
|
// s += ext;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Some(s)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn attr(&self) -> Attr {
|
pub fn attr(&self) -> Attr {
|
||||||
self.attr
|
self.attr
|
||||||
}
|
}
|
||||||
|
|
@ -540,7 +590,7 @@ impl<R: Read> DirIter<R> {
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
anyhow::anyhow!(
|
anyhow::anyhow!(
|
||||||
"failed to get long filename for {}: {}",
|
"failed to get long filename for {}: {}",
|
||||||
dir_entry.name_string().as_deref().unwrap_or("<invalid>"),
|
dir_entry.name_str().as_deref().unwrap_or("<invalid>"),
|
||||||
e
|
e
|
||||||
)
|
)
|
||||||
})? {
|
})? {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use std::cell::RefCell;
|
||||||
use std::io::{Read, Seek, SeekFrom, Write};
|
use std::io::{Read, Seek, SeekFrom, Write};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::dir::{DirEntry, DirIter};
|
use crate::dir::DirIter;
|
||||||
use crate::fat::{FatError, Fatty};
|
use crate::fat::{FatError, Fatty};
|
||||||
use crate::subslice::{SubSlice, SubSliceMut};
|
use crate::subslice::{SubSlice, SubSliceMut};
|
||||||
|
|
||||||
|
|
@ -217,7 +217,12 @@ impl FatFs {
|
||||||
Ok(data)
|
Ok(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn root_dir_iter(&self) -> Box<dyn Iterator<Item = DirEntry> + '_> {
|
fn chain_reader(&self, first_cluster: u32) -> impl Read {
|
||||||
|
iter::ClusterChainReader::new(self, first_cluster)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn root_dir_iter<'a>(&'a self) -> DirIter<Box<dyn Read + 'a>> {
|
||||||
|
// Box<dyn Iterator<Item = DirEntry> + '_>
|
||||||
// TODO: maybe wrap this in another RootDirIter enum, so we don't have to Box<dyn>
|
// TODO: maybe wrap this in another RootDirIter enum, so we don't have to Box<dyn>
|
||||||
|
|
||||||
if let Some(root_dir_offset) = self.root_dir_offset {
|
if let Some(root_dir_offset) = self.root_dir_offset {
|
||||||
|
|
@ -225,7 +230,7 @@ impl FatFs {
|
||||||
|
|
||||||
let sub_slice = SubSlice::new(self, root_dir_offset, self.root_dir_size);
|
let sub_slice = SubSlice::new(self, root_dir_offset, self.root_dir_size);
|
||||||
|
|
||||||
return Box::new(DirIter::new(sub_slice));
|
return DirIter::new(Box::new(sub_slice));
|
||||||
}
|
}
|
||||||
|
|
||||||
// FAT32
|
// FAT32
|
||||||
|
|
@ -235,10 +240,15 @@ impl FatFs {
|
||||||
|
|
||||||
let cluster_iter = iter::ClusterChainReader::new(self, root_cluster);
|
let cluster_iter = iter::ClusterChainReader::new(self, root_cluster);
|
||||||
|
|
||||||
Box::new(DirIter::new(cluster_iter))
|
DirIter::new(Box::new(cluster_iter))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn chain_reader(&self, first_cluster: u32) -> impl Read {
|
pub fn dir_iter<'a>(&'a self, first_cluster: u32) -> DirIter<Box<dyn Read + 'a>> {
|
||||||
iter::ClusterChainReader::new(self, first_cluster)
|
// TODO: return type must match root_dir_iter
|
||||||
|
// if the Box<dyn> is changed there, update here as well
|
||||||
|
|
||||||
|
let cluster_iter = self.chain_reader(first_cluster);
|
||||||
|
|
||||||
|
DirIter::new(Box::new(cluster_iter))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -68,9 +68,7 @@ fn tree(fat_fs: &FatFs, show_hidden: bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if dir_entry.is_dir() {
|
if dir_entry.is_dir() {
|
||||||
let reader = fat_fs.chain_reader(dir_entry.first_cluster());
|
let iter = fat_fs.dir_iter(dir_entry.first_cluster());
|
||||||
|
|
||||||
let iter = DirIter::new(reader);
|
|
||||||
|
|
||||||
tree_impl(fat_fs, iter, show_hidden, indent + 1);
|
tree_impl(fat_fs, iter, show_hidden, indent + 1);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,4 +10,5 @@ fat-bits = { version = "0.1.0", path = "../fat-bits" }
|
||||||
fuser = "0.15.1"
|
fuser = "0.15.1"
|
||||||
libc = "0.2.174"
|
libc = "0.2.174"
|
||||||
log = "0.4.27"
|
log = "0.4.27"
|
||||||
|
rand = { version = "0.9.2", default-features = false, features = ["os_rng", "small_rng"] }
|
||||||
thiserror = "2.0.12"
|
thiserror = "2.0.12"
|
||||||
|
|
|
||||||
572
fat-fuse/src/fuse.rs
Normal file
572
fat-fuse/src/fuse.rs
Normal file
|
|
@ -0,0 +1,572 @@
|
||||||
|
use std::ffi::c_int;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use fuser::Filesystem;
|
||||||
|
use libc::{EIO, ENOENT, ENOSYS, ENOTDIR, EPERM};
|
||||||
|
use log::{debug, warn};
|
||||||
|
|
||||||
|
use crate::FatFuse;
|
||||||
|
|
||||||
|
impl Filesystem for FatFuse {
|
||||||
|
fn init(
|
||||||
|
&mut self,
|
||||||
|
_req: &fuser::Request<'_>,
|
||||||
|
_config: &mut fuser::KernelConfig,
|
||||||
|
) -> Result<(), c_int> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn destroy(&mut self) {}
|
||||||
|
|
||||||
|
fn lookup(
|
||||||
|
&mut self,
|
||||||
|
_req: &fuser::Request<'_>,
|
||||||
|
parent: u64,
|
||||||
|
name: &std::ffi::OsStr,
|
||||||
|
reply: fuser::ReplyEntry,
|
||||||
|
) {
|
||||||
|
// warn!("[Not Implemented] lookup(parent: {:#x?}, name {:?})", parent, name);
|
||||||
|
// reply.error(ENOSYS);
|
||||||
|
|
||||||
|
let parent_inode = if let Some(inode) = self.get_inode(parent) {
|
||||||
|
inode
|
||||||
|
} else {
|
||||||
|
// parent inode does not exist
|
||||||
|
// TODO: how can we make sure this does not exist?
|
||||||
|
// panic?
|
||||||
|
reply.error(EIO);
|
||||||
|
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let Ok(dir_iter) = parent_inode.dir_iter(&self.fat_fs) else {
|
||||||
|
reply.error(ENOTDIR);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(dir_entry) =
|
||||||
|
dir_iter.find(|dir_entry| dir_entry.name_str().as_deref() == Some(""))
|
||||||
|
else {
|
||||||
|
reply.error(ENOENT);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
reply.entry(&Duration::from_secs(1), attr, generation);
|
||||||
|
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn forget(&mut self, _req: &fuser::Request<'_>, _ino: u64, _nlookup: u64) {}
|
||||||
|
|
||||||
|
fn getattr(
|
||||||
|
&mut self,
|
||||||
|
_req: &fuser::Request<'_>,
|
||||||
|
ino: u64,
|
||||||
|
fh: Option<u64>,
|
||||||
|
reply: fuser::ReplyAttr,
|
||||||
|
) {
|
||||||
|
warn!("[Not Implemented] getattr(ino: {:#x?}, fh: {:#x?})", ino, fh);
|
||||||
|
reply.error(ENOSYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setattr(
|
||||||
|
&mut self,
|
||||||
|
_req: &fuser::Request<'_>,
|
||||||
|
ino: u64,
|
||||||
|
mode: Option<u32>,
|
||||||
|
uid: Option<u32>,
|
||||||
|
gid: Option<u32>,
|
||||||
|
size: Option<u64>,
|
||||||
|
_atime: Option<fuser::TimeOrNow>,
|
||||||
|
_mtime: Option<fuser::TimeOrNow>,
|
||||||
|
_ctime: Option<std::time::SystemTime>,
|
||||||
|
fh: Option<u64>,
|
||||||
|
_crtime: Option<std::time::SystemTime>,
|
||||||
|
_chgtime: Option<std::time::SystemTime>,
|
||||||
|
_bkuptime: Option<std::time::SystemTime>,
|
||||||
|
flags: Option<u32>,
|
||||||
|
reply: fuser::ReplyAttr,
|
||||||
|
) {
|
||||||
|
debug!(
|
||||||
|
"[Not Implemented] setattr(ino: {:#x?}, mode: {:?}, uid: {:?}, \
|
||||||
|
gid: {:?}, size: {:?}, fh: {:?}, flags: {:?})",
|
||||||
|
ino, mode, uid, gid, size, fh, flags
|
||||||
|
);
|
||||||
|
reply.error(ENOSYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn readlink(&mut self, _req: &fuser::Request<'_>, ino: u64, reply: fuser::ReplyData) {
|
||||||
|
debug!("[Not Implemented] readlink(ino: {:#x?})", ino);
|
||||||
|
reply.error(ENOSYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mknod(
|
||||||
|
&mut self,
|
||||||
|
_req: &fuser::Request<'_>,
|
||||||
|
parent: u64,
|
||||||
|
name: &std::ffi::OsStr,
|
||||||
|
mode: u32,
|
||||||
|
umask: u32,
|
||||||
|
rdev: u32,
|
||||||
|
reply: fuser::ReplyEntry,
|
||||||
|
) {
|
||||||
|
debug!(
|
||||||
|
"[Not Implemented] mknod(parent: {:#x?}, name: {:?}, mode: {}, \
|
||||||
|
umask: {:#x?}, rdev: {})",
|
||||||
|
parent, name, mode, umask, rdev
|
||||||
|
);
|
||||||
|
reply.error(ENOSYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mkdir(
|
||||||
|
&mut self,
|
||||||
|
_req: &fuser::Request<'_>,
|
||||||
|
parent: u64,
|
||||||
|
name: &std::ffi::OsStr,
|
||||||
|
mode: u32,
|
||||||
|
umask: u32,
|
||||||
|
reply: fuser::ReplyEntry,
|
||||||
|
) {
|
||||||
|
debug!(
|
||||||
|
"[Not Implemented] mkdir(parent: {:#x?}, name: {:?}, mode: {}, umask: {:#x?})",
|
||||||
|
parent, name, mode, umask
|
||||||
|
);
|
||||||
|
reply.error(ENOSYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unlink(
|
||||||
|
&mut self,
|
||||||
|
_req: &fuser::Request<'_>,
|
||||||
|
parent: u64,
|
||||||
|
name: &std::ffi::OsStr,
|
||||||
|
reply: fuser::ReplyEmpty,
|
||||||
|
) {
|
||||||
|
debug!("[Not Implemented] unlink(parent: {:#x?}, name: {:?})", parent, name,);
|
||||||
|
reply.error(ENOSYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rmdir(
|
||||||
|
&mut self,
|
||||||
|
_req: &fuser::Request<'_>,
|
||||||
|
parent: u64,
|
||||||
|
name: &std::ffi::OsStr,
|
||||||
|
reply: fuser::ReplyEmpty,
|
||||||
|
) {
|
||||||
|
debug!("[Not Implemented] rmdir(parent: {:#x?}, name: {:?})", parent, name,);
|
||||||
|
reply.error(ENOSYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn symlink(
|
||||||
|
&mut self,
|
||||||
|
_req: &fuser::Request<'_>,
|
||||||
|
parent: u64,
|
||||||
|
link_name: &std::ffi::OsStr,
|
||||||
|
target: &std::path::Path,
|
||||||
|
reply: fuser::ReplyEntry,
|
||||||
|
) {
|
||||||
|
debug!(
|
||||||
|
"[Not Implemented] symlink(parent: {:#x?}, link_name: {:?}, target: {:?})",
|
||||||
|
parent, link_name, target,
|
||||||
|
);
|
||||||
|
reply.error(EPERM);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rename(
|
||||||
|
&mut self,
|
||||||
|
_req: &fuser::Request<'_>,
|
||||||
|
parent: u64,
|
||||||
|
name: &std::ffi::OsStr,
|
||||||
|
newparent: u64,
|
||||||
|
newname: &std::ffi::OsStr,
|
||||||
|
flags: u32,
|
||||||
|
reply: fuser::ReplyEmpty,
|
||||||
|
) {
|
||||||
|
debug!(
|
||||||
|
"[Not Implemented] rename(parent: {:#x?}, name: {:?}, newparent: {:#x?}, \
|
||||||
|
newname: {:?}, flags: {})",
|
||||||
|
parent, name, newparent, newname, flags,
|
||||||
|
);
|
||||||
|
reply.error(ENOSYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn link(
|
||||||
|
&mut self,
|
||||||
|
_req: &fuser::Request<'_>,
|
||||||
|
ino: u64,
|
||||||
|
newparent: u64,
|
||||||
|
newname: &std::ffi::OsStr,
|
||||||
|
reply: fuser::ReplyEntry,
|
||||||
|
) {
|
||||||
|
debug!(
|
||||||
|
"[Not Implemented] link(ino: {:#x?}, newparent: {:#x?}, newname: {:?})",
|
||||||
|
ino, newparent, newname
|
||||||
|
);
|
||||||
|
reply.error(EPERM);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn open(&mut self, _req: &fuser::Request<'_>, _ino: u64, _flags: i32, reply: fuser::ReplyOpen) {
|
||||||
|
reply.opened(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read(
|
||||||
|
&mut self,
|
||||||
|
_req: &fuser::Request<'_>,
|
||||||
|
ino: u64,
|
||||||
|
fh: u64,
|
||||||
|
offset: i64,
|
||||||
|
size: u32,
|
||||||
|
flags: i32,
|
||||||
|
lock_owner: Option<u64>,
|
||||||
|
reply: fuser::ReplyData,
|
||||||
|
) {
|
||||||
|
warn!(
|
||||||
|
"[Not Implemented] read(ino: {:#x?}, fh: {}, offset: {}, size: {}, \
|
||||||
|
flags: {:#x?}, lock_owner: {:?})",
|
||||||
|
ino, fh, offset, size, flags, lock_owner
|
||||||
|
);
|
||||||
|
reply.error(ENOSYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(
|
||||||
|
&mut self,
|
||||||
|
_req: &fuser::Request<'_>,
|
||||||
|
ino: u64,
|
||||||
|
fh: u64,
|
||||||
|
offset: i64,
|
||||||
|
data: &[u8],
|
||||||
|
write_flags: u32,
|
||||||
|
flags: i32,
|
||||||
|
lock_owner: Option<u64>,
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(
|
||||||
|
&mut self,
|
||||||
|
_req: &fuser::Request<'_>,
|
||||||
|
ino: u64,
|
||||||
|
fh: u64,
|
||||||
|
lock_owner: u64,
|
||||||
|
reply: fuser::ReplyEmpty,
|
||||||
|
) {
|
||||||
|
debug!(
|
||||||
|
"[Not Implemented] flush(ino: {:#x?}, fh: {}, lock_owner: {:?})",
|
||||||
|
ino, fh, lock_owner
|
||||||
|
);
|
||||||
|
reply.error(ENOSYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn release(
|
||||||
|
&mut self,
|
||||||
|
_req: &fuser::Request<'_>,
|
||||||
|
_ino: u64,
|
||||||
|
_fh: u64,
|
||||||
|
_flags: i32,
|
||||||
|
_lock_owner: Option<u64>,
|
||||||
|
_flush: bool,
|
||||||
|
reply: fuser::ReplyEmpty,
|
||||||
|
) {
|
||||||
|
reply.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fsync(
|
||||||
|
&mut self,
|
||||||
|
_req: &fuser::Request<'_>,
|
||||||
|
ino: u64,
|
||||||
|
fh: u64,
|
||||||
|
datasync: bool,
|
||||||
|
reply: fuser::ReplyEmpty,
|
||||||
|
) {
|
||||||
|
debug!("[Not Implemented] fsync(ino: {:#x?}, fh: {}, datasync: {})", ino, fh, datasync);
|
||||||
|
reply.error(ENOSYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn opendir(
|
||||||
|
&mut self,
|
||||||
|
_req: &fuser::Request<'_>,
|
||||||
|
_ino: u64,
|
||||||
|
_flags: i32,
|
||||||
|
reply: fuser::ReplyOpen,
|
||||||
|
) {
|
||||||
|
reply.opened(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn readdir(
|
||||||
|
&mut self,
|
||||||
|
_req: &fuser::Request<'_>,
|
||||||
|
ino: u64,
|
||||||
|
fh: u64,
|
||||||
|
offset: i64,
|
||||||
|
reply: fuser::ReplyDirectory,
|
||||||
|
) {
|
||||||
|
warn!("[Not Implemented] readdir(ino: {:#x?}, fh: {}, offset: {})", ino, fh, offset);
|
||||||
|
reply.error(ENOSYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn readdirplus(
|
||||||
|
&mut self,
|
||||||
|
_req: &fuser::Request<'_>,
|
||||||
|
ino: u64,
|
||||||
|
fh: u64,
|
||||||
|
offset: i64,
|
||||||
|
reply: fuser::ReplyDirectoryPlus,
|
||||||
|
) {
|
||||||
|
debug!(
|
||||||
|
"[Not Implemented] readdirplus(ino: {:#x?}, fh: {}, offset: {})",
|
||||||
|
ino, fh, offset
|
||||||
|
);
|
||||||
|
reply.error(ENOSYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn releasedir(
|
||||||
|
&mut self,
|
||||||
|
_req: &fuser::Request<'_>,
|
||||||
|
_ino: u64,
|
||||||
|
_fh: u64,
|
||||||
|
_flags: i32,
|
||||||
|
reply: fuser::ReplyEmpty,
|
||||||
|
) {
|
||||||
|
reply.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fsyncdir(
|
||||||
|
&mut self,
|
||||||
|
_req: &fuser::Request<'_>,
|
||||||
|
ino: u64,
|
||||||
|
fh: u64,
|
||||||
|
datasync: bool,
|
||||||
|
reply: fuser::ReplyEmpty,
|
||||||
|
) {
|
||||||
|
debug!(
|
||||||
|
"[Not Implemented] fsyncdir(ino: {:#x?}, fh: {}, datasync: {})",
|
||||||
|
ino, fh, datasync
|
||||||
|
);
|
||||||
|
reply.error(ENOSYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn statfs(&mut self, _req: &fuser::Request<'_>, _ino: u64, reply: fuser::ReplyStatfs) {
|
||||||
|
reply.statfs(0, 0, 0, 0, 0, 512, 255, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setxattr(
|
||||||
|
&mut self,
|
||||||
|
_req: &fuser::Request<'_>,
|
||||||
|
ino: u64,
|
||||||
|
name: &std::ffi::OsStr,
|
||||||
|
_value: &[u8],
|
||||||
|
flags: i32,
|
||||||
|
position: u32,
|
||||||
|
reply: fuser::ReplyEmpty,
|
||||||
|
) {
|
||||||
|
debug!(
|
||||||
|
"[Not Implemented] setxattr(ino: {:#x?}, name: {:?}, flags: {:#x?}, position: {})",
|
||||||
|
ino, name, flags, position
|
||||||
|
);
|
||||||
|
reply.error(ENOSYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getxattr(
|
||||||
|
&mut self,
|
||||||
|
_req: &fuser::Request<'_>,
|
||||||
|
ino: u64,
|
||||||
|
name: &std::ffi::OsStr,
|
||||||
|
size: u32,
|
||||||
|
reply: fuser::ReplyXattr,
|
||||||
|
) {
|
||||||
|
debug!("[Not Implemented] getxattr(ino: {:#x?}, name: {:?}, size: {})", ino, name, size);
|
||||||
|
reply.error(ENOSYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn listxattr(
|
||||||
|
&mut self,
|
||||||
|
_req: &fuser::Request<'_>,
|
||||||
|
ino: u64,
|
||||||
|
size: u32,
|
||||||
|
reply: fuser::ReplyXattr,
|
||||||
|
) {
|
||||||
|
debug!("[Not Implemented] listxattr(ino: {:#x?}, size: {})", ino, size);
|
||||||
|
reply.error(ENOSYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn removexattr(
|
||||||
|
&mut self,
|
||||||
|
_req: &fuser::Request<'_>,
|
||||||
|
ino: u64,
|
||||||
|
name: &std::ffi::OsStr,
|
||||||
|
reply: fuser::ReplyEmpty,
|
||||||
|
) {
|
||||||
|
debug!("[Not Implemented] removexattr(ino: {:#x?}, name: {:?})", ino, name);
|
||||||
|
reply.error(ENOSYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn access(&mut self, _req: &fuser::Request<'_>, ino: u64, mask: i32, reply: fuser::ReplyEmpty) {
|
||||||
|
debug!("[Not Implemented] access(ino: {:#x?}, mask: {})", ino, mask);
|
||||||
|
reply.error(ENOSYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create(
|
||||||
|
&mut self,
|
||||||
|
_req: &fuser::Request<'_>,
|
||||||
|
parent: u64,
|
||||||
|
name: &std::ffi::OsStr,
|
||||||
|
mode: u32,
|
||||||
|
umask: u32,
|
||||||
|
flags: i32,
|
||||||
|
reply: fuser::ReplyCreate,
|
||||||
|
) {
|
||||||
|
debug!(
|
||||||
|
"[Not Implemented] create(parent: {:#x?}, name: {:?}, mode: {}, umask: {:#x?}, \
|
||||||
|
flags: {:#x?})",
|
||||||
|
parent, name, mode, umask, flags
|
||||||
|
);
|
||||||
|
reply.error(ENOSYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getlk(
|
||||||
|
&mut self,
|
||||||
|
_req: &fuser::Request<'_>,
|
||||||
|
ino: u64,
|
||||||
|
fh: u64,
|
||||||
|
lock_owner: u64,
|
||||||
|
start: u64,
|
||||||
|
end: u64,
|
||||||
|
typ: i32,
|
||||||
|
pid: u32,
|
||||||
|
reply: fuser::ReplyLock,
|
||||||
|
) {
|
||||||
|
debug!(
|
||||||
|
"[Not Implemented] getlk(ino: {:#x?}, fh: {}, lock_owner: {}, start: {}, \
|
||||||
|
end: {}, typ: {}, pid: {})",
|
||||||
|
ino, fh, lock_owner, start, end, typ, pid
|
||||||
|
);
|
||||||
|
reply.error(ENOSYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setlk(
|
||||||
|
&mut self,
|
||||||
|
_req: &fuser::Request<'_>,
|
||||||
|
ino: u64,
|
||||||
|
fh: u64,
|
||||||
|
lock_owner: u64,
|
||||||
|
start: u64,
|
||||||
|
end: u64,
|
||||||
|
typ: i32,
|
||||||
|
pid: u32,
|
||||||
|
sleep: bool,
|
||||||
|
reply: fuser::ReplyEmpty,
|
||||||
|
) {
|
||||||
|
debug!(
|
||||||
|
"[Not Implemented] setlk(ino: {:#x?}, fh: {}, lock_owner: {}, start: {}, \
|
||||||
|
end: {}, typ: {}, pid: {}, sleep: {})",
|
||||||
|
ino, fh, lock_owner, start, end, typ, pid, sleep
|
||||||
|
);
|
||||||
|
reply.error(ENOSYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bmap(
|
||||||
|
&mut self,
|
||||||
|
_req: &fuser::Request<'_>,
|
||||||
|
ino: u64,
|
||||||
|
blocksize: u32,
|
||||||
|
idx: u64,
|
||||||
|
reply: fuser::ReplyBmap,
|
||||||
|
) {
|
||||||
|
debug!(
|
||||||
|
"[Not Implemented] bmap(ino: {:#x?}, blocksize: {}, idx: {})",
|
||||||
|
ino, blocksize, idx,
|
||||||
|
);
|
||||||
|
reply.error(ENOSYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ioctl(
|
||||||
|
&mut self,
|
||||||
|
_req: &fuser::Request<'_>,
|
||||||
|
ino: u64,
|
||||||
|
fh: u64,
|
||||||
|
flags: u32,
|
||||||
|
cmd: u32,
|
||||||
|
in_data: &[u8],
|
||||||
|
out_size: u32,
|
||||||
|
reply: fuser::ReplyIoctl,
|
||||||
|
) {
|
||||||
|
debug!(
|
||||||
|
"[Not Implemented] ioctl(ino: {:#x?}, fh: {}, flags: {}, cmd: {}, \
|
||||||
|
in_data.len(): {}, out_size: {})",
|
||||||
|
ino,
|
||||||
|
fh,
|
||||||
|
flags,
|
||||||
|
cmd,
|
||||||
|
in_data.len(),
|
||||||
|
out_size,
|
||||||
|
);
|
||||||
|
reply.error(ENOSYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fallocate(
|
||||||
|
&mut self,
|
||||||
|
_req: &fuser::Request<'_>,
|
||||||
|
ino: u64,
|
||||||
|
fh: u64,
|
||||||
|
offset: i64,
|
||||||
|
length: i64,
|
||||||
|
mode: i32,
|
||||||
|
reply: fuser::ReplyEmpty,
|
||||||
|
) {
|
||||||
|
debug!(
|
||||||
|
"[Not Implemented] fallocate(ino: {:#x?}, fh: {}, offset: {}, \
|
||||||
|
length: {}, mode: {})",
|
||||||
|
ino, fh, offset, length, mode
|
||||||
|
);
|
||||||
|
reply.error(ENOSYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lseek(
|
||||||
|
&mut self,
|
||||||
|
_req: &fuser::Request<'_>,
|
||||||
|
ino: u64,
|
||||||
|
fh: u64,
|
||||||
|
offset: i64,
|
||||||
|
whence: i32,
|
||||||
|
reply: fuser::ReplyLseek,
|
||||||
|
) {
|
||||||
|
debug!(
|
||||||
|
"[Not Implemented] lseek(ino: {:#x?}, fh: {}, offset: {}, whence: {})",
|
||||||
|
ino, fh, offset, whence
|
||||||
|
);
|
||||||
|
reply.error(ENOSYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn copy_file_range(
|
||||||
|
&mut self,
|
||||||
|
_req: &fuser::Request<'_>,
|
||||||
|
ino_in: u64,
|
||||||
|
fh_in: u64,
|
||||||
|
offset_in: i64,
|
||||||
|
ino_out: u64,
|
||||||
|
fh_out: u64,
|
||||||
|
offset_out: i64,
|
||||||
|
len: u64,
|
||||||
|
flags: u32,
|
||||||
|
reply: fuser::ReplyWrite,
|
||||||
|
) {
|
||||||
|
debug!(
|
||||||
|
"[Not Implemented] copy_file_range(ino_in: {:#x?}, fh_in: {}, \
|
||||||
|
offset_in: {}, ino_out: {:#x?}, fh_out: {}, offset_out: {}, \
|
||||||
|
len: {}, flags: {})",
|
||||||
|
ino_in, fh_in, offset_in, ino_out, fh_out, offset_out, len, flags
|
||||||
|
);
|
||||||
|
reply.error(ENOSYS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,11 +1,35 @@
|
||||||
|
use std::cell::{LazyCell, RefCell};
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
|
|
||||||
use chrono::{NaiveDateTime, NaiveTime};
|
use chrono::{NaiveDateTime, NaiveTime};
|
||||||
use fat_bits::FatFs;
|
use fat_bits::FatFs;
|
||||||
use fat_bits::dir::DirEntry;
|
use fat_bits::dir::{DirEntry, DirIter};
|
||||||
use fuser::FileAttr;
|
use fuser::FileAttr;
|
||||||
|
use rand::{Rng, SeedableRng as _};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
thread_local! {
|
||||||
|
/// SAFETY
|
||||||
|
///
|
||||||
|
/// do not access this directly, only invoke the get_random_u32 function
|
||||||
|
// static RNG: LazyCell<UnsafeCell<rand::rngs::SmallRng>> = LazyCell::new(|| UnsafeCell::new(rand::rngs::SmallRng::from_os_rng()));
|
||||||
|
|
||||||
|
/// performance should not be a bottleneck here, since we only need to occasionally generate u32s to
|
||||||
|
/// be used as generations in inodes
|
||||||
|
/// if at some point (contrary to expectations) it should become, can switch it to an UnsafeCell
|
||||||
|
static RNG: LazyCell<RefCell<rand::rngs::SmallRng>> = LazyCell::new(|| RefCell::new(rand::rngs::SmallRng::from_os_rng()));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_random_u32() -> u32 {
|
||||||
|
// RNG.with(|x| unsafe {
|
||||||
|
// let rng = &mut (*x.get());
|
||||||
|
|
||||||
|
// rng.random::<u32>()
|
||||||
|
// })
|
||||||
|
|
||||||
|
RNG.with(|rng| rng.borrow_mut().random())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum Kind {
|
pub enum Kind {
|
||||||
File,
|
File,
|
||||||
Dir,
|
Dir,
|
||||||
|
|
@ -20,13 +44,15 @@ impl From<Kind> for fuser::FileType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ROOT_INO: u64 = 1;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub struct Inode {
|
pub struct Inode {
|
||||||
ino: u64,
|
ino: u64,
|
||||||
|
generation: u32,
|
||||||
|
|
||||||
size: u64,
|
size: u64,
|
||||||
// blocks: u64,
|
|
||||||
block_size: u32,
|
block_size: u32,
|
||||||
|
|
||||||
kind: Kind,
|
kind: Kind,
|
||||||
|
|
@ -49,6 +75,8 @@ impl Inode {
|
||||||
pub fn new(fat_fs: &FatFs, dir_entry: DirEntry, uid: u32, gid: u32) -> Inode {
|
pub fn new(fat_fs: &FatFs, dir_entry: DirEntry, uid: u32, gid: u32) -> Inode {
|
||||||
assert!(dir_entry.is_file() || dir_entry.is_dir());
|
assert!(dir_entry.is_file() || dir_entry.is_dir());
|
||||||
|
|
||||||
|
let generation = get_random_u32();
|
||||||
|
|
||||||
let kind = if dir_entry.is_dir() {
|
let kind = if dir_entry.is_dir() {
|
||||||
Kind::Dir
|
Kind::Dir
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -69,6 +97,7 @@ impl Inode {
|
||||||
|
|
||||||
Inode {
|
Inode {
|
||||||
ino: dir_entry.first_cluster() as u64,
|
ino: dir_entry.first_cluster() as u64,
|
||||||
|
generation,
|
||||||
size: dir_entry.file_size() as u64,
|
size: dir_entry.file_size() as u64,
|
||||||
block_size: fat_fs.bpb().bytes_per_sector() as u32,
|
block_size: fat_fs.bpb().bytes_per_sector() as u32,
|
||||||
kind,
|
kind,
|
||||||
|
|
@ -103,4 +132,22 @@ impl Inode {
|
||||||
flags: 0,
|
flags: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn dir_iter(&self, fat_fs: &FatFs) -> anyhow::Result<impl Iterator<Item = DirEntry>> {
|
||||||
|
anyhow::ensure!(self.kind == Kind::Dir, "cannot dir_iter on a file");
|
||||||
|
|
||||||
|
// TODO: the boxing here is not particularly pretty, but neccessary, since the DirIter for
|
||||||
|
// the root holds a
|
||||||
|
|
||||||
|
if self.ino == ROOT_INO {
|
||||||
|
// root dir
|
||||||
|
|
||||||
|
return Ok(fat_fs.root_dir_iter());
|
||||||
|
}
|
||||||
|
|
||||||
|
let chain_reader = fat_fs.chain_reader(self.first_cluster);
|
||||||
|
|
||||||
|
// TODO: get rid of this Box if the boxing is removed from root_dir_iter
|
||||||
|
Ok(DirIter::new(Box::new(chain_reader)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,11 @@
|
||||||
|
mod fuse;
|
||||||
mod inode;
|
mod inode;
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::ffi::c_int;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use fat_bits::{FatFs, SliceLike};
|
use fat_bits::{FatFs, SliceLike};
|
||||||
use fuser::Filesystem;
|
|
||||||
use libc::{ENOSYS, EPERM};
|
|
||||||
use log::{debug, warn};
|
|
||||||
|
|
||||||
use crate::inode::Inode;
|
use crate::inode::Inode;
|
||||||
|
|
||||||
|
|
@ -19,6 +16,8 @@ pub struct FatFuse {
|
||||||
uid: u32,
|
uid: u32,
|
||||||
gid: u32,
|
gid: u32,
|
||||||
|
|
||||||
|
next_fd: u32,
|
||||||
|
|
||||||
inode_table: BTreeMap<u64, Inode>,
|
inode_table: BTreeMap<u64, Inode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -33,544 +32,16 @@ impl FatFuse {
|
||||||
fat_fs,
|
fat_fs,
|
||||||
uid,
|
uid,
|
||||||
gid,
|
gid,
|
||||||
|
next_fd: 0,
|
||||||
inode_table: BTreeMap::new(),
|
inode_table: BTreeMap::new(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Filesystem for FatFuse {
|
fn get_inode(&self, ino: u64) -> Option<&Inode> {
|
||||||
fn init(
|
self.inode_table.get(&ino)
|
||||||
&mut self,
|
|
||||||
_req: &fuser::Request<'_>,
|
|
||||||
_config: &mut fuser::KernelConfig,
|
|
||||||
) -> Result<(), c_int> {
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn destroy(&mut self) {}
|
fn get_inode_mut(&mut self, ino: u64) -> Option<&mut Inode> {
|
||||||
|
self.inode_table.get_mut(&ino)
|
||||||
fn lookup(
|
|
||||||
&mut self,
|
|
||||||
_req: &fuser::Request<'_>,
|
|
||||||
parent: u64,
|
|
||||||
name: &std::ffi::OsStr,
|
|
||||||
reply: fuser::ReplyEntry,
|
|
||||||
) {
|
|
||||||
warn!("[Not Implemented] lookup(parent: {:#x?}, name {:?})", parent, name);
|
|
||||||
reply.error(ENOSYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn forget(&mut self, _req: &fuser::Request<'_>, _ino: u64, _nlookup: u64) {}
|
|
||||||
|
|
||||||
fn getattr(
|
|
||||||
&mut self,
|
|
||||||
_req: &fuser::Request<'_>,
|
|
||||||
ino: u64,
|
|
||||||
fh: Option<u64>,
|
|
||||||
reply: fuser::ReplyAttr,
|
|
||||||
) {
|
|
||||||
warn!("[Not Implemented] getattr(ino: {:#x?}, fh: {:#x?})", ino, fh);
|
|
||||||
reply.error(ENOSYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setattr(
|
|
||||||
&mut self,
|
|
||||||
_req: &fuser::Request<'_>,
|
|
||||||
ino: u64,
|
|
||||||
mode: Option<u32>,
|
|
||||||
uid: Option<u32>,
|
|
||||||
gid: Option<u32>,
|
|
||||||
size: Option<u64>,
|
|
||||||
_atime: Option<fuser::TimeOrNow>,
|
|
||||||
_mtime: Option<fuser::TimeOrNow>,
|
|
||||||
_ctime: Option<std::time::SystemTime>,
|
|
||||||
fh: Option<u64>,
|
|
||||||
_crtime: Option<std::time::SystemTime>,
|
|
||||||
_chgtime: Option<std::time::SystemTime>,
|
|
||||||
_bkuptime: Option<std::time::SystemTime>,
|
|
||||||
flags: Option<u32>,
|
|
||||||
reply: fuser::ReplyAttr,
|
|
||||||
) {
|
|
||||||
debug!(
|
|
||||||
"[Not Implemented] setattr(ino: {:#x?}, mode: {:?}, uid: {:?}, \
|
|
||||||
gid: {:?}, size: {:?}, fh: {:?}, flags: {:?})",
|
|
||||||
ino, mode, uid, gid, size, fh, flags
|
|
||||||
);
|
|
||||||
reply.error(ENOSYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn readlink(&mut self, _req: &fuser::Request<'_>, ino: u64, reply: fuser::ReplyData) {
|
|
||||||
debug!("[Not Implemented] readlink(ino: {:#x?})", ino);
|
|
||||||
reply.error(ENOSYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mknod(
|
|
||||||
&mut self,
|
|
||||||
_req: &fuser::Request<'_>,
|
|
||||||
parent: u64,
|
|
||||||
name: &std::ffi::OsStr,
|
|
||||||
mode: u32,
|
|
||||||
umask: u32,
|
|
||||||
rdev: u32,
|
|
||||||
reply: fuser::ReplyEntry,
|
|
||||||
) {
|
|
||||||
debug!(
|
|
||||||
"[Not Implemented] mknod(parent: {:#x?}, name: {:?}, mode: {}, \
|
|
||||||
umask: {:#x?}, rdev: {})",
|
|
||||||
parent, name, mode, umask, rdev
|
|
||||||
);
|
|
||||||
reply.error(ENOSYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mkdir(
|
|
||||||
&mut self,
|
|
||||||
_req: &fuser::Request<'_>,
|
|
||||||
parent: u64,
|
|
||||||
name: &std::ffi::OsStr,
|
|
||||||
mode: u32,
|
|
||||||
umask: u32,
|
|
||||||
reply: fuser::ReplyEntry,
|
|
||||||
) {
|
|
||||||
debug!(
|
|
||||||
"[Not Implemented] mkdir(parent: {:#x?}, name: {:?}, mode: {}, umask: {:#x?})",
|
|
||||||
parent, name, mode, umask
|
|
||||||
);
|
|
||||||
reply.error(ENOSYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unlink(
|
|
||||||
&mut self,
|
|
||||||
_req: &fuser::Request<'_>,
|
|
||||||
parent: u64,
|
|
||||||
name: &std::ffi::OsStr,
|
|
||||||
reply: fuser::ReplyEmpty,
|
|
||||||
) {
|
|
||||||
debug!("[Not Implemented] unlink(parent: {:#x?}, name: {:?})", parent, name,);
|
|
||||||
reply.error(ENOSYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn rmdir(
|
|
||||||
&mut self,
|
|
||||||
_req: &fuser::Request<'_>,
|
|
||||||
parent: u64,
|
|
||||||
name: &std::ffi::OsStr,
|
|
||||||
reply: fuser::ReplyEmpty,
|
|
||||||
) {
|
|
||||||
debug!("[Not Implemented] rmdir(parent: {:#x?}, name: {:?})", parent, name,);
|
|
||||||
reply.error(ENOSYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn symlink(
|
|
||||||
&mut self,
|
|
||||||
_req: &fuser::Request<'_>,
|
|
||||||
parent: u64,
|
|
||||||
link_name: &std::ffi::OsStr,
|
|
||||||
target: &std::path::Path,
|
|
||||||
reply: fuser::ReplyEntry,
|
|
||||||
) {
|
|
||||||
debug!(
|
|
||||||
"[Not Implemented] symlink(parent: {:#x?}, link_name: {:?}, target: {:?})",
|
|
||||||
parent, link_name, target,
|
|
||||||
);
|
|
||||||
reply.error(EPERM);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn rename(
|
|
||||||
&mut self,
|
|
||||||
_req: &fuser::Request<'_>,
|
|
||||||
parent: u64,
|
|
||||||
name: &std::ffi::OsStr,
|
|
||||||
newparent: u64,
|
|
||||||
newname: &std::ffi::OsStr,
|
|
||||||
flags: u32,
|
|
||||||
reply: fuser::ReplyEmpty,
|
|
||||||
) {
|
|
||||||
debug!(
|
|
||||||
"[Not Implemented] rename(parent: {:#x?}, name: {:?}, newparent: {:#x?}, \
|
|
||||||
newname: {:?}, flags: {})",
|
|
||||||
parent, name, newparent, newname, flags,
|
|
||||||
);
|
|
||||||
reply.error(ENOSYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn link(
|
|
||||||
&mut self,
|
|
||||||
_req: &fuser::Request<'_>,
|
|
||||||
ino: u64,
|
|
||||||
newparent: u64,
|
|
||||||
newname: &std::ffi::OsStr,
|
|
||||||
reply: fuser::ReplyEntry,
|
|
||||||
) {
|
|
||||||
debug!(
|
|
||||||
"[Not Implemented] link(ino: {:#x?}, newparent: {:#x?}, newname: {:?})",
|
|
||||||
ino, newparent, newname
|
|
||||||
);
|
|
||||||
reply.error(EPERM);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn open(&mut self, _req: &fuser::Request<'_>, _ino: u64, _flags: i32, reply: fuser::ReplyOpen) {
|
|
||||||
reply.opened(0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read(
|
|
||||||
&mut self,
|
|
||||||
_req: &fuser::Request<'_>,
|
|
||||||
ino: u64,
|
|
||||||
fh: u64,
|
|
||||||
offset: i64,
|
|
||||||
size: u32,
|
|
||||||
flags: i32,
|
|
||||||
lock_owner: Option<u64>,
|
|
||||||
reply: fuser::ReplyData,
|
|
||||||
) {
|
|
||||||
warn!(
|
|
||||||
"[Not Implemented] read(ino: {:#x?}, fh: {}, offset: {}, size: {}, \
|
|
||||||
flags: {:#x?}, lock_owner: {:?})",
|
|
||||||
ino, fh, offset, size, flags, lock_owner
|
|
||||||
);
|
|
||||||
reply.error(ENOSYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write(
|
|
||||||
&mut self,
|
|
||||||
_req: &fuser::Request<'_>,
|
|
||||||
ino: u64,
|
|
||||||
fh: u64,
|
|
||||||
offset: i64,
|
|
||||||
data: &[u8],
|
|
||||||
write_flags: u32,
|
|
||||||
flags: i32,
|
|
||||||
lock_owner: Option<u64>,
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn flush(
|
|
||||||
&mut self,
|
|
||||||
_req: &fuser::Request<'_>,
|
|
||||||
ino: u64,
|
|
||||||
fh: u64,
|
|
||||||
lock_owner: u64,
|
|
||||||
reply: fuser::ReplyEmpty,
|
|
||||||
) {
|
|
||||||
debug!(
|
|
||||||
"[Not Implemented] flush(ino: {:#x?}, fh: {}, lock_owner: {:?})",
|
|
||||||
ino, fh, lock_owner
|
|
||||||
);
|
|
||||||
reply.error(ENOSYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn release(
|
|
||||||
&mut self,
|
|
||||||
_req: &fuser::Request<'_>,
|
|
||||||
_ino: u64,
|
|
||||||
_fh: u64,
|
|
||||||
_flags: i32,
|
|
||||||
_lock_owner: Option<u64>,
|
|
||||||
_flush: bool,
|
|
||||||
reply: fuser::ReplyEmpty,
|
|
||||||
) {
|
|
||||||
reply.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fsync(
|
|
||||||
&mut self,
|
|
||||||
_req: &fuser::Request<'_>,
|
|
||||||
ino: u64,
|
|
||||||
fh: u64,
|
|
||||||
datasync: bool,
|
|
||||||
reply: fuser::ReplyEmpty,
|
|
||||||
) {
|
|
||||||
debug!("[Not Implemented] fsync(ino: {:#x?}, fh: {}, datasync: {})", ino, fh, datasync);
|
|
||||||
reply.error(ENOSYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn opendir(
|
|
||||||
&mut self,
|
|
||||||
_req: &fuser::Request<'_>,
|
|
||||||
_ino: u64,
|
|
||||||
_flags: i32,
|
|
||||||
reply: fuser::ReplyOpen,
|
|
||||||
) {
|
|
||||||
reply.opened(0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn readdir(
|
|
||||||
&mut self,
|
|
||||||
_req: &fuser::Request<'_>,
|
|
||||||
ino: u64,
|
|
||||||
fh: u64,
|
|
||||||
offset: i64,
|
|
||||||
reply: fuser::ReplyDirectory,
|
|
||||||
) {
|
|
||||||
warn!("[Not Implemented] readdir(ino: {:#x?}, fh: {}, offset: {})", ino, fh, offset);
|
|
||||||
reply.error(ENOSYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn readdirplus(
|
|
||||||
&mut self,
|
|
||||||
_req: &fuser::Request<'_>,
|
|
||||||
ino: u64,
|
|
||||||
fh: u64,
|
|
||||||
offset: i64,
|
|
||||||
reply: fuser::ReplyDirectoryPlus,
|
|
||||||
) {
|
|
||||||
debug!(
|
|
||||||
"[Not Implemented] readdirplus(ino: {:#x?}, fh: {}, offset: {})",
|
|
||||||
ino, fh, offset
|
|
||||||
);
|
|
||||||
reply.error(ENOSYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn releasedir(
|
|
||||||
&mut self,
|
|
||||||
_req: &fuser::Request<'_>,
|
|
||||||
_ino: u64,
|
|
||||||
_fh: u64,
|
|
||||||
_flags: i32,
|
|
||||||
reply: fuser::ReplyEmpty,
|
|
||||||
) {
|
|
||||||
reply.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fsyncdir(
|
|
||||||
&mut self,
|
|
||||||
_req: &fuser::Request<'_>,
|
|
||||||
ino: u64,
|
|
||||||
fh: u64,
|
|
||||||
datasync: bool,
|
|
||||||
reply: fuser::ReplyEmpty,
|
|
||||||
) {
|
|
||||||
debug!(
|
|
||||||
"[Not Implemented] fsyncdir(ino: {:#x?}, fh: {}, datasync: {})",
|
|
||||||
ino, fh, datasync
|
|
||||||
);
|
|
||||||
reply.error(ENOSYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn statfs(&mut self, _req: &fuser::Request<'_>, _ino: u64, reply: fuser::ReplyStatfs) {
|
|
||||||
reply.statfs(0, 0, 0, 0, 0, 512, 255, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setxattr(
|
|
||||||
&mut self,
|
|
||||||
_req: &fuser::Request<'_>,
|
|
||||||
ino: u64,
|
|
||||||
name: &std::ffi::OsStr,
|
|
||||||
_value: &[u8],
|
|
||||||
flags: i32,
|
|
||||||
position: u32,
|
|
||||||
reply: fuser::ReplyEmpty,
|
|
||||||
) {
|
|
||||||
debug!(
|
|
||||||
"[Not Implemented] setxattr(ino: {:#x?}, name: {:?}, flags: {:#x?}, position: {})",
|
|
||||||
ino, name, flags, position
|
|
||||||
);
|
|
||||||
reply.error(ENOSYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn getxattr(
|
|
||||||
&mut self,
|
|
||||||
_req: &fuser::Request<'_>,
|
|
||||||
ino: u64,
|
|
||||||
name: &std::ffi::OsStr,
|
|
||||||
size: u32,
|
|
||||||
reply: fuser::ReplyXattr,
|
|
||||||
) {
|
|
||||||
debug!("[Not Implemented] getxattr(ino: {:#x?}, name: {:?}, size: {})", ino, name, size);
|
|
||||||
reply.error(ENOSYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn listxattr(
|
|
||||||
&mut self,
|
|
||||||
_req: &fuser::Request<'_>,
|
|
||||||
ino: u64,
|
|
||||||
size: u32,
|
|
||||||
reply: fuser::ReplyXattr,
|
|
||||||
) {
|
|
||||||
debug!("[Not Implemented] listxattr(ino: {:#x?}, size: {})", ino, size);
|
|
||||||
reply.error(ENOSYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn removexattr(
|
|
||||||
&mut self,
|
|
||||||
_req: &fuser::Request<'_>,
|
|
||||||
ino: u64,
|
|
||||||
name: &std::ffi::OsStr,
|
|
||||||
reply: fuser::ReplyEmpty,
|
|
||||||
) {
|
|
||||||
debug!("[Not Implemented] removexattr(ino: {:#x?}, name: {:?})", ino, name);
|
|
||||||
reply.error(ENOSYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn access(&mut self, _req: &fuser::Request<'_>, ino: u64, mask: i32, reply: fuser::ReplyEmpty) {
|
|
||||||
debug!("[Not Implemented] access(ino: {:#x?}, mask: {})", ino, mask);
|
|
||||||
reply.error(ENOSYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create(
|
|
||||||
&mut self,
|
|
||||||
_req: &fuser::Request<'_>,
|
|
||||||
parent: u64,
|
|
||||||
name: &std::ffi::OsStr,
|
|
||||||
mode: u32,
|
|
||||||
umask: u32,
|
|
||||||
flags: i32,
|
|
||||||
reply: fuser::ReplyCreate,
|
|
||||||
) {
|
|
||||||
debug!(
|
|
||||||
"[Not Implemented] create(parent: {:#x?}, name: {:?}, mode: {}, umask: {:#x?}, \
|
|
||||||
flags: {:#x?})",
|
|
||||||
parent, name, mode, umask, flags
|
|
||||||
);
|
|
||||||
reply.error(ENOSYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn getlk(
|
|
||||||
&mut self,
|
|
||||||
_req: &fuser::Request<'_>,
|
|
||||||
ino: u64,
|
|
||||||
fh: u64,
|
|
||||||
lock_owner: u64,
|
|
||||||
start: u64,
|
|
||||||
end: u64,
|
|
||||||
typ: i32,
|
|
||||||
pid: u32,
|
|
||||||
reply: fuser::ReplyLock,
|
|
||||||
) {
|
|
||||||
debug!(
|
|
||||||
"[Not Implemented] getlk(ino: {:#x?}, fh: {}, lock_owner: {}, start: {}, \
|
|
||||||
end: {}, typ: {}, pid: {})",
|
|
||||||
ino, fh, lock_owner, start, end, typ, pid
|
|
||||||
);
|
|
||||||
reply.error(ENOSYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setlk(
|
|
||||||
&mut self,
|
|
||||||
_req: &fuser::Request<'_>,
|
|
||||||
ino: u64,
|
|
||||||
fh: u64,
|
|
||||||
lock_owner: u64,
|
|
||||||
start: u64,
|
|
||||||
end: u64,
|
|
||||||
typ: i32,
|
|
||||||
pid: u32,
|
|
||||||
sleep: bool,
|
|
||||||
reply: fuser::ReplyEmpty,
|
|
||||||
) {
|
|
||||||
debug!(
|
|
||||||
"[Not Implemented] setlk(ino: {:#x?}, fh: {}, lock_owner: {}, start: {}, \
|
|
||||||
end: {}, typ: {}, pid: {}, sleep: {})",
|
|
||||||
ino, fh, lock_owner, start, end, typ, pid, sleep
|
|
||||||
);
|
|
||||||
reply.error(ENOSYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bmap(
|
|
||||||
&mut self,
|
|
||||||
_req: &fuser::Request<'_>,
|
|
||||||
ino: u64,
|
|
||||||
blocksize: u32,
|
|
||||||
idx: u64,
|
|
||||||
reply: fuser::ReplyBmap,
|
|
||||||
) {
|
|
||||||
debug!(
|
|
||||||
"[Not Implemented] bmap(ino: {:#x?}, blocksize: {}, idx: {})",
|
|
||||||
ino, blocksize, idx,
|
|
||||||
);
|
|
||||||
reply.error(ENOSYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ioctl(
|
|
||||||
&mut self,
|
|
||||||
_req: &fuser::Request<'_>,
|
|
||||||
ino: u64,
|
|
||||||
fh: u64,
|
|
||||||
flags: u32,
|
|
||||||
cmd: u32,
|
|
||||||
in_data: &[u8],
|
|
||||||
out_size: u32,
|
|
||||||
reply: fuser::ReplyIoctl,
|
|
||||||
) {
|
|
||||||
debug!(
|
|
||||||
"[Not Implemented] ioctl(ino: {:#x?}, fh: {}, flags: {}, cmd: {}, \
|
|
||||||
in_data.len(): {}, out_size: {})",
|
|
||||||
ino,
|
|
||||||
fh,
|
|
||||||
flags,
|
|
||||||
cmd,
|
|
||||||
in_data.len(),
|
|
||||||
out_size,
|
|
||||||
);
|
|
||||||
reply.error(ENOSYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fallocate(
|
|
||||||
&mut self,
|
|
||||||
_req: &fuser::Request<'_>,
|
|
||||||
ino: u64,
|
|
||||||
fh: u64,
|
|
||||||
offset: i64,
|
|
||||||
length: i64,
|
|
||||||
mode: i32,
|
|
||||||
reply: fuser::ReplyEmpty,
|
|
||||||
) {
|
|
||||||
debug!(
|
|
||||||
"[Not Implemented] fallocate(ino: {:#x?}, fh: {}, offset: {}, \
|
|
||||||
length: {}, mode: {})",
|
|
||||||
ino, fh, offset, length, mode
|
|
||||||
);
|
|
||||||
reply.error(ENOSYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn lseek(
|
|
||||||
&mut self,
|
|
||||||
_req: &fuser::Request<'_>,
|
|
||||||
ino: u64,
|
|
||||||
fh: u64,
|
|
||||||
offset: i64,
|
|
||||||
whence: i32,
|
|
||||||
reply: fuser::ReplyLseek,
|
|
||||||
) {
|
|
||||||
debug!(
|
|
||||||
"[Not Implemented] lseek(ino: {:#x?}, fh: {}, offset: {}, whence: {})",
|
|
||||||
ino, fh, offset, whence
|
|
||||||
);
|
|
||||||
reply.error(ENOSYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn copy_file_range(
|
|
||||||
&mut self,
|
|
||||||
_req: &fuser::Request<'_>,
|
|
||||||
ino_in: u64,
|
|
||||||
fh_in: u64,
|
|
||||||
offset_in: i64,
|
|
||||||
ino_out: u64,
|
|
||||||
fh_out: u64,
|
|
||||||
offset_out: i64,
|
|
||||||
len: u64,
|
|
||||||
flags: u32,
|
|
||||||
reply: fuser::ReplyWrite,
|
|
||||||
) {
|
|
||||||
debug!(
|
|
||||||
"[Not Implemented] copy_file_range(ino_in: {:#x?}, fh_in: {}, \
|
|
||||||
offset_in: {}, ino_out: {:#x?}, fh_out: {}, offset_out: {}, \
|
|
||||||
len: {}, flags: {})",
|
|
||||||
ino_in, fh_in, offset_in, ino_out, fh_out, offset_out, len, flags
|
|
||||||
);
|
|
||||||
reply.error(ENOSYS);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue