#![crate_name = "mkdir"] #![feature(path_ext)] /* * This file is part of the uutils coreutils package. * * (c) Nicholas Juszczak * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ extern crate getopts; extern crate libc; use std::ffi::CString; use std::fs::{self, PathExt}; use std::io::{Error, Write}; use std::path::{Path, PathBuf}; #[path = "../common/util.rs"] #[macro_use] mod util; static NAME: &'static str = "mkdir"; static VERSION: &'static str = "1.0.0"; /** * Handles option parsing */ pub fn uumain(args: Vec) -> i32 { let mut opts = getopts::Options::new(); // Linux-specific options, not implemented // opts.optflag("Z", "context", "set SELinux secutiry context" + // " of each created directory to CTX"), opts.optopt("m", "mode", "set file mode", "755"); opts.optflag("p", "parents", "make parent directories as needed"); opts.optflag("v", "verbose", "print a message for each printed directory"); opts.optflag("h", "help", "display this help"); opts.optflag("V", "version", "display this version"); let matches = match opts.parse(&args[1..]) { Ok(m) => m, Err(f) => crash!(1, "Invalid options\n{}", f) }; if args.len() == 1 || matches.opt_present("help") { print_help(&opts); return 0; } if matches.opt_present("version") { println!("{} v{}", NAME, VERSION); return 0; } let verbose = matches.opt_present("verbose"); let recursive = matches.opt_present("parents"); // Translate a ~str in octal form to u16, default to 755 // Not tested on Windows let mode_match = matches.opts_str(&["mode".to_string()]); let mode: u16 = if mode_match.is_some() { let m = mode_match.unwrap(); let res: Option = u16::from_str_radix(&m, 8).ok(); if res.is_some() { unsafe { std::mem::transmute(res.unwrap()) } } else { crash!(1, "no mode given"); } } else { unsafe { std::mem::transmute(0o755 as u16) } }; let dirs = matches.free; if dirs.is_empty() { crash!(1, "missing operand"); } exec(dirs, recursive, mode, verbose) } fn print_help(opts: &getopts::Options) { println!("{} v{} - make a new directory with the given path", NAME, VERSION); println!(""); println!("Usage:"); print!("{}", opts.usage("Create the given DIRECTORY(ies) if they do not exist")); } /** * 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.iter() { let path = Path::new(dir); if recursive { let mut pathbuf = PathBuf::new(); for component in path.components() { pathbuf.push(component.as_os_str()); status |= mkdir(pathbuf.as_path(), mode, verbose); } } else { match path.parent() { Some(parent) => { if parent != empty && !parent.exists() { show_info!("cannot create directory '{}': No such file or directory", path.display()); status = 1; } else { status |= mkdir(path, mode, verbose); } }, None => { status |= mkdir(path, mode, verbose); } } } } status } /** * Wrapper to catch errors, return 1 if failed */ fn mkdir(path: &Path, mode: u16, verbose: bool) -> i32 { if path.exists() { show_info!("cannot create directory '{}': File exists", path.display()); return 1; } if let Err(e) = fs::create_dir(path) { show_info!("{}: {}", path.display(), e.to_string()); return 1; } if verbose { show_info!("created directory '{}'", path.display()); } let directory = CString::new(path.as_os_str().to_str().unwrap()).unwrap_or_else(|e| crash!(1, "{}", e)); let mode = mode as libc::mode_t; if unsafe { libc::chmod(directory.as_ptr(), mode) } != 0 { show_info!("{}: errno {}", path.display(), Error::last_os_error().raw_os_error().unwrap()); return 1; } 0 }