mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-31 13:07:46 +00:00
commit
f0e5c19ed4
2 changed files with 80 additions and 90 deletions
|
@ -1,5 +1,5 @@
|
||||||
#![crate_name = "mkdir"]
|
#![crate_name = "mkdir"]
|
||||||
#![feature(collections, core, old_io, old_path, rustc_private)]
|
#![feature(path_ext, rustc_private)]
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file is part of the uutils coreutils package.
|
* This file is part of the uutils coreutils package.
|
||||||
|
@ -13,9 +13,10 @@
|
||||||
extern crate getopts;
|
extern crate getopts;
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
|
||||||
use std::old_io::fs::{self, PathExtensions};
|
use std::ffi::CString;
|
||||||
use std::old_io::FilePermission;
|
use std::fs::{self, PathExt};
|
||||||
use std::num::from_str_radix;
|
use std::io::{Error, Write};
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
#[path = "../common/util.rs"]
|
#[path = "../common/util.rs"]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
@ -28,7 +29,6 @@ static VERSION: &'static str = "1.0.0";
|
||||||
* Handles option parsing
|
* Handles option parsing
|
||||||
*/
|
*/
|
||||||
pub fn uumain(args: Vec<String>) -> i32 {
|
pub fn uumain(args: Vec<String>) -> i32 {
|
||||||
|
|
||||||
let opts = [
|
let opts = [
|
||||||
// Linux-specific options, not implemented
|
// Linux-specific options, not implemented
|
||||||
// getopts::optflag("Z", "context", "set SELinux secutiry context" +
|
// getopts::optflag("Z", "context", "set SELinux secutiry context" +
|
||||||
|
@ -41,7 +41,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
||||||
getopts::optflag("V", "version", "display this version")
|
getopts::optflag("V", "version", "display this version")
|
||||||
];
|
];
|
||||||
|
|
||||||
let matches = match getopts::getopts(args.tail(), &opts) {
|
let matches = match getopts::getopts(&args[1..], &opts) {
|
||||||
Ok(m) => m,
|
Ok(m) => m,
|
||||||
Err(f) => {
|
Err(f) => {
|
||||||
crash!(1, "Invalid options\n{}", f);
|
crash!(1, "Invalid options\n{}", f);
|
||||||
|
@ -56,32 +56,29 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
||||||
println!("mkdir v{}", VERSION);
|
println!("mkdir v{}", VERSION);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
let verbose_flag = matches.opt_present("verbose");
|
let verbose = matches.opt_present("verbose");
|
||||||
let mk_parents = matches.opt_present("parents");
|
let recursive = matches.opt_present("parents");
|
||||||
|
|
||||||
// Translate a ~str in octal form to u32, default to 755
|
// Translate a ~str in octal form to u16, default to 755
|
||||||
// Not tested on Windows
|
// Not tested on Windows
|
||||||
let mode_match = matches.opts_str(&["mode".to_string()]);
|
let mode_match = matches.opts_str(&["mode".to_string()]);
|
||||||
let mode: FilePermission = if mode_match.is_some() {
|
let mode: u16 = if mode_match.is_some() {
|
||||||
let m = mode_match.unwrap();
|
let m = mode_match.unwrap();
|
||||||
let res: Option<u32> = from_str_radix(m.as_slice(), 8).ok();
|
let res: Option<u16> = u16::from_str_radix(&m, 8).ok();
|
||||||
if res.is_some() {
|
if res.is_some() {
|
||||||
unsafe { std::mem::transmute(res.unwrap()) }
|
unsafe { std::mem::transmute(res.unwrap()) }
|
||||||
} else {
|
} else {
|
||||||
crash!(1, "no mode given");
|
crash!(1, "no mode given");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
unsafe { std::mem::transmute(0o755 as u32) }
|
unsafe { std::mem::transmute(0o755 as u16) }
|
||||||
};
|
};
|
||||||
|
|
||||||
let dirs = matches.free;
|
let dirs = matches.free;
|
||||||
if dirs.is_empty() {
|
if dirs.is_empty() {
|
||||||
crash!(1, "missing operand");
|
crash!(1, "missing operand");
|
||||||
}
|
}
|
||||||
match exec(dirs, mk_parents, mode, verbose_flag) {
|
exec(dirs, recursive, mode, verbose)
|
||||||
Ok(()) => 0,
|
|
||||||
Err(e) => e
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_help(opts: &[getopts::OptGroup]) {
|
fn print_help(opts: &[getopts::OptGroup]) {
|
||||||
|
@ -94,68 +91,61 @@ fn print_help(opts: &[getopts::OptGroup]) {
|
||||||
/**
|
/**
|
||||||
* Create the list of new directories
|
* Create the list of new directories
|
||||||
*/
|
*/
|
||||||
fn exec(dirs: Vec<String>, mk_parents: bool, mode: FilePermission, verbose: bool) -> Result<(), i32> {
|
fn exec(dirs: Vec<String>, recursive: bool, mode: u16, verbose: bool) -> i32 {
|
||||||
let mut result = Ok(());
|
let mut status = 0;
|
||||||
|
let empty = Path::new("");
|
||||||
let mut parent_dirs = Vec::new();
|
for dir in dirs.iter() {
|
||||||
if mk_parents {
|
let path = Path::new(dir);
|
||||||
for dir in dirs.iter() {
|
if recursive {
|
||||||
let path = Path::new((*dir).clone());
|
let mut pathbuf = PathBuf::new();
|
||||||
// Build list of parent dirs which need to be created
|
for component in path.components() {
|
||||||
let parent = path.dirname_str();
|
pathbuf.push(component.as_os_str());
|
||||||
match parent {
|
status |= mkdir(pathbuf.as_path(), mode, verbose);
|
||||||
Some(p) => {
|
}
|
||||||
if !Path::new(p).exists() {
|
} else {
|
||||||
parent_dirs.push(p.to_string())
|
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 => ()
|
None => {
|
||||||
|
status |= mkdir(path, mode, verbose);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Recursively build parent dirs that are needed
|
status
|
||||||
if !parent_dirs.is_empty() {
|
|
||||||
match exec(parent_dirs, mk_parents, mode, verbose) {
|
|
||||||
Ok(()) => ( /* keep going */ ),
|
|
||||||
Err(e) => result = Err(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for dir in dirs.iter() {
|
|
||||||
let path = Path::new((*dir).clone());
|
|
||||||
// Determine if parent directory to the one to
|
|
||||||
// be created exists
|
|
||||||
let parent = match path.dirname_str() {
|
|
||||||
Some(p) => p,
|
|
||||||
None => ""
|
|
||||||
};
|
|
||||||
let parent_exists = Path::new(parent).exists();
|
|
||||||
if parent_exists && !path.exists() {
|
|
||||||
mkdir(&path, mode);
|
|
||||||
if verbose {println!("{}", *dir);}
|
|
||||||
} else if !mk_parents {
|
|
||||||
let error_msg =
|
|
||||||
if !parent_exists {
|
|
||||||
format!("parent directory '{}' does not exist", parent)
|
|
||||||
} else {
|
|
||||||
format!("directory '{}' already exists", *dir)
|
|
||||||
};
|
|
||||||
show_error!("{}", error_msg);
|
|
||||||
result = Err(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper to catch errors, return false if failed
|
* Wrapper to catch errors, return 1 if failed
|
||||||
*/
|
*/
|
||||||
fn mkdir(path: &Path, mode: FilePermission) {
|
fn mkdir(path: &Path, mode: u16, verbose: bool) -> i32 {
|
||||||
match fs::mkdir(path, mode) {
|
if path.exists() {
|
||||||
Ok(_) => {},
|
show_info!("cannot create directory '{}': File exists", path.display());
|
||||||
Err(e) => {
|
return 1;
|
||||||
crash!(1, "test {}", e.to_string());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,29 +1,34 @@
|
||||||
#![allow(unstable)]
|
#![feature(path_ext)]
|
||||||
|
|
||||||
use std::old_io::process::Command;
|
use std::fs::{remove_dir, PathExt};
|
||||||
use std::old_io::fs::{rmdir, PathExtensions};
|
use std::path::Path;
|
||||||
use std::borrow::ToOwned;
|
use std::process::{Command, Output};
|
||||||
|
|
||||||
static EXE: &'static str = "./mkdir";
|
static PROGNAME: &'static str = "./mkdir";
|
||||||
static TEST_DIR1: &'static str = "mkdir_test1";
|
static TEST_DIR1: &'static str = "mkdir_test1";
|
||||||
static TEST_DIR2: &'static str = "mkdir_test2";
|
static TEST_DIR2: &'static str = "mkdir_test2";
|
||||||
static TEST_DIR3: &'static str = "mkdir_test3";
|
static TEST_DIR3: &'static str = "mkdir_test3";
|
||||||
static TEST_DIR4: &'static str = "mkdir_test4/mkdir_test4_1";
|
static TEST_DIR4: &'static str = "mkdir_test4/mkdir_test4_1";
|
||||||
static TEST_DIR5: &'static str = "mkdir_test5/mkdir_test5_1";
|
static TEST_DIR5: &'static str = "mkdir_test5/mkdir_test5_1";
|
||||||
|
|
||||||
|
fn run(args: &[&'static str]) -> Output {
|
||||||
|
Command::new(PROGNAME)
|
||||||
|
.args(args)
|
||||||
|
.output()
|
||||||
|
.unwrap_or_else(|e| panic!("{}", e))
|
||||||
|
}
|
||||||
|
|
||||||
fn cleanup(dir: &'static str) {
|
fn cleanup(dir: &'static str) {
|
||||||
let d = dir.to_owned();
|
let p = Path::new(dir);
|
||||||
let p = Path::new(d.to_owned());
|
|
||||||
if p.exists() {
|
if p.exists() {
|
||||||
rmdir(&p).unwrap();
|
remove_dir(&p).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_mkdir_mkdir() {
|
fn test_mkdir_mkdir() {
|
||||||
cleanup(TEST_DIR1);
|
cleanup(TEST_DIR1);
|
||||||
let prog = Command::new(EXE).arg(TEST_DIR1).status();
|
let exit_success = run(&[TEST_DIR1]).status.success();
|
||||||
let exit_success = prog.unwrap().success();
|
|
||||||
cleanup(TEST_DIR1);
|
cleanup(TEST_DIR1);
|
||||||
assert_eq!(exit_success, true);
|
assert_eq!(exit_success, true);
|
||||||
}
|
}
|
||||||
|
@ -31,14 +36,12 @@ fn test_mkdir_mkdir() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_mkdir_dup_dir() {
|
fn test_mkdir_dup_dir() {
|
||||||
cleanup(TEST_DIR2);
|
cleanup(TEST_DIR2);
|
||||||
let prog = Command::new(EXE).arg(TEST_DIR2).status();
|
let exit_success = run(&[TEST_DIR2]).status.success();
|
||||||
let exit_success = prog.unwrap().success();
|
|
||||||
if !exit_success {
|
if !exit_success {
|
||||||
cleanup(TEST_DIR2);
|
cleanup(TEST_DIR2);
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
let prog2 = Command::new(EXE).arg(TEST_DIR2).status();
|
let exit_success2 = run(&[TEST_DIR2]).status.success();
|
||||||
let exit_success2 = prog2.unwrap().success();
|
|
||||||
cleanup(TEST_DIR2);
|
cleanup(TEST_DIR2);
|
||||||
assert_eq!(exit_success2, false);
|
assert_eq!(exit_success2, false);
|
||||||
}
|
}
|
||||||
|
@ -46,8 +49,7 @@ fn test_mkdir_dup_dir() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_mkdir_mode() {
|
fn test_mkdir_mode() {
|
||||||
cleanup(TEST_DIR3);
|
cleanup(TEST_DIR3);
|
||||||
let prog = Command::new(EXE).arg("-m").arg("755").arg(TEST_DIR3).status();
|
let exit_success = run(&["-m", "755", TEST_DIR3]).status.success();
|
||||||
let exit_success = prog.unwrap().success();
|
|
||||||
cleanup(TEST_DIR3);
|
cleanup(TEST_DIR3);
|
||||||
assert_eq!(exit_success, true);
|
assert_eq!(exit_success, true);
|
||||||
}
|
}
|
||||||
|
@ -55,8 +57,7 @@ fn test_mkdir_mode() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_mkdir_parent() {
|
fn test_mkdir_parent() {
|
||||||
cleanup(TEST_DIR4);
|
cleanup(TEST_DIR4);
|
||||||
let prog = Command::new(EXE).arg("-p").arg(TEST_DIR4).status();
|
let exit_success = run(&["-p", TEST_DIR4]).status.success();
|
||||||
let exit_success = prog.unwrap().success();
|
|
||||||
cleanup(TEST_DIR4);
|
cleanup(TEST_DIR4);
|
||||||
assert_eq!(exit_success, true);
|
assert_eq!(exit_success, true);
|
||||||
}
|
}
|
||||||
|
@ -64,8 +65,7 @@ fn test_mkdir_parent() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_mkdir_no_parent() {
|
fn test_mkdir_no_parent() {
|
||||||
cleanup(TEST_DIR5);
|
cleanup(TEST_DIR5);
|
||||||
let prog = Command::new(EXE).arg(TEST_DIR5).status();
|
let exit_success = run(&[TEST_DIR5]).status.success();
|
||||||
let exit_success = prog.unwrap().success();
|
|
||||||
cleanup(TEST_DIR5);
|
cleanup(TEST_DIR5);
|
||||||
assert_eq!(exit_success, false);
|
assert_eq!(exit_success, false);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue