abi: merge remove() and remove_directory()
This commit is contained in:
parent
f978a6b287
commit
f1256e262b
@ -1,6 +1,6 @@
|
||||
use yggdrasil_abi::{
|
||||
error::Error,
|
||||
io::{AccessMode, FileMode, GroupId, OpenOptions, UserId},
|
||||
io::{AccessMode, FileMode, GroupId, OpenOptions, RemoveFlags, UserId},
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
@ -291,32 +291,6 @@ impl IoContext {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn remove_entry<P: AsRef<Path>>(
|
||||
&mut self,
|
||||
at: Option<NodeRef>,
|
||||
path: P,
|
||||
directory: bool,
|
||||
) -> Result<(), Error> {
|
||||
let path = path.as_ref();
|
||||
let (parent, name) = path.trim_end_separators().split_right();
|
||||
|
||||
if name.is_empty() {
|
||||
log::warn!("Tried to remove weird path: {:?}", path);
|
||||
return Err(Error::DoesNotExist);
|
||||
}
|
||||
|
||||
let parent = self.find(at, parent, false)?;
|
||||
let access = self.check_access(&parent, AccessMode::WRITE)?;
|
||||
|
||||
if directory {
|
||||
// parent.remove_directory(name, access)
|
||||
todo!()
|
||||
} else {
|
||||
let filename = Filename::new(name)?;
|
||||
parent.remove_file(filename, access)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rename(
|
||||
&mut self,
|
||||
src_at: Option<NodeRef>,
|
||||
@ -374,12 +348,37 @@ impl IoContext {
|
||||
}
|
||||
|
||||
/// Removes a device or regular file node at given path
|
||||
pub fn remove_file<P: AsRef<Path>>(
|
||||
pub fn remove<P: AsRef<Path>>(
|
||||
&mut self,
|
||||
at: Option<NodeRef>,
|
||||
path: P,
|
||||
flags: RemoveFlags,
|
||||
) -> Result<(), Error> {
|
||||
self.remove_entry(at, path, false)
|
||||
let path = path.as_ref();
|
||||
let (parent, name) = path.trim_end_separators().split_right();
|
||||
|
||||
if name.is_empty() {
|
||||
log::warn!("Tried to remove weird path: {:?}", path);
|
||||
return Err(Error::DoesNotExist);
|
||||
}
|
||||
|
||||
let parent = self.find(at, parent, false)?;
|
||||
let access = self.check_access(&parent, AccessMode::WRITE)?;
|
||||
let filename = Filename::new(name)?;
|
||||
|
||||
let child = parent.lookup_or_load(filename, access.clone())?;
|
||||
|
||||
if child.is_directory() {
|
||||
if !flags.contains_any(RemoveFlags::DIRECTORY | RemoveFlags::DIRECTORY_ONLY) {
|
||||
return Err(Error::IsADirectory);
|
||||
}
|
||||
} else {
|
||||
if flags.contains_any(RemoveFlags::DIRECTORY_ONLY) {
|
||||
return Err(Error::NotADirectory);
|
||||
}
|
||||
}
|
||||
|
||||
parent.remove_file(filename, access)
|
||||
}
|
||||
|
||||
/// Locates a [crate::Node] pointed to by given [Path]
|
||||
|
@ -4,7 +4,7 @@ pub(crate) use abi::{
|
||||
error::Error,
|
||||
io::{
|
||||
AccessMode, DirectoryEntry, FileAttr, FileMode, FileSync, MountOptions, OpenOptions,
|
||||
PipeOptions, PollControl, RawFd, TerminalOptions, TerminalSize, TimerOptions,
|
||||
PipeOptions, PollControl, RawFd, RemoveFlags, TerminalOptions, TerminalSize, TimerOptions,
|
||||
UnmountOptions,
|
||||
},
|
||||
mem::{MappingFlags, MappingSource},
|
||||
|
@ -5,8 +5,8 @@ use abi::{
|
||||
io::{
|
||||
AccessMode, ChannelPublisherId, DeviceRequest, DirectoryEntry, FileAttr, FileControl,
|
||||
FileMetadataUpdate, FileMode, FileSync, FilesystemControl, MessageDestination, OpenOptions,
|
||||
PipeOptions, PollControl, RawFd, ReceivedMessageMetadata, Rename, SeekFrom, SentMessage,
|
||||
TerminalOptions, TerminalSize, TimerOptions,
|
||||
PipeOptions, PollControl, RawFd, ReceivedMessageMetadata, RemoveFlags, Rename, SeekFrom,
|
||||
SentMessage, TerminalOptions, TerminalSize, TimerOptions,
|
||||
},
|
||||
process::{ProcessWait, WaitFlags},
|
||||
};
|
||||
@ -176,16 +176,12 @@ pub(crate) fn create_symlink(at: Option<RawFd>, target: &str, path: &str) -> Res
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn remove_directory(_at: Option<RawFd>, _path: &str) -> Result<(), Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub(crate) fn remove(at: Option<RawFd>, path: &str) -> Result<(), Error> {
|
||||
pub(crate) fn remove(at: Option<RawFd>, path: &str, options: RemoveFlags) -> Result<(), Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io_at(&process, at, |at, mut io| {
|
||||
io.ioctx_mut().remove_file(Some(at), path)?;
|
||||
io.ioctx_mut().remove(Some(at), path, options)?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
@ -32,6 +32,11 @@ bitfield FileMode(u32) {
|
||||
USER_READ: 8,
|
||||
}
|
||||
|
||||
bitfield RemoveFlags(u32) {
|
||||
DIRECTORY: 1,
|
||||
DIRECTORY_ONLY: 2,
|
||||
}
|
||||
|
||||
bitfield FileSync(u32) {
|
||||
DATA: 0,
|
||||
METADATA: 1,
|
||||
|
@ -125,11 +125,10 @@ syscall write_at(fd: RawFd, pos: u64, data: &[u8]) -> Result<usize>;
|
||||
syscall open_directory(at: Option<RawFd>, path: &str) -> Result<RawFd>;
|
||||
syscall read_directory_entries(fd: RawFd, entries: &mut [MaybeUninit<DirectoryEntry>]) -> Result<usize>;
|
||||
syscall create_directory(at: Option<RawFd>, path: &str, mode: FileMode) -> Result<()>;
|
||||
syscall remove_directory(at: Option<RawFd>, path: &str) -> Result<()>;
|
||||
syscall create_symlink(at: Option<RawFd>, target: &str, path: &str) -> Result<()>;
|
||||
|
||||
syscall read_link(at: Option<RawFd>, path: &str, buf: &mut [u8]) -> Result<usize>;
|
||||
syscall remove(at: Option<RawFd>, path: &str) -> Result<()>;
|
||||
syscall remove(at: Option<RawFd>, path: &str, flags: RemoveFlags) -> Result<()>;
|
||||
syscall rename(rename: &Rename<'_>) -> Result<()>;
|
||||
syscall clone_fd(source: RawFd, target: Option<RawFd>) -> Result<RawFd>;
|
||||
syscall update_metadata(at: Option<RawFd>, path: &str, update: &FileMetadataUpdate) -> Result<()>;
|
||||
|
@ -9,7 +9,8 @@ mod terminal;
|
||||
|
||||
pub use crate::generated::{
|
||||
AccessMode, DirectoryEntry, FileAttr, FileMode, FileSync, FileType, GroupId, MountOptions,
|
||||
OpenOptions, PipeOptions, PollControl, RawFd, TimerOptions, UnmountOptions, UserId,
|
||||
OpenOptions, PipeOptions, PollControl, RawFd, RemoveFlags, TimerOptions, UnmountOptions,
|
||||
UserId,
|
||||
};
|
||||
pub use channel::{ChannelPublisherId, MessageDestination, ReceivedMessageMetadata, SentMessage};
|
||||
pub use device::{DeviceRequest, Framebuffer};
|
||||
|
@ -1,71 +0,0 @@
|
||||
#![allow(missing_docs)]
|
||||
|
||||
pub mod device {
|
||||
pub use abi::io::{DeviceRequest, Framebuffer, MountOptions, UnmountOptions};
|
||||
}
|
||||
|
||||
pub mod terminal {
|
||||
pub use abi::io::{
|
||||
TerminalInputOptions, TerminalLineOptions, TerminalOptions, TerminalOutputOptions,
|
||||
TerminalSize,
|
||||
};
|
||||
}
|
||||
|
||||
pub mod message_channel {
|
||||
pub use abi::io::{
|
||||
ChannelPublisherId, MessageDestination, ReceivedMessageMetadata, SentMessage,
|
||||
};
|
||||
}
|
||||
|
||||
pub mod poll {
|
||||
pub use abi::io::PollControl;
|
||||
}
|
||||
|
||||
use core::str::FromStr;
|
||||
|
||||
pub use abi::io::{
|
||||
AccessMode, DirectoryEntry, FileAttr, FileMetadataUpdate, FileMetadataUpdateMode, FileMode,
|
||||
FileSync, FileTimesUpdate, FileType, OpenOptions, PipeOptions, RawFd, Rename, SeekFrom,
|
||||
TimerOptions,
|
||||
};
|
||||
|
||||
use abi::{error::Error, io::DeviceRequest, process::ProcessOption, util::FixedString};
|
||||
use alloc::string::String;
|
||||
|
||||
pub fn current_exe<T, F: FnOnce(&str) -> T>(_mapper: F) -> Result<T, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn home_directory<T, F: FnOnce(&str) -> T>(_mapper: F) -> Result<T, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn current_directory<T, F: FnOnce(&str) -> T>(mapper: F) -> Result<T, Error> {
|
||||
let mut option = ProcessOption::Directory(FixedString::empty());
|
||||
unsafe { crate::sys::get_process_option(&mut option) }?;
|
||||
let ProcessOption::Directory(path) = &option else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
Ok(mapper(path.as_ref()))
|
||||
}
|
||||
|
||||
pub fn current_directory_string() -> Result<String, Error> {
|
||||
current_directory(|s| s.into())
|
||||
}
|
||||
|
||||
pub fn set_current_directory(path: &str) -> Result<(), Error> {
|
||||
let mut option = ProcessOption::Directory(FixedString::from_str(path)?);
|
||||
unsafe { crate::sys::set_process_option(&mut option) }?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn make_temp_directory(_template: &mut [u8]) -> Result<(), Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn is_terminal(f: RawFd) -> bool {
|
||||
let mut option = DeviceRequest::IsTerminal(false);
|
||||
let res = unsafe { crate::sys::device_request(f, &mut option) };
|
||||
matches!((res, option), (Ok(()), DeviceRequest::IsTerminal(true)))
|
||||
}
|
53
lib/runtime/src/io/mod.rs
Normal file
53
lib/runtime/src/io/mod.rs
Normal file
@ -0,0 +1,53 @@
|
||||
#![allow(missing_docs)]
|
||||
|
||||
pub mod device {
|
||||
pub use abi::io::{DeviceRequest, Framebuffer, MountOptions, UnmountOptions};
|
||||
}
|
||||
|
||||
pub mod terminal {
|
||||
pub use abi::io::{
|
||||
TerminalInputOptions, TerminalLineOptions, TerminalOptions, TerminalOutputOptions,
|
||||
TerminalSize,
|
||||
};
|
||||
}
|
||||
|
||||
pub mod message_channel {
|
||||
pub use abi::io::{
|
||||
ChannelPublisherId, MessageDestination, ReceivedMessageMetadata, SentMessage,
|
||||
};
|
||||
}
|
||||
|
||||
pub mod poll {
|
||||
pub use abi::io::PollControl;
|
||||
}
|
||||
|
||||
pub use abi::io::{
|
||||
AccessMode, DirectoryEntry, FileAttr, FileMetadataUpdate, FileMetadataUpdateMode, FileMode,
|
||||
FileSync, FileTimesUpdate, FileType, OpenOptions, PipeOptions, RawFd, RemoveFlags, Rename,
|
||||
SeekFrom, TimerOptions,
|
||||
};
|
||||
|
||||
pub mod paths;
|
||||
pub use paths::*;
|
||||
|
||||
use abi::error::Error;
|
||||
|
||||
use device::DeviceRequest;
|
||||
|
||||
pub fn is_terminal(f: RawFd) -> bool {
|
||||
let mut option = DeviceRequest::IsTerminal(false);
|
||||
let res = unsafe { crate::sys::device_request(f, &mut option) };
|
||||
matches!((res, option), (Ok(()), DeviceRequest::IsTerminal(true)))
|
||||
}
|
||||
|
||||
pub fn remove_file(at: Option<RawFd>, path: &str) -> Result<(), Error> {
|
||||
unsafe { crate::sys::remove(at, path, RemoveFlags::empty()) }
|
||||
}
|
||||
|
||||
pub fn remove_directory(at: Option<RawFd>, path: &str) -> Result<(), Error> {
|
||||
unsafe { crate::sys::remove(at, path, RemoveFlags::DIRECTORY_ONLY) }
|
||||
}
|
||||
|
||||
pub fn remove_directory_recursive(_at: Option<RawFd>, _path: &str) -> Result<(), Error> {
|
||||
todo!()
|
||||
}
|
40
lib/runtime/src/io/paths.rs
Normal file
40
lib/runtime/src/io/paths.rs
Normal file
@ -0,0 +1,40 @@
|
||||
use core::str::FromStr;
|
||||
|
||||
use abi::{error::Error, process::ProcessOption, util::FixedString};
|
||||
use alloc::string::String;
|
||||
|
||||
pub fn current_exe<T, F: FnOnce(&str) -> T>(_mapper: F) -> Result<T, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn home_directory<T, F: FnOnce(&str) -> T>(_mapper: F) -> Result<T, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn current_directory<T, F: FnOnce(&str) -> T>(mapper: F) -> Result<T, Error> {
|
||||
let mut option = ProcessOption::Directory(FixedString::empty());
|
||||
unsafe { crate::sys::get_process_option(&mut option) }?;
|
||||
let ProcessOption::Directory(path) = &option else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
Ok(mapper(path.as_ref()))
|
||||
}
|
||||
|
||||
pub fn current_directory_string() -> Result<String, Error> {
|
||||
current_directory(|s| s.into())
|
||||
}
|
||||
|
||||
pub fn set_current_directory(path: &str) -> Result<(), Error> {
|
||||
let mut option = ProcessOption::Directory(FixedString::from_str(path)?);
|
||||
unsafe { crate::sys::set_process_option(&mut option) }?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn make_temp_directory(_template: &mut [u8]) -> Result<(), Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn canonicalize<T, F: FnOnce(&str) -> T>(_path: &str, _mapper: F) -> Result<T, Error> {
|
||||
todo!()
|
||||
}
|
@ -17,8 +17,8 @@ mod generated {
|
||||
error::Error,
|
||||
io::{
|
||||
AccessMode, ChannelPublisherId, DirectoryEntry, FileAttr, FileMode, FileSync,
|
||||
MountOptions, OpenOptions, PipeOptions, PollControl, RawFd, TerminalOptions,
|
||||
TerminalSize, TimerOptions, UnmountOptions,
|
||||
MountOptions, OpenOptions, PipeOptions, PollControl, RawFd, RemoveFlags,
|
||||
TerminalOptions, TerminalSize, TimerOptions, UnmountOptions,
|
||||
},
|
||||
mem::{MappingFlags, MappingSource},
|
||||
net::SocketType,
|
||||
|
@ -1,5 +1,10 @@
|
||||
#![feature(io_error_more)]
|
||||
use std::{io, fs, path::{Path, PathBuf}, process::ExitCode};
|
||||
|
||||
use std::{
|
||||
fs, io::{self, stdin, stdout, Write},
|
||||
path::{Path, PathBuf},
|
||||
process::ExitCode,
|
||||
};
|
||||
|
||||
use clap::Parser;
|
||||
|
||||
@ -7,16 +12,59 @@ use clap::Parser;
|
||||
struct Args {
|
||||
#[arg(short)]
|
||||
recurse: bool,
|
||||
#[arg(short)]
|
||||
verbose: bool,
|
||||
#[arg(short)]
|
||||
force: bool,
|
||||
#[clap(required = true)]
|
||||
paths: Vec<PathBuf>
|
||||
paths: Vec<PathBuf>,
|
||||
}
|
||||
|
||||
fn rm<P: AsRef<Path>>(path: P, recurse: bool) -> bool {
|
||||
fn read_answer() -> Result<bool, io::Error> {
|
||||
let stdin = stdin();
|
||||
|
||||
for _ in 0..3 {
|
||||
let mut buffer = String::new();
|
||||
let len = stdin.read_line(&mut buffer)?;
|
||||
if len == 0 {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
match buffer.as_str().trim() {
|
||||
"y" | "Y" | "" => return Ok(true),
|
||||
"n" | "N" => return Ok(false),
|
||||
_ => {
|
||||
eprintln!("Please answer `y` (default) or `n`");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
fn rm<P: AsRef<Path>>(path: P, args: &Args) -> bool {
|
||||
let path = path.as_ref();
|
||||
println!("remove {}", path.display());
|
||||
|
||||
if !args.force {
|
||||
print!("Remove {} [Y/n]? ", path.display());
|
||||
stdout().flush().ok();
|
||||
match read_answer() {
|
||||
Ok(true) => (),
|
||||
Ok(false) => return true,
|
||||
Err(err) => {
|
||||
eprintln!("stdin: {err}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if args.verbose {
|
||||
println!("remove {}", path.display());
|
||||
}
|
||||
|
||||
match fs::remove_file(path) {
|
||||
Err(e) if recurse && e.kind() == io::ErrorKind::IsADirectory => {
|
||||
Err(e) if args.recurse && e.kind() == io::ErrorKind::IsADirectory => {
|
||||
let readdir = match fs::read_dir(path) {
|
||||
Ok(dir) => dir,
|
||||
Err(error) => {
|
||||
@ -37,7 +85,11 @@ fn rm<P: AsRef<Path>>(path: P, recurse: bool) -> bool {
|
||||
}
|
||||
};
|
||||
|
||||
result &= rm(entry.path(), recurse);
|
||||
if entry.file_name() == ".." || entry.file_name() == "." {
|
||||
continue;
|
||||
}
|
||||
|
||||
result &= rm(entry.path(), args);
|
||||
}
|
||||
|
||||
if result {
|
||||
@ -48,12 +100,12 @@ fn rm<P: AsRef<Path>>(path: P, recurse: bool) -> bool {
|
||||
}
|
||||
|
||||
result
|
||||
},
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("{}: {}", path.display(), e);
|
||||
false
|
||||
}
|
||||
Ok(_) => true
|
||||
Ok(_) => true,
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,8 +113,8 @@ fn main() -> ExitCode {
|
||||
let args = Args::parse();
|
||||
let mut result = ExitCode::SUCCESS;
|
||||
|
||||
for arg in args.paths {
|
||||
if !rm(arg, args.recurse) {
|
||||
for arg in args.paths.iter() {
|
||||
if !rm(arg, &args) {
|
||||
result = ExitCode::FAILURE;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user