Skip to content

Commit 192a495

Browse files
authored
Merge pull request #43 from rustcoreutils/mkdir
add util: mkdir
2 parents 971f074 + 25ac69c commit 192a495

File tree

3 files changed

+101
-1
lines changed

3 files changed

+101
-1
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ https://github.com/jgarzik/posixutils
107107
- [ ] make
108108
- [ ] man
109109
- [x] mesg
110-
- [ ] mkdir
110+
- [x] mkdir
111111
- [x] mkfifo
112112
- [ ] more
113113
- [x] mv

tree/Cargo.toml

+4
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ path = "src/link.rs"
3939
name = "ln"
4040
path = "src/ln.rs"
4141

42+
[[bin]]
43+
name = "mkdir"
44+
path = "src/mkdir.rs"
45+
4246
[[bin]]
4347
name = "mkfifo"
4448
path = "src/mkfifo.rs"

tree/src/mkdir.rs

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
//
2+
// Copyright (c) 2024 Jeff Garzik
3+
//
4+
// This file is part of the posixutils-rs project covered under
5+
// the MIT License. For the full license text, please see the LICENSE
6+
// file in the root directory of this project.
7+
// SPDX-License-Identifier: MIT
8+
//
9+
10+
extern crate clap;
11+
extern crate libc;
12+
extern crate plib;
13+
14+
use clap::Parser;
15+
use gettextrs::{bind_textdomain_codeset, textdomain};
16+
use modestr::ChmodMode;
17+
use plib::{modestr, PROJECT_NAME};
18+
use std::ffi::CString;
19+
use std::io;
20+
use std::path::PathBuf;
21+
22+
/// mkdir - make directories
23+
#[derive(Parser, Debug)]
24+
#[command(author, version, about, long_about)]
25+
struct Args {
26+
/// Create any missing intermediate pathname components.
27+
#[arg(short, long)]
28+
parents: bool,
29+
30+
/// Set the file permission bits of the newly-created directory to the specified mode value.
31+
#[arg(short, long)]
32+
mode: Option<String>,
33+
34+
/// A pathname of a directory to be created.
35+
dirs: Vec<String>,
36+
}
37+
38+
fn create_dir_with_mode(path: &str, mode: u32) -> io::Result<()> {
39+
let c_path = CString::new(path).expect("CString::new failed");
40+
let c_mode = mode as libc::mode_t;
41+
42+
let result = unsafe { libc::mkdir(c_path.as_ptr(), c_mode) };
43+
if result == 0 {
44+
Ok(())
45+
} else {
46+
Err(io::Error::last_os_error())
47+
}
48+
}
49+
50+
fn do_mkdir(dirname: &str, mode: &ChmodMode, parents: bool) -> io::Result<()> {
51+
let mode_val = match mode {
52+
ChmodMode::Absolute(mode) => *mode,
53+
ChmodMode::Symbolic(sym) => modestr::mutate(0o777, sym),
54+
};
55+
56+
if parents {
57+
let mut path = PathBuf::new();
58+
for part in dirname.split('/') {
59+
path.push(part);
60+
if path.is_dir() {
61+
continue;
62+
}
63+
create_dir_with_mode(&path.to_string_lossy(), mode_val)?;
64+
}
65+
} else {
66+
create_dir_with_mode(dirname, mode_val)?;
67+
}
68+
69+
Ok(())
70+
}
71+
72+
fn main() -> Result<(), Box<dyn std::error::Error>> {
73+
// parse command line arguments
74+
let args = Args::parse();
75+
76+
textdomain(PROJECT_NAME)?;
77+
bind_textdomain_codeset(PROJECT_NAME, "UTF-8")?;
78+
79+
let mut exit_code = 0;
80+
81+
// parse the mode string
82+
let mode = match args.mode {
83+
Some(mode) => modestr::parse(&mode)?,
84+
None => ChmodMode::Absolute(0o777),
85+
};
86+
87+
// apply the mode to each file
88+
for dirname in &args.dirs {
89+
if let Err(e) = do_mkdir(dirname, &mode, args.parents) {
90+
exit_code = 1;
91+
eprintln!("{}: {}", dirname, e);
92+
}
93+
}
94+
95+
std::process::exit(exit_code)
96+
}

0 commit comments

Comments
 (0)