Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/uu/chmod/locales/en-US.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ chmod-help-recursive = change files and directories recursively
chmod-help-reference = use RFILE's mode instead of MODE values

# Verbose messages
chmod-verbose-failed-dangling = failed to change mode of {$file} from 0000 (---------) to 1500 (r-x-----T)
chmod-verbose-neither-changed = neither symbolic link {$file} nor referent has been changed
chmod-verbose-mode-retained = mode of {$file} retained as {$mode_octal} ({$mode_display})
chmod-verbose-failed-change = failed to change mode of file {$file} from {$old_mode} ({$old_mode_display}) to {$new_mode} ({$new_mode_display})
Expand Down
1 change: 0 additions & 1 deletion src/uu/chmod/locales/fr-FR.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ chmod-error-missing-operand = opérande manquant
chmod-error-reference-stat = impossible d'obtenir les attributs de { $file } : { $error }

# Messages verbeux/de statut
chmod-verbose-failed-dangling = échec du changement de mode de {$file} de 0000 (---------) vers 1500 (r-x-----T)
chmod-verbose-neither-changed = ni le lien symbolique {$file} ni la référence n'ont été changés
chmod-verbose-mode-retained = mode de {$file} conservé comme {$mode_octal} ({$mode_display})
chmod-verbose-failed-change = échec du changement de mode du fichier {$file} de {$old_mode} ({$old_mode_display}) vers {$new_mode} ({$new_mode_display})
Expand Down
24 changes: 14 additions & 10 deletions src/uu/chmod/src/chmod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,12 @@ impl Chmoder {
/// subtree was left alone.
fn report_unreadable_dir(&self, path: &Path, err: std::io::Error) {
self.report_failure(ChmodError::CannotReadDirectory(path.into(), err).into());
self.report_not_accessed(path);
}

/// With --verbose, GNU follows a failure to stat or read FILE with
/// "'FILE' could not be accessed" on stdout, even with --quiet.
fn report_not_accessed(&self, path: &Path) {
if self.verbose {
println!(
"{}",
Expand Down Expand Up @@ -487,16 +493,10 @@ impl Chmoder {
show!(ChmodError::DanglingSymlink(filename.into()));
set_exit_code(1);
}

if self.verbose {
println!(
"{}",
translate!("chmod-verbose-failed-dangling", "file" => filename.quote())
);
}
} else if !self.quiet {
show!(ChmodError::NoSuchFile(filename.into()));
}
self.report_not_accessed(file);
// GNU exits with exit code 1 even if -q or --quiet are passed
// So we set the exit code, because it hasn't been set yet if `self.quiet` is true.
set_exit_code(1);
Expand All @@ -506,6 +506,7 @@ impl Chmoder {
if !self.quiet {
show!(ChmodError::PermissionDenied(filename.into()));
}
self.report_not_accessed(file);
set_exit_code(1);
continue;
}
Expand Down Expand Up @@ -854,10 +855,13 @@ impl Chmoder {
Self::print_neither_changed(file.into())?;
}
Ok(()) // Skip dangling symlinks
} else if err.kind() == std::io::ErrorKind::PermissionDenied {
Err(ChmodError::PermissionDenied(file.into()).into())
} else {
Err(ChmodError::CannotStat(file.into(), err).into())
self.report_not_accessed(file);
if err.kind() == std::io::ErrorKind::PermissionDenied {
Err(ChmodError::PermissionDenied(file.into()).into())
} else {
Err(ChmodError::CannotStat(file.into(), err).into())
}
};
}
};
Expand Down
44 changes: 38 additions & 6 deletions tests/by-util/test_chmod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -784,9 +784,7 @@ fn test_chmod_symlink_non_existing_file() {

let non_existing = "test_chmod_symlink_non_existing_file";
let test_symlink = "test_chmod_symlink_non_existing_file_symlink";
let expected_stdout = &format!(
"failed to change mode of '{test_symlink}' from 0000 (---------) to 1500 (r-x-----T)"
);
let expected_stdout = &format!("'{test_symlink}' could not be accessed");
let expected_stderr = &format!("cannot operate on dangling symlink '{test_symlink}'");

at.symlink_file(non_existing, test_symlink);
Expand Down Expand Up @@ -963,9 +961,7 @@ fn test_chmod_file_symlink_after_non_existing_file() {

let non_existing = "test_chmod_symlink_non_existing_file";
let test_dangling_symlink = "test_chmod_symlink_non_existing_file_symlink";
let expected_stdout = &format!(
"failed to change mode of '{test_dangling_symlink}' from 0000 (---------) to 1500 (r-x-----T)"
);
let expected_stdout = &format!("'{test_dangling_symlink}' could not be accessed");
let expected_stderr = &format!("cannot operate on dangling symlink '{test_dangling_symlink}'");

at.touch(existing);
Expand Down Expand Up @@ -2068,3 +2064,39 @@ fn test_overlong_path_reports_os_error_and_continues() {
"chmod: failed to get attributes of '{path}': {error}\n"
));
}

#[test]
fn test_chmod_verbose_reports_inaccessible_operand() {
let (at, mut ucmd) = at_and_ucmd!();
at.touch("f");
at.set_mode("f", 0o644);
ucmd.args(&["-v", "644", "missing", "f/", "f"])
.fails_with_code(1)
.stdout_is(
"'missing' could not be accessed\n\
'f/' could not be accessed\n\
mode of 'f' retained as 0644 (rw-r--r--)\n",
)
.stderr_is(
"chmod: cannot access 'missing': No such file or directory\n\
chmod: cannot access 'f/': Not a directory\n",
);
}

#[test]
fn test_chmod_verbose_quiet_still_reports_inaccessible_operand() {
new_ucmd!()
.args(&["-v", "-f", "644", "missing"])
.fails_with_code(1)
.stdout_is("'missing' could not be accessed\n")
.no_stderr();
}

#[test]
fn test_chmod_changes_does_not_report_inaccessible_operand() {
new_ucmd!()
.args(&["-c", "644", "missing"])
.fails_with_code(1)
.no_stdout()
.stderr_is("chmod: cannot access 'missing': No such file or directory\n");
}
Loading