Skip to content

Commit

Permalink
Merge branch 'main' into split-b-chunk
Browse files Browse the repository at this point in the history
  • Loading branch information
zhitkoff committed Nov 9, 2023
2 parents e7dd254 + 6fa8a6d commit c024b1f
Show file tree
Hide file tree
Showing 9 changed files with 429 additions and 194 deletions.
1 change: 1 addition & 0 deletions .vscode/cspell.dictionaries/workspace.wordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ clippy
rustc
rustfmt
rustup
rustdoc
#
bitor # BitOr trait function
bitxor # BitXor trait function
Expand Down
376 changes: 266 additions & 110 deletions CONTRIBUTING.md

Large diffs are not rendered by default.

108 changes: 57 additions & 51 deletions src/uu/du/src/du.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,11 @@ use std::time::{Duration, UNIX_EPOCH};
use std::{error::Error, fmt::Display};
use uucore::display::{print_verbatim, Quotable};
use uucore::error::FromIo;
use uucore::error::{set_exit_code, UError, UResult};
use uucore::error::{set_exit_code, UError, UResult, USimpleError};
use uucore::line_ending::LineEnding;
use uucore::parse_glob;
use uucore::parse_size::{parse_size_u64, ParseSizeError};
use uucore::{
crash, format_usage, help_about, help_section, help_usage, show, show_error, show_warning,
};
use uucore::{format_usage, help_about, help_section, help_usage, show, show_error, show_warning};
#[cfg(windows)]
use windows_sys::Win32::Foundation::HANDLE;
#[cfg(windows)]
Expand Down Expand Up @@ -137,39 +135,42 @@ impl Stat {
}?;

#[cfg(not(windows))]
let file_info = FileInfo {
file_id: metadata.ino() as u128,
dev_id: metadata.dev(),
};
#[cfg(not(windows))]
return Ok(Self {
path: path.to_path_buf(),
is_dir: metadata.is_dir(),
size: if path.is_dir() { 0 } else { metadata.len() },
blocks: metadata.blocks(),
inodes: 1,
inode: Some(file_info),
created: birth_u64(&metadata),
accessed: metadata.atime() as u64,
modified: metadata.mtime() as u64,
});
{
let file_info = FileInfo {
file_id: metadata.ino() as u128,
dev_id: metadata.dev(),
};

Ok(Self {
path: path.to_path_buf(),
is_dir: metadata.is_dir(),
size: if path.is_dir() { 0 } else { metadata.len() },
blocks: metadata.blocks(),
inodes: 1,
inode: Some(file_info),
created: birth_u64(&metadata),
accessed: metadata.atime() as u64,
modified: metadata.mtime() as u64,
})
}

#[cfg(windows)]
let size_on_disk = get_size_on_disk(path);
#[cfg(windows)]
let file_info = get_file_info(path);
#[cfg(windows)]
Ok(Self {
path: path.to_path_buf(),
is_dir: metadata.is_dir(),
size: if path.is_dir() { 0 } else { metadata.len() },
blocks: size_on_disk / 1024 * 2,
inode: file_info,
inodes: 1,
created: windows_creation_time_to_unix_time(metadata.creation_time()),
accessed: windows_time_to_unix_time(metadata.last_access_time()),
modified: windows_time_to_unix_time(metadata.last_write_time()),
})
{
let size_on_disk = get_size_on_disk(path);
let file_info = get_file_info(path);

Ok(Self {
path: path.to_path_buf(),
is_dir: metadata.is_dir(),
size: if path.is_dir() { 0 } else { metadata.len() },
blocks: size_on_disk / 1024 * 2,
inodes: 1,
inode: file_info,
created: windows_creation_time_to_unix_time(metadata.creation_time()),
accessed: windows_time_to_unix_time(metadata.last_access_time()),
modified: windows_time_to_unix_time(metadata.last_write_time()),
})
}
}
}

Expand Down Expand Up @@ -255,22 +256,22 @@ fn get_file_info(path: &Path) -> Option<FileInfo> {
result
}

