implemented rmdir
This commit is contained in:
parent
2ed107478e
commit
c9e8833ac6
4 changed files with 131 additions and 99 deletions
|
|
@ -270,6 +270,17 @@ impl DirEntry {
|
||||||
self.write(sub_slice)
|
self.write(sub_slice)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// erase this DirEntry
|
||||||
|
pub fn erase(self, fat_fs: &FatFs) -> std::io::Result<()> {
|
||||||
|
let mut sub_slice = SubSliceMut::new(fat_fs.inner.clone(), self.offset, 32);
|
||||||
|
|
||||||
|
// set first byte to 0xE5 (free)
|
||||||
|
sub_slice.write_all(&[0xe5])?;
|
||||||
|
|
||||||
|
// paste over with zeros
|
||||||
|
sub_slice.write_all(&[0; 31])
|
||||||
|
}
|
||||||
|
|
||||||
/// indicates this DirEntry is empty
|
/// indicates this DirEntry is empty
|
||||||
///
|
///
|
||||||
/// can be either simply empty (0xe5) or the sentinel (0x00) that indicates that all following
|
/// can be either simply empty (0xe5) or the sentinel (0x00) that indicates that all following
|
||||||
|
|
@ -660,13 +671,21 @@ impl<'a> DirIter<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// inner function for iterator
|
pub fn find_by_name(&mut self, name: &str) -> Option<DirEntry> {
|
||||||
fn next_impl(&mut self) -> anyhow::Result<Option<DirEntry>> {
|
self.find(|dir_entry| &dir_entry.name_string() == name)
|
||||||
let offset = self.reader.current_offset();
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for DirIter<'_> {
|
||||||
|
type Item = DirEntry;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
fn next_impl(me: &mut DirIter<'_>) -> anyhow::Result<Option<DirEntry>> {
|
||||||
|
let offset = me.reader.current_offset();
|
||||||
|
|
||||||
let mut chunk = [0; 32];
|
let mut chunk = [0; 32];
|
||||||
|
|
||||||
if self.reader.read_exact(&mut chunk).is_err() {
|
if me.reader.read_exact(&mut chunk).is_err() {
|
||||||
// nothing we can do here since we might be in an invalid state after a partial read
|
// nothing we can do here since we might be in an invalid state after a partial read
|
||||||
anyhow::bail!("read failed");
|
anyhow::bail!("read failed");
|
||||||
}
|
}
|
||||||
|
|
@ -677,12 +696,12 @@ impl<'a> DirIter<'a> {
|
||||||
let mut dir_entry = match dir_entry {
|
let mut dir_entry = match dir_entry {
|
||||||
DirEntryWrapper::Regular(dir_entry) => dir_entry,
|
DirEntryWrapper::Regular(dir_entry) => dir_entry,
|
||||||
DirEntryWrapper::LongName(long_name) => {
|
DirEntryWrapper::LongName(long_name) => {
|
||||||
self.long_filename_buf.next(long_name).map_err(|e| {
|
me.long_filename_buf.next(long_name).map_err(|e| {
|
||||||
self.long_filename_buf.reset();
|
me.long_filename_buf.reset();
|
||||||
anyhow::anyhow!("invalid long filename entry: {e}")
|
anyhow::anyhow!("invalid long filename entry: {e}")
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
return self.next_impl();
|
return next_impl(me);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -691,10 +710,10 @@ impl<'a> DirIter<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if dir_entry.is_empty() {
|
if dir_entry.is_empty() {
|
||||||
return self.next_impl();
|
return next_impl(me);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(iter) = self
|
if let Some(iter) = me
|
||||||
.long_filename_buf
|
.long_filename_buf
|
||||||
.get_buf(dir_entry.checksum)
|
.get_buf(dir_entry.checksum)
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
|
|
@ -713,17 +732,12 @@ impl<'a> DirIter<'a> {
|
||||||
dir_entry.set_long_name(long_filename);
|
dir_entry.set_long_name(long_filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.long_filename_buf.reset();
|
me.long_filename_buf.reset();
|
||||||
|
|
||||||
Ok(Some(dir_entry))
|
Ok(Some(dir_entry))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Iterator for DirIter<'_> {
|
match next_impl(self) {
|
||||||
type Item = DirEntry;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
match self.next_impl() {
|
|
||||||
Ok(x) => x,
|
Ok(x) => x,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
// print error message, try next
|
// print error message, try next
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
use std::ffi::c_int;
|
use std::ffi::c_int;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use std::rc::Rc;
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use fat_bits::dir::DirEntry;
|
use fat_bits::dir::DirEntry;
|
||||||
|
|
@ -44,7 +43,8 @@ impl Filesystem for FatFuse {
|
||||||
let Some(name) = name.to_str() else {
|
let Some(name) = name.to_str() else {
|
||||||
// TODO: add proper handling of non-utf8 strings
|
// TODO: add proper handling of non-utf8 strings
|
||||||
debug!("cannot convert OsStr {:?} to str", name);
|
debug!("cannot convert OsStr {:?} to str", name);
|
||||||
reply.error(ENOSYS);
|
|
||||||
|
reply.error(EINVAL);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -62,14 +62,7 @@ impl Filesystem for FatFuse {
|
||||||
|
|
||||||
let parent_inode = parent_inode.borrow();
|
let parent_inode = parent_inode.borrow();
|
||||||
|
|
||||||
let dir_entry: DirEntry =
|
let dir_entry: DirEntry = match parent_inode.find_child_by_name(&self.fat_fs, name) {
|
||||||
match parent_inode
|
|
||||||
.dir_iter(&self.fat_fs)
|
|
||||||
.and_then(|mut dir_iter| {
|
|
||||||
dir_iter
|
|
||||||
.find(|dir_entry| &dir_entry.name_string() == name)
|
|
||||||
.ok_or(ENOENT)
|
|
||||||
}) {
|
|
||||||
Ok(dir_entry) => dir_entry,
|
Ok(dir_entry) => dir_entry,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
debug!("error: {}", err);
|
debug!("error: {}", err);
|
||||||
|
|
@ -79,11 +72,7 @@ impl Filesystem for FatFuse {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let inode = self.get_or_make_inode_by_dir_entry(
|
let inode = self.get_or_make_inode(&dir_entry, &parent_inode);
|
||||||
&dir_entry,
|
|
||||||
parent_inode.ino(),
|
|
||||||
parent_inode.path(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut inode = inode.borrow_mut();
|
let mut inode = inode.borrow_mut();
|
||||||
|
|
||||||
|
|
@ -239,8 +228,39 @@ impl Filesystem for FatFuse {
|
||||||
name: &std::ffi::OsStr,
|
name: &std::ffi::OsStr,
|
||||||
reply: fuser::ReplyEmpty,
|
reply: fuser::ReplyEmpty,
|
||||||
) {
|
) {
|
||||||
debug!("[Not Implemented] rmdir(parent: {:#x?}, name: {:?})", parent, name,);
|
let Some(name) = name.to_str() else {
|
||||||
reply.error(ENOSYS);
|
// TODO: add proper handling of non-utf8 strings
|
||||||
|
debug!("cannot convert OsStr {:?} to str", name);
|
||||||
|
|
||||||
|
reply.error(EINVAL);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(parent_inode) = self.get_inode(parent) else {
|
||||||
|
debug!("parent inode {parent} does not exist");
|
||||||
|
|
||||||
|
reply.error(ENOENT);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let dir_entry = match parent_inode.borrow().find_child_by_name(&self.fat_fs, name) {
|
||||||
|
Ok(dir_entry) => dir_entry,
|
||||||
|
Err(err) => {
|
||||||
|
debug!("parent inode {parent} has no child {name}");
|
||||||
|
|
||||||
|
reply.error(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(err) = dir_entry.erase(&self.fat_fs) {
|
||||||
|
debug!("error while erasing DirEntry: {err}");
|
||||||
|
|
||||||
|
reply.error(EIO);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
reply.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rename(
|
fn rename(
|
||||||
|
|
@ -651,14 +671,10 @@ impl Filesystem for FatFuse {
|
||||||
// also skip over `offset` entries
|
// also skip over `offset` entries
|
||||||
let dirs: Vec<DirEntry> = dir_iter.skip(offset).collect();
|
let dirs: Vec<DirEntry> = dir_iter.skip(offset).collect();
|
||||||
|
|
||||||
let dir_ino = dir_inode.ino();
|
|
||||||
let dir_path = dir_inode.path();
|
|
||||||
|
|
||||||
for dir_entry in dirs {
|
for dir_entry in dirs {
|
||||||
let name = dir_entry.name_string();
|
let name = dir_entry.name_string();
|
||||||
|
|
||||||
let inode =
|
let inode = self.get_or_make_inode(&dir_entry, &dir_inode);
|
||||||
self.get_or_make_inode_by_dir_entry(&dir_entry, dir_ino, Rc::clone(&dir_path));
|
|
||||||
|
|
||||||
let inode = inode.borrow();
|
let inode = inode.borrow();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,10 @@ 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 fat_bits::iter::{ClusterChainReader, ClusterChainWriter};
|
use fat_bits::iter::{ClusterChainReader, ClusterChainWriter};
|
||||||
use fuser::FileAttr;
|
use fuser::FileAttr;
|
||||||
use libc::{EISDIR, ENOTDIR};
|
use libc::{EISDIR, ENOENT, ENOTDIR};
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use rand::{Rng, SeedableRng as _};
|
use rand::{Rng, SeedableRng as _};
|
||||||
|
|
||||||
|
|
@ -311,7 +311,7 @@ impl Inode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dir_iter(&self, fat_fs: &FatFs) -> Result<impl Iterator<Item = DirEntry>, i32> {
|
pub fn dir_iter<'a>(&'a self, fat_fs: &'a FatFs) -> Result<DirIter<'a>, i32> {
|
||||||
if self.kind != Kind::Dir {
|
if self.kind != Kind::Dir {
|
||||||
return Err(ENOTDIR);
|
return Err(ENOTDIR);
|
||||||
}
|
}
|
||||||
|
|
@ -325,6 +325,11 @@ impl Inode {
|
||||||
Ok(fat_fs.dir_iter(self.first_cluster))
|
Ok(fat_fs.dir_iter(self.first_cluster))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn find_child_by_name(&self, fat_fs: &FatFs, name: &str) -> Result<DirEntry, i32> {
|
||||||
|
self.dir_iter(fat_fs)
|
||||||
|
.and_then(|mut dir_iter| dir_iter.find_by_name(name).ok_or(ENOENT))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn file_reader<'a>(&'a self, fat_fs: &'a FatFs) -> Result<ClusterChainReader<'a>, i32> {
|
pub fn file_reader<'a>(&'a self, fat_fs: &'a FatFs) -> Result<ClusterChainReader<'a>, i32> {
|
||||||
if self.is_dir() {
|
if self.is_dir() {
|
||||||
return Err(EISDIR);
|
return Err(EISDIR);
|
||||||
|
|
|
||||||
|
|
@ -206,12 +206,9 @@ impl FatFuse {
|
||||||
self.inode_table.get(&ino)
|
self.inode_table.get(&ino)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_or_make_inode_by_dir_entry(
|
fn get_or_make_inode(&mut self, dir_entry: &DirEntry, parent: &Inode) -> InodeRef {
|
||||||
&mut self,
|
// let parent = parent.borrow();
|
||||||
dir_entry: &DirEntry,
|
|
||||||
parent_ino: u64,
|
|
||||||
parent_path: Rc<str>,
|
|
||||||
) -> InodeRef {
|
|
||||||
// try to find inode by first cluster first
|
// try to find inode by first cluster first
|
||||||
if dir_entry.first_cluster() != 0
|
if dir_entry.first_cluster() != 0
|
||||||
&& let Some(inode) = self.get_inode_by_first_cluster(dir_entry.first_cluster())
|
&& let Some(inode) = self.get_inode_by_first_cluster(dir_entry.first_cluster())
|
||||||
|
|
@ -223,9 +220,9 @@ impl FatFuse {
|
||||||
// mostly for empty files/directories which have a first cluster of 0
|
// mostly for empty files/directories which have a first cluster of 0
|
||||||
|
|
||||||
let path = {
|
let path = {
|
||||||
let mut path = parent_path.as_ref().to_owned();
|
let mut path = parent.path().as_ref().to_owned();
|
||||||
|
|
||||||
if parent_ino != inode::ROOT_INO {
|
if parent.ino() != inode::ROOT_INO {
|
||||||
// root inode already has trailing slash
|
// root inode already has trailing slash
|
||||||
path.push('/');
|
path.push('/');
|
||||||
}
|
}
|
||||||
|
|
@ -242,9 +239,9 @@ impl FatFuse {
|
||||||
// no inode found, make a new one
|
// no inode found, make a new one
|
||||||
let ino = self.next_ino();
|
let ino = self.next_ino();
|
||||||
|
|
||||||
let Some(parent_inode) = self.get_inode(parent_ino).cloned() else {
|
let Some(parent_inode) = self.get_inode(parent.ino()).cloned() else {
|
||||||
// TODO: what do we do here? should not happen
|
// TODO: what do we do here? should not happen
|
||||||
panic!("parent_ino {} does not lead to inode", parent_ino);
|
panic!("parent_ino {} does not lead to inode", parent.ino());
|
||||||
};
|
};
|
||||||
|
|
||||||
let inode =
|
let inode =
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue