diff --git a/src/uu/mkdir/src/mkdir.rs b/src/uu/mkdir/src/mkdir.rs index 82d561213..a99867570 100644 --- a/src/uu/mkdir/src/mkdir.rs +++ b/src/uu/mkdir/src/mkdir.rs @@ -8,25 +8,26 @@ #[macro_use] extern crate uucore; +use clap::OsValues; use clap::{crate_version, App, Arg}; use std::fs; use std::path::Path; +use uucore::error::{FromIo, UResult, USimpleError}; static ABOUT: &str = "Create the given DIRECTORY(ies) if they do not exist"; -static OPT_MODE: &str = "mode"; -static OPT_PARENTS: &str = "parents"; -static OPT_VERBOSE: &str = "verbose"; - -static ARG_DIRS: &str = "dirs"; +mod options { + pub const MODE: &str = "mode"; + pub const PARENTS: &str = "parents"; + pub const VERBOSE: &str = "verbose"; + pub const DIRS: &str = "dirs"; +} fn get_usage() -> String { format!("{0} [OPTION]... [USER]", executable!()) } -/** - * Handles option parsing - */ -pub fn uumain(args: impl uucore::Args) -> i32 { +#[uucore_procs::gen_uumain] +pub fn uumain(args: impl uucore::Args) -> UResult<()> { let usage = get_usage(); // Linux-specific options, not implemented @@ -34,26 +35,16 @@ pub fn uumain(args: impl uucore::Args) -> i32 { // " of each created directory to CTX"), let matches = uu_app().usage(&usage[..]).get_matches_from(args); - let dirs: Vec = matches - .values_of(ARG_DIRS) - .map(|v| v.map(ToString::to_string).collect()) - .unwrap_or_default(); - - let verbose = matches.is_present(OPT_VERBOSE); - let recursive = matches.is_present(OPT_PARENTS); + let dirs = matches.values_of_os(options::DIRS).unwrap_or_default(); + let verbose = matches.is_present(options::VERBOSE); + let recursive = matches.is_present(options::PARENTS); // Translate a ~str in octal form to u16, default to 755 // Not tested on Windows - let mode_match = matches.value_of(OPT_MODE); - let mode: u16 = match mode_match { - Some(m) => { - let res: Option = u16::from_str_radix(m, 8).ok(); - match res { - Some(r) => r, - _ => crash!(1, "no mode given"), - } - } - _ => 0o755_u16, + let mode: u16 = match matches.value_of(options::MODE) { + Some(m) => u16::from_str_radix(m, 8) + .map_err(|_| USimpleError::new(1, format!("invalid mode '{}'", m)))?, + None => 0o755_u16, }; exec(dirs, recursive, mode, verbose) @@ -64,27 +55,27 @@ pub fn uu_app() -> App<'static, 'static> { .version(crate_version!()) .about(ABOUT) .arg( - Arg::with_name(OPT_MODE) + Arg::with_name(options::MODE) .short("m") - .long(OPT_MODE) + .long(options::MODE) .help("set file mode (not implemented on windows)") .default_value("755"), ) .arg( - Arg::with_name(OPT_PARENTS) + Arg::with_name(options::PARENTS) .short("p") - .long(OPT_PARENTS) + .long(options::PARENTS) .alias("parent") .help("make parent directories as needed"), ) .arg( - Arg::with_name(OPT_VERBOSE) + Arg::with_name(options::VERBOSE) .short("v") - .long(OPT_VERBOSE) + .long(options::VERBOSE) .help("print a message for each printed directory"), ) .arg( - Arg::with_name(ARG_DIRS) + Arg::with_name(options::DIRS) .multiple(true) .takes_value(true) .min_values(1), @@ -94,64 +85,43 @@ pub fn uu_app() -> App<'static, 'static> { /** * Create the list of new directories */ -fn exec(dirs: Vec, recursive: bool, mode: u16, verbose: bool) -> i32 { - let mut status = 0; - let empty = Path::new(""); - for dir in &dirs { +fn exec(dirs: OsValues, recursive: bool, mode: u16, verbose: bool) -> UResult<()> { + for dir in dirs { let path = Path::new(dir); - if !recursive { - if let Some(parent) = path.parent() { - if parent != empty && !parent.exists() { - show_error!( - "cannot create directory '{}': No such file or directory", - path.display() - ); - status = 1; - continue; - } - } - } - status |= mkdir(path, recursive, mode, verbose); + show_if_err!(mkdir(path, recursive, mode, verbose)); } - status + Ok(()) } -/** - * Wrapper to catch errors, return 1 if failed - */ -fn mkdir(path: &Path, recursive: bool, mode: u16, verbose: bool) -> i32 { +fn mkdir(path: &Path, recursive: bool, mode: u16, verbose: bool) -> UResult<()> { let create_dir = if recursive { fs::create_dir_all } else { fs::create_dir }; - if let Err(e) = create_dir(path) { - show_error!("{}: {}", path.display(), e.to_string()); - return 1; - } + + create_dir(path).map_err_context(|| format!("cannot create directory '{}'", path.display()))?; if verbose { println!("{}: created directory '{}'", executable!(), path.display()); } - #[cfg(any(unix, target_os = "redox"))] - fn chmod(path: &Path, mode: u16) -> i32 { - use std::fs::{set_permissions, Permissions}; - use std::os::unix::fs::PermissionsExt; - - let mode = Permissions::from_mode(u32::from(mode)); - - if let Err(err) = set_permissions(path, mode) { - show_error!("{}: {}", path.display(), err); - return 1; - } - 0 - } - #[cfg(windows)] - #[allow(unused_variables)] - fn chmod(path: &Path, mode: u16) -> i32 { - // chmod on Windows only sets the readonly flag, which isn't even honored on directories - 0 - } chmod(path, mode) } + +#[cfg(any(unix, target_os = "redox"))] +fn chmod(path: &Path, mode: u16) -> UResult<()> { + use std::fs::{set_permissions, Permissions}; + use std::os::unix::fs::PermissionsExt; + + let mode = Permissions::from_mode(u32::from(mode)); + + set_permissions(path, mode) + .map_err_context(|| format!("cannot set permissions '{}'", path.display())) +} + +#[cfg(windows)] +fn chmod(_path: &Path, _mode: u16) -> UResult<()> { + // chmod on Windows only sets the readonly flag, which isn't even honored on directories + Ok(()) +}