fn read_block_size(s: Option<&str>) -> u64 {
fn read_block_size(s: Option<&str>) -> UResult<u64> {
if let Some(s) = s {
parse_size_u64(s)
.unwrap_or_else(|e| crash!(1, "{}", format_error_message(&e, s, options::BLOCK_SIZE)))
.map_err(|e| USimpleError::new(1, format_error_message(&e, s, options::BLOCK_SIZE)))
} else {
for env_var in ["DU_BLOCK_SIZE", "BLOCK_SIZE", "BLOCKSIZE"] {
if let Ok(env_size) = env::var(env_var) {
if let Ok(v) = parse_size_u64(&env_size) {
return v;
return Ok(v);
}
}
}
if env::var("POSIXLY_CORRECT").is_ok() {
512
Ok(512)
} else {
1024
Ok(1024)
}
}
}
Expand Down Expand Up @@ -574,12 +575,20 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
matches
.get_one::<String>(options::BLOCK_SIZE)
.map(|s| s.as_str()),
);
)?;

let threshold = matches.get_one::<String>(options::THRESHOLD).map(|s| {
Threshold::from_str(s)
.unwrap_or_else(|e| crash!(1, "{}", format_error_message(&e, s, options::THRESHOLD)))
});
let threshold = match matches.get_one::<String>(options::THRESHOLD) {
Some(s) => match Threshold::from_str(s) {
Ok(t) => Some(t),
Err(e) => {
return Err(USimpleError::new(
1,
format_error_message(&e, s, options::THRESHOLD),
))
}
},
None => None,
};

