2014-03-31 16:40:21 +00:00
|
|
|
#![crate_id(name="mkdir", vers="1.0.0", author="Nicholas Juszczak")]
|
2014-01-01 08:08:27 +00:00
|
|
|
|
2014-02-07 06:39:07 +00:00
|
|
|
/*
|
2014-01-01 08:08:27 +00:00
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2014-03-31 16:40:21 +00:00
|
|
|
#![feature(macro_rules)]
|
2014-02-07 06:39:07 +00:00
|
|
|
|
2014-02-16 21:29:31 +00:00
|
|
|
extern crate getopts;
|
2014-04-07 22:43:34 +00:00
|
|
|
extern crate libc;
|
2014-01-01 08:08:27 +00:00
|
|
|
|
2014-02-07 06:39:07 +00:00
|
|
|
use std::io::fs;
|
2014-05-07 06:25:49 +00:00
|
|
|
use std::io::FilePermission;
|
2014-01-03 23:32:39 +00:00
|
|
|
use std::num::strconv;
|
2014-01-01 08:08:27 +00:00
|
|
|
|
2014-02-23 22:17:48 +00:00
|
|
|
#[path = "../common/util.rs"]
|
2014-02-07 06:39:07 +00:00
|
|
|
mod util;
|
|
|
|
|
|
|
|
static NAME: &'static str = "mkdir";
|
2014-01-01 08:08:27 +00:00
|
|
|
static VERSION: &'static str = "1.0.0";
|
|
|
|
|
2014-01-03 23:32:39 +00:00
|
|
|
/**
|
|
|
|
* Handles option parsing
|
|
|
|
*/
|
2014-06-08 07:56:37 +00:00
|
|
|
pub fn uumain(args: Vec<String>) -> int {
|
2014-03-22 08:18:52 +00:00
|
|
|
|
2014-05-30 08:35:54 +00:00
|
|
|
let opts = [
|
2014-01-03 23:32:39 +00:00
|
|
|
// Linux-specific options, not implemented
|
2014-02-07 06:39:07 +00:00
|
|
|
// getopts::optflag("Z", "context", "set SELinux secutiry context" +
|
2014-01-01 23:32:21 +00:00
|
|
|
// " of each created directory to CTX"),
|
2014-02-07 06:39:07 +00:00
|
|
|
getopts::optopt("m", "mode", "set file mode", "755"),
|
|
|
|
getopts::optflag("p", "parents", "make parent directories as needed"),
|
|
|
|
getopts::optflag("v", "verbose",
|
2014-01-01 08:08:27 +00:00
|
|
|
"print a message for each printed directory"),
|
2014-02-07 06:39:07 +00:00
|
|
|
getopts::optflag("h", "help", "display this help"),
|
|
|
|
getopts::optflag("V", "version", "display this version")
|
2014-01-05 22:22:04 +00:00
|
|
|
];
|
2014-01-01 08:08:27 +00:00
|
|
|
|
2014-02-07 06:39:07 +00:00
|
|
|
let matches = match getopts::getopts(args.tail(), opts) {
|
2014-01-01 08:08:27 +00:00
|
|
|
Ok(m) => m,
|
|
|
|
Err(f) => {
|
2014-06-15 10:50:40 +00:00
|
|
|
crash!(1, "Invalid options\n{}", f);
|
2014-01-01 08:08:27 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-01-03 23:32:39 +00:00
|
|
|
if args.len() == 1 || matches.opt_present("help") {
|
2014-01-01 08:08:27 +00:00
|
|
|
print_help(opts);
|
2014-06-08 07:56:37 +00:00
|
|
|
return 0;
|
2014-01-01 08:08:27 +00:00
|
|
|
}
|
|
|
|
if matches.opt_present("version") {
|
2014-02-04 16:24:47 +00:00
|
|
|
println!("mkdir v{}", VERSION);
|
2014-06-08 07:56:37 +00:00
|
|
|
return 0;
|
2014-01-01 08:08:27 +00:00
|
|
|
}
|
2014-01-05 22:22:04 +00:00
|
|
|
let verbose_flag = matches.opt_present("verbose");
|
|
|
|
let mk_parents = matches.opt_present("parents");
|
2014-01-03 23:32:39 +00:00
|
|
|
|
|
|
|
// Translate a ~str in octal form to u32, default to 755
|
|
|
|
// Not tested on Windows
|
2014-05-28 06:33:39 +00:00
|
|
|
let mode_match = matches.opts_str(&["mode".to_string()]);
|
2014-05-07 06:25:49 +00:00
|
|
|
let mode: FilePermission = if mode_match.is_some() {
|
2014-01-05 22:22:04 +00:00
|
|
|
let m = mode_match.unwrap();
|
2014-05-17 10:32:14 +00:00
|
|
|
let res: Option<u32> = strconv::from_str_common(m.as_slice(), 8, false, false, false,
|
2014-05-07 06:25:49 +00:00
|
|
|
strconv::ExpNone,
|
|
|
|
false, false);
|
2014-01-03 23:32:39 +00:00
|
|
|
if res.is_some() {
|
2014-05-16 09:03:19 +00:00
|
|
|
unsafe { std::mem::transmute(res.unwrap()) }
|
2014-01-03 23:32:39 +00:00
|
|
|
} else {
|
2014-02-07 06:39:07 +00:00
|
|
|
crash!(1, "no mode given");
|
2014-01-03 23:32:39 +00:00
|
|
|
}
|
|
|
|
} else {
|
2014-05-16 09:03:19 +00:00
|
|
|
unsafe { std::mem::transmute(0o755 as u32) }
|
2014-01-03 23:32:39 +00:00
|
|
|
};
|
|
|
|
|
2014-01-05 22:22:04 +00:00
|
|
|
let dirs = matches.free;
|
2014-05-18 10:15:49 +00:00
|
|
|
if dirs.is_empty() {
|
|
|
|
crash!(1, "missing operand");
|
|
|
|
}
|
2014-06-08 08:37:02 +00:00
|
|
|
match exec(dirs, mk_parents, mode, verbose_flag) {
|
2014-06-12 04:41:53 +00:00
|
|
|
Ok(()) => 0,
|
|
|
|
Err(e) => e
|
2014-06-08 08:37:02 +00:00
|
|
|
}
|
2014-01-01 08:08:27 +00:00
|
|
|
}
|
|
|
|
|
2014-02-07 06:39:07 +00:00
|
|
|
fn print_help(opts: &[getopts::OptGroup]) {
|
2014-01-01 23:32:21 +00:00
|
|
|
println!("mkdir v{} - make a new directory with the given path", VERSION);
|
2014-02-04 16:24:47 +00:00
|
|
|
println!("");
|
|
|
|
println!("Usage:");
|
2014-05-23 12:28:40 +00:00
|
|
|
print!("{}", getopts::usage("Create the given DIRECTORY(ies) if they do not exist", opts));
|
2014-01-01 08:08:27 +00:00
|
|
|
}
|
|
|
|
|
2014-01-03 23:32:39 +00:00
|
|
|
/**
|
|
|
|
* Create the list of new directories
|
|
|
|
*/
|
2014-06-08 08:37:02 +00:00
|
|
|
fn exec(dirs: Vec<String>, mk_parents: bool, mode: FilePermission, verbose: bool) -> Result<(), int> {
|
2014-06-10 05:30:54 +00:00
|
|
|
let mut result = Ok(());
|
|
|
|
|
2014-03-22 08:18:52 +00:00
|
|
|
let mut parent_dirs = Vec::new();
|
2014-01-05 22:03:13 +00:00
|
|
|
if mk_parents {
|
|
|
|
for dir in dirs.iter() {
|
|
|
|
let path = Path::new((*dir).clone());
|
|
|
|
// Build list of parent dirs which need to be created
|
|
|
|
let parent = path.dirname_str();
|
|
|
|
match parent {
|
|
|
|
Some(p) => {
|
|
|
|
if !Path::new(p).exists() {
|
2014-05-28 06:33:39 +00:00
|
|
|
parent_dirs.push(p.to_string())
|
2014-01-05 22:03:13 +00:00
|
|
|
}
|
2014-01-01 23:32:21 +00:00
|
|
|
},
|
|
|
|
None => ()
|
|
|
|
}
|
|
|
|
}
|
2014-01-03 23:32:39 +00:00
|
|
|
}
|
|
|
|
// Recursively build parent dirs that are needed
|
|
|
|
if !parent_dirs.is_empty() {
|
2014-06-08 08:37:02 +00:00
|
|
|
match exec(parent_dirs, mk_parents, mode, verbose) {
|
|
|
|
Ok(()) => ( /* keep going */ ),
|
2014-06-10 05:30:54 +00:00
|
|
|
Err(e) => result = Err(e)
|
2014-06-08 08:37:02 +00:00
|
|
|
}
|
2014-01-03 23:32:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for dir in dirs.iter() {
|
|
|
|
let path = Path::new((*dir).clone());
|
|
|
|
// Determine if parent directory to the one to
|
|
|
|
// be created exists
|
2014-01-05 22:22:04 +00:00
|
|
|
let parent = match path.dirname_str() {
|
2014-01-03 23:32:39 +00:00
|
|
|
Some(p) => p,
|
|
|
|
None => ""
|
|
|
|
};
|
2014-01-05 22:22:04 +00:00
|
|
|
let parent_exists = Path::new(parent).exists();
|
2014-01-03 23:32:39 +00:00
|
|
|
if parent_exists && !path.exists() {
|
2014-02-07 06:39:07 +00:00
|
|
|
mkdir(&path, mode);
|
2014-02-04 16:24:47 +00:00
|
|
|
if verbose {println!("{}", *dir);}
|
2014-02-28 21:35:21 +00:00
|
|
|
} else if !mk_parents {
|
2014-04-26 05:03:08 +00:00
|
|
|
let error_msg =
|
|
|
|
if !parent_exists {
|
|
|
|
format!("parent directory '{}' does not exist", parent)
|
|
|
|
} else {
|
|
|
|
format!("directory '{}' already exists", *dir)
|
|
|
|
};
|
2014-06-09 03:26:51 +00:00
|
|
|
show_error!("{}", error_msg);
|
2014-06-10 05:30:54 +00:00
|
|
|
result = Err(1)
|
2014-01-03 23:32:39 +00:00
|
|
|
}
|
|
|
|
}
|
2014-06-08 08:37:02 +00:00
|
|
|
|
2014-06-12 04:41:53 +00:00
|
|
|
result
|
2014-01-03 23:32:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Wrapper to catch errors, return false if failed
|
|
|
|
*/
|
2014-05-07 06:25:49 +00:00
|
|
|
fn mkdir(path: &Path, mode: FilePermission) {
|
2014-02-05 03:39:17 +00:00
|
|
|
match fs::mkdir(path, mode) {
|
2014-02-07 06:39:07 +00:00
|
|
|
Ok(_) => {},
|
2014-01-03 23:32:39 +00:00
|
|
|
Err(e) => {
|
2014-02-07 06:39:07 +00:00
|
|
|
crash!(1, "test {}", e.to_str());
|
2014-01-01 23:32:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|