diff --git a/src/uu/mkdir/src/mkdir.rs b/src/uu/mkdir/src/mkdir.rs index 5147ec5e0..14c7701db 100644 --- a/src/uu/mkdir/src/mkdir.rs +++ b/src/uu/mkdir/src/mkdir.rs @@ -33,6 +33,24 @@ mod options { 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)] fn get_mode(_matches: &ArgMatches, _mode_had_minus_prefix: bool) -> Result { Ok(DEFAULT_PERM) @@ -98,14 +116,16 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let context = matches.get_one::(options::CONTEXT); match get_mode(&matches, mode_had_minus_prefix) { - Ok(mode) => exec( - dirs, - recursive, - mode, - verbose, - set_selinux_context || context.is_some(), - context, - ), + Ok(mode) => { + let config = Config { + recursive, + mode, + verbose, + set_selinux_context: set_selinux_context || context.is_some(), + context, + }; + exec(dirs, &config) + } Err(f) => Err(USimpleError::new(1, f)), } } @@ -159,26 +179,12 @@ pub fn uu_app() -> Command { /** * Create the list of new directories */ -fn exec( - dirs: ValuesRef, - recursive: bool, - mode: u32, - verbose: bool, - set_selinux_context: bool, - context: Option<&String>, -) -> UResult<()> { +fn exec(dirs: ValuesRef, config: &Config) -> UResult<()> { for dir in dirs { let path_buf = PathBuf::from(dir); let path = path_buf.as_path(); - show_if_err!(mkdir( - path, - recursive, - mode, - verbose, - set_selinux_context, - context - )); + show_if_err!(mkdir(path, config)); } Ok(()) } @@ -196,14 +202,7 @@ fn exec( /// /// 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). -pub fn mkdir( - path: &Path, - recursive: bool, - mode: u32, - verbose: bool, - set_selinux_context: bool, - context: Option<&String>, -) -> UResult<()> { +pub fn mkdir(path: &Path, config: &Config) -> UResult<()> { if path.as_os_str().is_empty() { return Err(USimpleError::new( 1, @@ -216,15 +215,7 @@ pub fn mkdir( // std::fs::create_dir("foo/."); fails in pure Rust let path_buf = dir_strip_dot_for_creation(path); let path = path_buf.as_path(); - create_dir( - path, - recursive, - verbose, - false, - mode, - set_selinux_context, - context, - ) + create_dir(path, false, config) } #[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. // `is_parent` argument is not used on windows #[allow(unused_variables)] -fn create_dir( - path: &Path, - recursive: bool, - verbose: bool, - is_parent: bool, - mode: u32, - set_selinux_context: bool, - context: Option<&String>, -) -> UResult<()> { +fn create_dir(path: &Path, is_parent: bool, config: &Config) -> UResult<()> { let path_exists = path.exists(); - if path_exists && !recursive { + if path_exists && !config.recursive { return Err(USimpleError::new( 1, format!("{}: File exists", path.display()), @@ -265,17 +248,9 @@ fn create_dir( return Ok(()); } - if recursive { + if config.recursive { match path.parent() { - Some(p) => create_dir( - p, - recursive, - verbose, - true, - mode, - set_selinux_context, - context, - )?, + Some(p) => create_dir(p, true, config)?, None => { USimpleError::new(1, "failed to create whole tree"); } @@ -284,7 +259,7 @@ fn create_dir( match std::fs::create_dir(path) { Ok(()) => { - if verbose { + if config.verbose { println!( "{}: created directory {}", uucore::util_name(), @@ -294,7 +269,7 @@ fn create_dir( #[cfg(all(unix, target_os = "linux"))] let new_mode = if path_exists { - mode + config.mode } else { // TODO: Make this macos and freebsd compatible by creating a function to get permission bits from // acl in extended attributes @@ -303,24 +278,24 @@ fn create_dir( if is_parent { (!mode::get_umask() & 0o777) | 0o300 | acl_perm_bits } else { - mode | acl_perm_bits + config.mode | acl_perm_bits } }; #[cfg(all(unix, not(target_os = "linux")))] let new_mode = if is_parent { (!mode::get_umask() & 0o777) | 0o300 } else { - mode + config.mode }; #[cfg(windows)] - let new_mode = mode; + let new_mode = config.mode; chmod(path, new_mode)?; // Apply SELinux context if requested - #[cfg(target_os = "linux")] - if set_selinux_context { - if let Err(e) = uucore::selinux_support::set_selinux_security_context(path, context) + #[cfg(feature = "selinux")] + if config.set_selinux_context && uucore::selinux::check_selinux_enabled().is_ok() { + if let Err(e) = uucore::selinux::set_selinux_security_context(path, config.context) { let _ = std::fs::remove_dir(path); return Err(USimpleError::new(