let multiplier: u64 = if matches.get_flag(options::SI) {
1000
Expand Down Expand Up @@ -821,6 +830,7 @@ pub fn uu_app() -> Command {
.arg(
Arg::new(options::DEREFERENCE_ARGS)
.short('D')
.visible_short_alias('H')
.long(options::DEREFERENCE_ARGS)
.help("follow only symlinks that are listed on the command line")
.action(ArgAction::SetTrue)
Expand Down Expand Up @@ -991,13 +1001,9 @@ mod test_du {

#[test]
fn test_read_block_size() {
let test_data = [
(Some("1024".to_string()), 1024),
(Some("K".to_string()), 1024),
(None, 1024),
];
let test_data = [Some("1024".to_string()), Some("K".to_string()), None];
for it in &test_data {
assert_eq!(read_block_size(it.0.as_deref()), it.1);
assert!(matches!(read_block_size(it.as_deref()), Ok(1024)));
}
}
}
58 changes: 40 additions & 18 deletions src/uu/mktemp/src/mktemp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,29 +115,30 @@ impl Display for MkTempError {
/// This provides a layer of indirection between the application logic
/// and the argument parsing library `clap`, allowing each to vary
/// independently.
struct Options {
#[derive(Clone)]
pub struct Options {
/// Whether to create a temporary directory instead of a file.
directory: bool,
pub directory: bool,

/// Whether to just print the name of a file that would have been created.
dry_run: bool,
pub dry_run: bool,

/// Whether to suppress file creation error messages.
quiet: bool,
pub quiet: bool,

/// The directory in which to create the temporary file.
///
/// If `None`, the file will be created in the current directory.
tmpdir: Option<PathBuf>,
pub tmpdir: Option<PathBuf>,

/// The suffix to append to the temporary file, if any.
suffix: Option<String>,
pub suffix: Option<String>,

/// Whether to treat the template argument as a single file path component.
treat_as_template: bool,
pub treat_as_template: bool,

/// The template to use for the name of the temporary file.
template: String,
pub template: String,
}

impl Options {
Expand Down Expand Up @@ -192,7 +193,7 @@ impl Options {
/// `num_rand_chars`.
struct Params {
/// The directory that will contain the temporary file.
directory: String,
directory: PathBuf,

/// The (non-random) prefix of the temporary file.
prefix: String,
Expand Down Expand Up @@ -297,7 +298,7 @@ impl Params {
let num_rand_chars = j - i;

Ok(Self {
directory,
directory: directory.into(),
prefix,
num_rand_chars,
suffix,
Expand Down Expand Up @@ -357,12 +358,13 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
exec(&tmpdir, &prefix, rand, &suffix, make_dir)
};

if suppress_file_err {
let res = if suppress_file_err {
// Mapping all UErrors to ExitCodes prevents the errors from being printed
res.map_err(|e| e.code().into())
} else {
res
}
};
println_verbatim(res?).map_err_context(|| "failed to print directory name".to_owned())
}

pub fn uu_app() -> Command {
Expand Down Expand Up @@ -441,7 +443,7 @@ pub fn uu_app() -> Command {
.arg(Arg::new(ARG_TEMPLATE).num_args(..=1))
}

pub fn dry_exec(tmpdir: &str, prefix: &str, rand: usize, suffix: &str) -> UResult<()> {
fn dry_exec(tmpdir: &Path, prefix: &str, rand: usize, suffix: &str) -> UResult<PathBuf> {
let len = prefix.len() + suffix.len() + rand;
let mut buf = Vec::with_capacity(len);
buf.extend(prefix.as_bytes());
Expand All @@ -462,7 +464,7 @@ pub fn dry_exec(tmpdir: &str, prefix: &str, rand: usize, suffix: &str) -> UResul
// We guarantee utf8.
let buf = String::from_utf8(buf).unwrap();
let tmpdir = Path::new(tmpdir).join(buf);
println_verbatim(tmpdir).map_err_context(|| "failed to print directory name".to_owned())
Ok(tmpdir)
}

/// Create a temporary directory with the given parameters.
Expand All @@ -476,7 +478,7 @@ pub fn dry_exec(tmpdir: &str, prefix: &str, rand: usize, suffix: &str) -> UResul
///
/// If the temporary directory could not be written to disk or if the
/// given directory `dir` does not exist.
fn make_temp_dir(dir: &str, prefix: &str, rand: usize, suffix: &str) -> UResult<PathBuf> {
fn make_temp_dir(dir: &Path, prefix: &str, rand: usize, suffix: &str) -> UResult<PathBuf> {
let mut builder = Builder::new();
builder.prefix(prefix).rand_bytes(rand).suffix(suffix);
match builder.tempdir_in(dir) {
Expand Down Expand Up @@ -508,7 +510,7 @@ fn make_temp_dir(dir: &str, prefix: &str, rand: usize, suffix: &str) -> UResult<
///
/// If the file could not be written to disk or if the directory does
/// not exist.
fn make_temp_file(dir: &str, prefix: &str, rand: usize, suffix: &str) -> UResult<PathBuf> {
fn make_temp_file(dir: &Path, prefix: &str, rand: usize, suffix: &str) -> UResult<PathBuf> {
let mut builder = Builder::new();
builder.prefix(prefix).rand_bytes(rand).suffix(suffix);
match builder.tempfile_in(dir) {
Expand All @@ -527,7 +529,7 @@ fn make_temp_file(dir: &str, prefix: &str, rand: usize, suffix: &str) -> UResult
}
}

fn exec(dir: &str, prefix: &str, rand: usize, suffix: &str, make_dir: bool) -> UResult<()> {
fn exec(dir: &Path, prefix: &str, rand: usize, suffix: &str, make_dir: bool) -> UResult<PathBuf> {
let path = if make_dir {
make_temp_dir(dir, prefix, rand, suffix)?
} else {
Expand All @@ -546,7 +548,27 @@ fn exec(dir: &str, prefix: &str, rand: usize, suffix: &str, make_dir: bool) -> U
// relative path.
let path = Path::new(dir).join(filename);

println_verbatim(path).map_err_context(|| "failed to print directory name".to_owned())
Ok(path)
}

/// Create a temporary file or directory
///
/// Behavior is determined by the `options` parameter, see [`Options`] for details.
pub fn mktemp(options: &Options) -> UResult<PathBuf> {
// Parse file path parameters from the command-line options.
let Params {
directory: tmpdir,
prefix,
num_rand_chars: rand,
suffix,
} = Params::from(options.clone())?;

// Create the temporary file or directory, or simulate creating it.
if options.dry_run {
dry_exec(&tmpdir, &prefix, rand, &suffix)
} else {
exec(&tmpdir, &prefix, rand, &suffix, options.directory)
}
}

#[cfg(test)]
Expand Down
8 changes: 8 additions & 0 deletions src/uu/printf/printf.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ Fields
second parameter is min-width, integer
output below that width is padded with leading zeroes

* `%q`: ARGUMENT is printed in a format that can be reused as shell input, escaping non-printable
characters with the proposed POSIX $'' syntax.

* `%f` or `%F`: decimal floating point value
* `%e` or `%E`: scientific notation floating point value
* `%g` or `%G`: shorter of specially interpreted decimal or SciNote floating point value.
Expand Down Expand Up @@ -181,6 +184,11 @@ All string fields have a 'max width' parameter
still be interpreted and not throw a warning, you will have problems if you use this for a
literal whose code begins with zero, as it will be viewed as in `\\0NNN` form.)

* `%q`: escaped string - the string in a format that can be reused as input by most shells.
Non-printable characters are escaped with the POSIX proposed ‘$''’ syntax,
and shell meta-characters are quoted appropriately.
This is an equivalent format to ls --quoting=shell-escape output.

#### CHAR SUBSTITUTIONS

The character field does not have a secondary parameter.
Expand Down
Loading

0 comments on commit c024b1f

Please sign in to comment.