Skip to content

Commit

Permalink
Merge branch 'main' into issue-5766
Browse files Browse the repository at this point in the history
  • Loading branch information
sylvestre authored Jan 6, 2024
2 parents 32f0256 + c867d6b commit b309d64
Show file tree
Hide file tree
Showing 14 changed files with 435 additions and 94 deletions.
13 changes: 11 additions & 2 deletions src/uu/cp/src/copydir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ use std::path::{Path, PathBuf, StripPrefixError};
use indicatif::ProgressBar;
use uucore::display::Quotable;
use uucore::error::UIoError;
use uucore::fs::{canonicalize, FileInformation, MissingHandling, ResolveMode};
use uucore::fs::{
canonicalize, path_ends_with_terminator, FileInformation, MissingHandling, ResolveMode,
};
use uucore::show;
use uucore::show_error;
use uucore::uio_error;
Expand Down Expand Up @@ -170,7 +172,14 @@ impl Entry {
let mut descendant =
get_local_to_root_parent(&source_absolute, context.root_parent.as_deref())?;
if no_target_dir {
descendant = descendant.strip_prefix(context.root)?.to_path_buf();
let source_is_dir = direntry.path().is_dir();
if path_ends_with_terminator(context.target) && source_is_dir {
if let Err(e) = std::fs::create_dir_all(context.target) {
eprintln!("Failed to create directory: {}", e);
}
} else {
descendant = descendant.strip_prefix(context.root)?.to_path_buf();
}
}

let local_to_target = context.target.join(descendant);
Expand Down
8 changes: 6 additions & 2 deletions src/uu/cp/src/cp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ use platform::copy_on_write;
use uucore::display::Quotable;
use uucore::error::{set_exit_code, UClapError, UError, UResult, UUsageError};
use uucore::fs::{
are_hardlinks_to_same_file, canonicalize, is_symlink_loop, paths_refer_to_same_file,
FileInformation, MissingHandling, ResolveMode,
are_hardlinks_to_same_file, canonicalize, is_symlink_loop, path_ends_with_terminator,
paths_refer_to_same_file, FileInformation, MissingHandling, ResolveMode,
};
use uucore::{backup_control, update_control};
// These are exposed for projects (e.g. nushell) that want to create an `Options` value, which
Expand Down Expand Up @@ -1994,6 +1994,10 @@ fn copy_helper(
fs::create_dir_all(parent)?;
}

if path_ends_with_terminator(dest) && !dest.is_dir() {
return Err(Error::NotADirectory(dest.to_path_buf()));
}

if source.as_os_str() == "/dev/null" {
/* workaround a limitation of fs::copy
* https://github.com/rust-lang/rust/issues/79390
Expand Down
110 changes: 72 additions & 38 deletions src/uu/ls/src/ls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -621,7 +621,52 @@ fn extract_hyperlink(options: &clap::ArgMatches) -> bool {
}
}

/// Match the argument given to --quoting-style or the QUOTING_STYLE env variable.
///
/// # Arguments
///
/// * `style`: the actual argument string
/// * `show_control` - A boolean value representing whether or not to show control characters.
///
/// # Returns
///
/// * An option with None if the style string is invalid, or a `QuotingStyle` wrapped in `Some`.
fn match_quoting_style_name(style: &str, show_control: bool) -> Option<QuotingStyle> {
match style {
"literal" => Some(QuotingStyle::Literal { show_control }),
"shell" => Some(QuotingStyle::Shell {
escape: false,
always_quote: false,
show_control,
}),
"shell-always" => Some(QuotingStyle::Shell {
escape: false,
always_quote: true,
show_control,
}),
"shell-escape" => Some(QuotingStyle::Shell {
escape: true,
always_quote: false,
show_control,
}),
"shell-escape-always" => Some(QuotingStyle::Shell {
escape: true,
always_quote: true,
show_control,
}),
"c" => Some(QuotingStyle::C {
quotes: quoting_style::Quotes::Double,
}),
"escape" => Some(QuotingStyle::C {
quotes: quoting_style::Quotes::None,
}),
_ => None,
}
}

/// Extracts the quoting style to use based on the options provided.
/// If no options are given, it looks if a default quoting style is provided
/// through the QUOTING_STYLE environment variable.
///
/// # Arguments
///
Expand All @@ -632,38 +677,12 @@ fn extract_hyperlink(options: &clap::ArgMatches) -> bool {
///
/// A QuotingStyle variant representing the quoting style to use.
fn extract_quoting_style(options: &clap::ArgMatches, show_control: bool) -> QuotingStyle {
let opt_quoting_style = options.get_one::<String>(options::QUOTING_STYLE).cloned();
let opt_quoting_style = options.get_one::<String>(options::QUOTING_STYLE);

if let Some(style) = opt_quoting_style {
match style.as_str() {
"literal" => QuotingStyle::Literal { show_control },
"shell" => QuotingStyle::Shell {
escape: false,
always_quote: false,
show_control,
},
"shell-always" => QuotingStyle::Shell {
escape: false,
always_quote: true,
show_control,
},
"shell-escape" => QuotingStyle::Shell {
escape: true,
always_quote: false,
show_control,
},
"shell-escape-always" => QuotingStyle::Shell {
escape: true,
always_quote: true,
show_control,
},
"c" => QuotingStyle::C {
quotes: quoting_style::Quotes::Double,
},
"escape" => QuotingStyle::C {
quotes: quoting_style::Quotes::None,
},
_ => unreachable!("Should have been caught by Clap"),
match match_quoting_style_name(style, show_control) {
Some(qs) => qs,
None => unreachable!("Should have been caught by Clap"),
}
} else if options.get_flag(options::quoting::LITERAL) {
QuotingStyle::Literal { show_control }
Expand All @@ -675,16 +694,31 @@ fn extract_quoting_style(options: &clap::ArgMatches, show_control: bool) -> Quot
QuotingStyle::C {
quotes: quoting_style::Quotes::Double,
}
} else if options.get_flag(options::DIRED) || !std::io::stdout().is_terminal() {
// By default, `ls` uses Literal quoting when
// writing to a non-terminal file descriptor
} else if options.get_flag(options::DIRED) {
QuotingStyle::Literal { show_control }
} else {
// TODO: use environment variable if available
QuotingStyle::Shell {
escape: true,
always_quote: false,
show_control,
// If set, the QUOTING_STYLE environment variable specifies a default style.
if let Ok(style) = std::env::var("QUOTING_STYLE") {
match match_quoting_style_name(style.as_str(), show_control) {
Some(qs) => return qs,
None => eprintln!(
"{}: Ignoring invalid value of environment variable QUOTING_STYLE: '{}'",
std::env::args().next().unwrap_or("ls".to_string()),
style
),
}
}

// By default, `ls` uses Shell escape quoting style when writing to a terminal file
// descriptor and Literal otherwise.
if std::io::stdout().is_terminal() {
QuotingStyle::Shell {
escape: true,
always_quote: false,
show_control,
}
} else {
QuotingStyle::Literal { show_control }
}
}
}
Expand Down
27 changes: 6 additions & 21 deletions src/uu/mv/src/mv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ use std::path::{Path, PathBuf};
use uucore::backup_control::{self, source_is_target_backup};
use uucore::display::Quotable;
use uucore::error::{set_exit_code, FromIo, UResult, USimpleError, UUsageError};
use uucore::fs::{are_hardlinks_or_one_way_symlink_to_same_file, are_hardlinks_to_same_file};
use uucore::fs::{
are_hardlinks_or_one_way_symlink_to_same_file, are_hardlinks_to_same_file,
path_ends_with_terminator,
};
use uucore::update_control;
// These are exposed for projects (e.g. nushell) that want to create an `Options` value, which
// requires these enums
Expand Down Expand Up @@ -104,25 +107,6 @@ static OPT_VERBOSE: &str = "verbose";
static OPT_PROGRESS: &str = "progress";
static ARG_FILES: &str = "files";

/// Returns true if the passed `path` ends with a path terminator.
#[cfg(unix)]
fn path_ends_with_terminator(path: &Path) -> bool {
use std::os::unix::prelude::OsStrExt;
path.as_os_str()
.as_bytes()
.last()
.map_or(false, |&byte| byte == b'/' || byte == b'\\')
}

#[cfg(windows)]
fn path_ends_with_terminator(path: &Path) -> bool {
use std::os::windows::prelude::OsStrExt;
path.as_os_str()
.encode_wide()
.last()
.map_or(false, |wide| wide == b'/'.into() || wide == b'\\'.into())
}

#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let mut app = uu_app();
Expand Down Expand Up @@ -335,9 +319,10 @@ fn handle_two_paths(source: &Path, target: &Path, opts: &Options) -> UResult<()>
}

let target_is_dir = target.is_dir();
let source_is_dir = source.is_dir();

if path_ends_with_terminator(target)
&& !target_is_dir
&& (!target_is_dir && !source_is_dir)
&& !opts.no_target_dir
&& opts.update != UpdateMode::ReplaceIfOlder
{
Expand Down
Loading

0 comments on commit b309d64

Please sign in to comment.