1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 11:37:44 +00:00

mkdir: move to a config approach for the functions

This commit is contained in:
Sylvestre Ledru 2025-03-30 11:23:52 +02:00
parent d41c0ceb53
commit b874d90345

View file

@ -33,6 +33,24 @@ mod options {
pub const CONTEXT: &str = "context"; pub const CONTEXT: &str = "context";
} }
/// Configuration for directory creation.
pub struct Config<'a> {
/// Create parent directories as needed.
pub recursive: bool,
/// File permissions (octal).
pub mode: u32,
/// Print message for each created directory.
pub verbose: bool,
/// Set SELinux security context.
pub set_selinux_context: bool,
/// Specific SELinux context.
pub context: Option<&'a String>,
}
#[cfg(windows)] #[cfg(windows)]
fn get_mode(_matches: &ArgMatches, _mode_had_minus_prefix: bool) -> Result<u32, String> { fn get_mode(_matches: &ArgMatches, _mode_had_minus_prefix: bool) -> Result<u32, String> {
Ok(DEFAULT_PERM) Ok(DEFAULT_PERM)
@ -98,14 +116,16 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let context = matches.get_one::<String>(options::CONTEXT); let context = matches.get_one::<String>(options::CONTEXT);
match get_mode(&matches, mode_had_minus_prefix) { match get_mode(&matches, mode_had_minus_prefix) {
Ok(mode) => exec( Ok(mode) => {
dirs, let config = Config {
recursive, recursive,
mode, mode,
verbose, verbose,
set_selinux_context || context.is_some(), set_selinux_context: set_selinux_context || context.is_some(),
context, context,
), };
exec(dirs, &config)
}
Err(f) => Err(USimpleError::new(1, f)), Err(f) => Err(USimpleError::new(1, f)),
} }
} }
@ -159,26 +179,12 @@ pub fn uu_app() -> Command {
/** /**
* Create the list of new directories * Create the list of new directories
*/ */
fn exec( fn exec(dirs: ValuesRef<OsString>, config: &Config) -> UResult<()> {
dirs: ValuesRef<OsString>,
recursive: bool,
mode: u32,
verbose: bool,
set_selinux_context: bool,
context: Option<&String>,
) -> UResult<()> {
for dir in dirs { for dir in dirs {
let path_buf = PathBuf::from(dir); let path_buf = PathBuf::from(dir);
let path = path_buf.as_path(); let path = path_buf.as_path();
show_if_err!(mkdir( show_if_err!(mkdir(path, config));
path,
recursive,
mode,
verbose,
set_selinux_context,
context
));
} }
Ok(()) Ok(())
} }
@ -196,14 +202,7 @@ fn exec(
/// ///
/// To match the GNU behavior, a path with the last directory being a single dot /// To match the GNU behavior, a path with the last directory being a single dot
/// (like `some/path/to/.`) is created (with the dot stripped). /// (like `some/path/to/.`) is created (with the dot stripped).
pub fn mkdir( pub fn mkdir(path: &Path, config: &Config) -> UResult<()> {
path: &Path,
recursive: bool,
mode: u32,
verbose: bool,
set_selinux_context: bool,
context: Option<&String>,
) -> UResult<()> {
if path.as_os_str().is_empty() { if path.as_os_str().is_empty() {
return Err(USimpleError::new( return Err(USimpleError::new(
1, 1,
@ -216,15 +215,7 @@ pub fn mkdir(
// std::fs::create_dir("foo/."); fails in pure Rust // std::fs::create_dir("foo/."); fails in pure Rust
let path_buf = dir_strip_dot_for_creation(path); let path_buf = dir_strip_dot_for_creation(path);
let path = path_buf.as_path(); let path = path_buf.as_path();
create_dir( create_dir(path, false, config)
path,
recursive,
verbose,
false,
mode,
set_selinux_context,
context,
)
} }
#[cfg(any(unix, target_os = "redox"))] #[cfg(any(unix, target_os = "redox"))]
@ -245,17 +236,9 @@ fn chmod(_path: &Path, _mode: u32) -> UResult<()> {
// Return true if the directory at `path` has been created by this call. // Return true if the directory at `path` has been created by this call.
// `is_parent` argument is not used on windows // `is_parent` argument is not used on windows
#[allow(unused_variables)] #[allow(unused_variables)]
fn create_dir( fn create_dir(path: &Path, is_parent: bool, config: &Config) -> UResult<()> {
path: &Path,
recursive: bool,
verbose: bool,
is_parent: bool,
mode: u32,
set_selinux_context: bool,
context: Option<&String>,
) -> UResult<()> {
let path_exists = path.exists(); let path_exists = path.exists();
if path_exists && !recursive { if path_exists && !config.recursive {
return Err(USimpleError::new( return Err(USimpleError::new(
1, 1,
format!("{}: File exists", path.display()), format!("{}: File exists", path.display()),
@ -265,17 +248,9 @@ fn create_dir(
return Ok(()); return Ok(());
} }
if recursive { if config.recursive {
match path.parent() { match path.parent() {
Some(p) => create_dir( Some(p) => create_dir(p, true, config)?,
p,
recursive,
verbose,
true,
mode,
set_selinux_context,
context,
)?,
None => { None => {
USimpleError::new(1, "failed to create whole tree"); USimpleError::new(1, "failed to create whole tree");
} }
@ -284,7 +259,7 @@ fn create_dir(
match std::fs::create_dir(path) { match std::fs::create_dir(path) {
Ok(()) => { Ok(()) => {
if verbose { if config.verbose {
println!( println!(
"{}: created directory {}", "{}: created directory {}",
uucore::util_name(), uucore::util_name(),
@ -294,7 +269,7 @@ fn create_dir(
#[cfg(all(unix, target_os = "linux"))] #[cfg(all(unix, target_os = "linux"))]
let new_mode = if path_exists { let new_mode = if path_exists {
mode config.mode
} else { } else {
// TODO: Make this macos and freebsd compatible by creating a function to get permission bits from // TODO: Make this macos and freebsd compatible by creating a function to get permission bits from
// acl in extended attributes // acl in extended attributes
@ -303,24 +278,24 @@ fn create_dir(
if is_parent { if is_parent {
(!mode::get_umask() & 0o777) | 0o300 | acl_perm_bits (!mode::get_umask() & 0o777) | 0o300 | acl_perm_bits
} else { } else {
mode | acl_perm_bits config.mode | acl_perm_bits
} }
}; };
#[cfg(all(unix, not(target_os = "linux")))] #[cfg(all(unix, not(target_os = "linux")))]
let new_mode = if is_parent { let new_mode = if is_parent {
(!mode::get_umask() & 0o777) | 0o300 (!mode::get_umask() & 0o777) | 0o300
} else { } else {
mode config.mode
}; };
#[cfg(windows)] #[cfg(windows)]
let new_mode = mode; let new_mode = config.mode;
chmod(path, new_mode)?; chmod(path, new_mode)?;
// Apply SELinux context if requested // Apply SELinux context if requested
#[cfg(target_os = "linux")] #[cfg(feature = "selinux")]
if set_selinux_context { if config.set_selinux_context && uucore::selinux::check_selinux_enabled().is_ok() {
if let Err(e) = uucore::selinux_support::set_selinux_security_context(path, context) if let Err(e) = uucore::selinux::set_selinux_security_context(path, config.context)
{ {
let _ = std::fs::remove_dir(path); let _ = std::fs::remove_dir(path);
return Err(USimpleError::new( return Err(USimpleError::new(