Finish Node::extract method

This commit is contained in:
Nathan Fisher 2023-07-05 13:07:46 -04:00
parent 5fd1d09e77
commit e5cbf16064
3 changed files with 98 additions and 12 deletions

View File

@ -17,6 +17,37 @@ pub fn chown(path: &str, uid: u32, gid: u32) -> Result<(), Error> {
} }
} }
#[cfg(target_os = "linux")]
pub fn chmod(path: &str, mode: u32) -> Result<(), Error> {
let ret = unsafe { libc::chmod(CString::new(path)?.as_ptr(), mode) };
if ret == 0 {
Ok(())
} else {
Err(Error::Io(io::Error::last_os_error()))
}
}
#[cfg(target_os = "freebsd")]
pub fn chmod(path: &str, mode: u32) -> Result<(), Error> {
let ret = unsafe { libc::chmod(CString::new(path)?.as_ptr(), mode.try_into()?) };
if ret == 0 {
Ok(())
} else {
Err(Error::Io(io::Error::last_os_error()))
}
}
#[cfg(target_os = "linux")]
pub fn mkfifo(path: &str, mode: u32) -> Result<(), Error> {
let ret = unsafe { libc::mkfifo(CString::new(path)?.as_ptr(), mode) };
if ret == 0 {
Ok(())
} else {
Err(Error::Io(io::Error::last_os_error()))
}
}
#[cfg(target_os = "freebsd")]
pub fn mkfifo(path: &str, mode: u32) -> Result<(), Error> { pub fn mkfifo(path: &str, mode: u32) -> Result<(), Error> {
let ret = unsafe { libc::mkfifo(CString::new(path)?.as_ptr(), mode.try_into()?) }; let ret = unsafe { libc::mkfifo(CString::new(path)?.as_ptr(), mode.try_into()?) };
if ret == 0 { if ret == 0 {
@ -26,6 +57,18 @@ pub fn mkfifo(path: &str, mode: u32) -> Result<(), Error> {
} }
} }
#[cfg(target_os = "linux")]
pub fn mknod(path: &str, mode: u32, major: u32, minor: u32) -> Result<(), Error> {
let dev = libc::makedev(major, minor);
let res = unsafe { libc::mknod(CString::new(path)?.as_ptr(), mode, dev) };
if res == 0 {
Ok(())
} else {
Err(Error::Io(io::Error::last_os_error()))
}
}
#[cfg(target_os = "freebsd")]
pub fn mknod(path: &str, mode: u32, major: u32, minor: u32) -> Result<(), Error> { pub fn mknod(path: &str, mode: u32, major: u32, minor: u32) -> Result<(), Error> {
let dev = libc::makedev(major, minor); let dev = libc::makedev(major, minor);
let res = unsafe { libc::mknod(CString::new(path)?.as_ptr(), mode.try_into()?, dev) }; let res = unsafe { libc::mknod(CString::new(path)?.as_ptr(), mode.try_into()?, dev) };

View File

@ -6,7 +6,7 @@ use {
std::{ std::{
collections::HashMap, collections::HashMap,
fs, fs,
io::{BufReader, Read, Write}, io::{BufReader, BufWriter, Read, Write},
os::unix::fs::{symlink, DirBuilderExt, MetadataExt}, os::unix::fs::{symlink, DirBuilderExt, MetadataExt},
path::{Path, PathBuf}, path::{Path, PathBuf},
sync::Mutex, sync::Mutex,
@ -156,10 +156,10 @@ impl Node {
} }
let kind = Kind::from(mode); let kind = Kind::from(mode);
if kind == Kind::Char { if kind == Kind::Char {
let device = Special::from_rdev(meta.rdev().try_into()?); let device = Special::from_rdev(meta.rdev());
break 'blk FileType::Character(device); break 'blk FileType::Character(device);
} else if kind == Kind::Block { } else if kind == Kind::Block {
let device = Special::from_rdev(meta.rdev().try_into()?); let device = Special::from_rdev(meta.rdev());
break 'blk FileType::Block(device); break 'blk FileType::Block(device);
} else if kind == Kind::Pipe { } else if kind == Kind::Pipe {
break 'blk FileType::Fifo; break 'blk FileType::Fifo;
@ -225,10 +225,38 @@ impl Node {
if euid == 0 { if euid == 0 {
nix::chown(&path, self.uid, self.gid)?; nix::chown(&path, self.uid, self.gid)?;
} }
}, }
FileType::Block(ref b) => todo!(), FileType::Block(ref b) => {
FileType::Character(ref c) => todo!(), if euid == 0 {
FileType::Normal(ref n) => todo!(), nix::mknod(&path, self.mode, b.major, b.minor)?;
}
}
FileType::Character(ref c) => {
if euid == 0 {
nix::mknod(&path, self.mode, c.major, c.minor)?;
}
}
FileType::Normal(ref n) => {
let n_path = PathBuf::from(&path);
if let Some(p) = n_path.parent() {
if !p.exists() {
self.mkdir(&p)?;
}
}
{
let fd = fs::OpenOptions::new()
.create(true)
.truncate(true)
.write(true)
.open(&n_path)?;
let mut writer = BufWriter::new(fd);
writer.write_all(&n.data)?;
}
if euid == 0 {
nix::chown(&path, self.uid, self.gid)?;
}
nix::chmod(&path, self.mode)?;
}
FileType::HardLink(ref t) => { FileType::HardLink(ref t) => {
let target = if let Some(prefix) = prefix { let target = if let Some(prefix) = prefix {
format!("{prefix}/{t}") format!("{prefix}/{t}")
@ -236,7 +264,7 @@ impl Node {
t.to_string() t.to_string()
}; };
fs::hard_link(&target, &path)?; fs::hard_link(&target, &path)?;
}, }
FileType::SoftLink(ref t) => { FileType::SoftLink(ref t) => {
symlink(&self.name, t)?; symlink(&self.name, t)?;
} }

View File

@ -27,10 +27,25 @@ impl Special {
Ok(()) Ok(())
} }
pub(super) fn from_rdev(rdev: u32) -> Self { #[cfg(all(target_os = "freebsd", target_arch = "x86_64"))]
pub(super) fn from_rdev(rdev: u64) -> Self {
Self { Self {
major: rdev >> 8, major: ((rdev >> 8) & 0xff) as u32,
minor: rdev & 0xff, minor: (rdev & 0xffff00ff) as u32,
}
}
#[cfg(target_os = "linux")]
pub(super) fn from_rdev(rdev: u64) -> Self {
let mut major = 0;
major |= (rdev & 0x00000000000fff00) >> 8;
major |= (rdev & 0xfffff00000000000) >> 32;
let mut minor = 0;
minor |= (rdev & 0x00000000000000ff) >> 0;
minor |= (rdev & 0x00000ffffff00000) >> 12;
Self {
major: major as u32,
minor: minor as u32,
} }
} }
} }