chown - Removed several clones

This commit is contained in:
Nathan Fisher 2023-01-18 21:45:18 -05:00
parent 3016f4c234
commit 7fc064a441

View File

@ -1,7 +1,13 @@
use super::Cmd; use super::Cmd;
use crate::{fs::FileType, pw}; use crate::{fs::FileType, pw};
use clap::{Arg, ArgAction, ArgGroup, Command, ValueHint}; use clap::{Arg, ArgAction, ArgGroup, Command, ValueHint};
use std::{error::Error, fs::{File, self}, io, path::PathBuf, os::{unix::prelude::MetadataExt, fd::AsRawFd}}; use std::{
error::Error,
fs::{self, File},
io,
os::{fd::AsRawFd, unix::prelude::MetadataExt},
path::PathBuf,
};
use walkdir::{DirEntry, WalkDir}; use walkdir::{DirEntry, WalkDir};
#[derive(Debug, Default)] #[derive(Debug, Default)]
@ -78,17 +84,17 @@ impl Cmd for Chown {
if matches.get_flag("full-traverse") { if matches.get_flag("full-traverse") {
Some(Recurse { Some(Recurse {
traversal: Traversal::FullLinks, traversal: Traversal::FullLinks,
same_filesystem: matches.get_flag("same-filesystem") same_filesystem: matches.get_flag("same-filesystem"),
}) })
} else if matches.get_flag("cli-traverse") { } else if matches.get_flag("cli-traverse") {
Some(Recurse { Some(Recurse {
traversal: Traversal::CliLinks, traversal: Traversal::CliLinks,
same_filesystem: matches.get_flag("same-filesystem") same_filesystem: matches.get_flag("same-filesystem"),
}) })
} else { } else {
Some(Recurse { Some(Recurse {
traversal: Traversal::NoLinks, traversal: Traversal::NoLinks,
same_filesystem: matches.get_flag("same-filesystem") same_filesystem: matches.get_flag("same-filesystem"),
}) })
} }
} else { } else {
@ -103,12 +109,30 @@ impl Cmd for Chown {
}; };
let (user, group) = if let Some(who) = matches.get_one::<String>("user") { let (user, group) = if let Some(who) = matches.get_one::<String>("user") {
if let Some((u, g)) = who.split_once(':') { if let Some((u, g)) = who.split_once(':') {
let uid = pw::get_uid_for_name(u).ok_or(io::Error::new(io::ErrorKind::Other, "cannot get uid"))?; let uid = pw::get_uid_for_name(u)
let gid = pw::get_gid_for_groupname(g).ok_or(io::Error::new(io::ErrorKind::Other, "cannot get gid"))?; .ok_or(io::Error::new(io::ErrorKind::Other, "cannot get uid"))?;
(User { name: u.to_string(), uid }, Some(Group { name: g.to_string(), gid })) let gid = pw::get_gid_for_groupname(g)
.ok_or(io::Error::new(io::ErrorKind::Other, "cannot get gid"))?;
(
User {
name: u.to_string(),
uid,
},
Some(Group {
name: g.to_string(),
gid,
}),
)
} else { } else {
let uid = pw::get_uid_for_name(who).ok_or(io::Error::new(io::ErrorKind::Other, "cannot get uid"))?; let uid = pw::get_uid_for_name(who)
(User { name: who.to_string(), uid }, None) .ok_or(io::Error::new(io::ErrorKind::Other, "cannot get uid"))?;
(
User {
name: who.to_string(),
uid,
},
None,
)
} }
} else { } else {
return Err(Box::new(io::Error::new( return Err(Box::new(io::Error::new(
@ -201,13 +225,18 @@ impl Action {
let uid = meta.uid(); let uid = meta.uid();
let gid = meta.gid(); let gid = meta.gid();
unsafe { unsafe {
if libc::fchown(fd.as_raw_fd(), self.user.uid, self.group.clone().map(|x| x.gid).unwrap_or(gid)) != 0 { if libc::fchown(
fd.as_raw_fd(),
self.user.uid,
self.group.as_ref().map(|x| x.gid).unwrap_or(gid),
) != 0
{
return Err(io::Error::last_os_error().into()); return Err(io::Error::last_os_error().into());
} }
} }
let ft = FileType::from(meta); let ft = FileType::from(meta);
match ft { match ft {
FileType::File => {}, FileType::File => {}
FileType::Symlink => { FileType::Symlink => {
let tgt = fs::read_link(&self.path)?; let tgt = fs::read_link(&self.path)?;
if tgt.is_dir() { if tgt.is_dir() {
@ -217,41 +246,56 @@ impl Action {
} }
} }
} }
}, }
FileType::Dir => { FileType::Dir => {
if let Some(r) = self.recurse { if let Some(r) = self.recurse {
if r.traversal != Traversal::NoLinks { if r.traversal != Traversal::NoLinks {
self.recurse()?; self.recurse()?;
} }
} }
}, }
} }
if let Some(feedback) = self.feedback { if let Some(feedback) = self.feedback {
match feedback { match feedback {
Feedback::Full => { Feedback::Full => {
if self.user.uid != uid || self.group.clone().map(|x| x.gid) != Some(gid) { if self.user.uid != uid || self.group.as_ref().map(|x| x.gid) != Some(gid) {
if let Some(g) = &self.group { if let Some(g) = &self.group {
println!("{} changed to {}:{}", &self.path.display(), &self.user.name, &g.name); println!(
"{} changed to {}:{}",
&self.path.display(),
&self.user.name,
&g.name
);
} else { } else {
println!("{} changed to {}", &self.path.display(), &self.user.name); println!("{} changed to {}", &self.path.display(), &self.user.name);
} }
} else { } else {
if let Some(g) = &self.group { if let Some(g) = &self.group {
println!("{} retained as {}:{}", &self.path.display(), &self.user.name, &g.name); println!(
"{} retained as {}:{}",
&self.path.display(),
&self.user.name,
&g.name
);
} else { } else {
println!("{} retained as {}", &self.path.display(), &self.user.name); println!("{} retained as {}", &self.path.display(), &self.user.name);
} }
} }
} }
Feedback::Changes => { Feedback::Changes => {
if self.user.uid != uid || self.group.clone().map(|x| x.gid) != Some(gid) { if self.user.uid != uid || self.group.as_ref().map(|x| x.gid) != Some(gid) {
if let Some(g) = &self.group { if let Some(g) = &self.group {
println!("{} changed to {}:{}", self.path.display(), &self.user.name, &g.name); println!(
"{} changed to {}:{}",
self.path.display(),
&self.user.name,
&g.name
);
} else { } else {
println!("{}, changed to {}", self.path.display(), &self.user.name); println!("{}, changed to {}", self.path.display(), &self.user.name);
} }
} }
}, }
} }
} }
Ok(()) Ok(())
@ -259,7 +303,11 @@ impl Action {
fn into_child(&self, entry: DirEntry) -> Result<Self, Box<dyn Error>> { fn into_child(&self, entry: DirEntry) -> Result<Self, Box<dyn Error>> {
let path = entry.path().to_path_buf(); let path = entry.path().to_path_buf();
let recurse = if let Some(r) = self.recurse { Some(r.increment()) } else { None }; let recurse = if let Some(r) = self.recurse {
Some(r.increment())
} else {
None
};
Ok(Self { Ok(Self {
path, path,
user: self.user.clone(), user: self.user.clone(),
@ -272,11 +320,9 @@ impl Action {
fn recurse(&self) -> Result<(), Box<dyn Error>> { fn recurse(&self) -> Result<(), Box<dyn Error>> {
let walker = WalkDir::new(&self.path) let walker = WalkDir::new(&self.path)
.same_file_system(self.recurse.map_or(false, |x| !x.same_filesystem)) .same_file_system(self.recurse.map_or(false, |x| !x.same_filesystem))
.follow_links(self.recurse.map_or(false, |x| { .follow_links(self.recurse.map_or(false, |x| match x.traversal {
match x.traversal {
Traversal::NoLinks | Traversal::CliLinks => false, Traversal::NoLinks | Traversal::CliLinks => false,
_ => true, _ => true,
}
})); }));
for entry in walker { for entry in walker {
let entry = entry?; let entry = entry?;