coreutils/src/mkdir/mkdir.rs
Joseph Crail 496d5883a4 Switch to external getopts cargo (part 3).
I switched over to the getopts crate on crates.io, instead of Rust's
private implementation. This will allow coreutils to build for Rust 1.0.

I'm splitting the updates into several commits for easier reviewing.
2015-05-21 21:32:55 -04:00

148 lines
4.3 KiB
Rust

#![crate_name = "mkdir"]
#![feature(path_ext)]
/*
* This file is part of the uutils coreutils package.
*
* (c) Nicholas Juszczak <juszczakn@gmail.com>
*
* 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<String>) -> 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> = 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<String>, 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
}