Skip to content
Open
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
62 changes: 26 additions & 36 deletions src/uu/chmod/src/chmod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -828,44 +828,34 @@ impl Chmoder {
let (new_mode, naively_expected_new_mode) =
self.calculate_new_mode(fperm, file.is_dir())?;

// Determine how to apply the permissions
if let Some(mode) = self.fmode {
// A symlink reached without dereferencing (for example one met while
// walking a `-R` tree) must be left alone: chmod(2) follows the link,
// so changing it would change the mode of the referent, which can live
// outside the tree. The symbolic/numeric path below already skips it.
if file.is_symlink() && !dereference {
if self.verbose {
Self::print_neither_changed(file.into())?;
}
} else {
self.change_file(fperm, mode, file)?;
// A symlink reached without dereferencing (for example one met while
// walking a `-R` tree) must be left alone: chmod(2) follows the link,
// so changing it would change the mode of the referent, which can live
// outside the tree. On most Unix systems, symlink permissions are
// ignored by the kernel anyway, so changing them has no effect.
if file.is_symlink() && !dereference {
if self.verbose {
Self::print_neither_changed(file.into())?;
}
} else {
// Special handling for symlinks when not dereferencing
if file.is_symlink() && !dereference {
// TODO: On most Unix systems, symlink permissions are ignored by the kernel,
// so changing them has no effect. We skip this operation for compatibility.
// Note that "chmod without dereferencing" effectively does nothing on symlinks.
if self.verbose {
Self::print_neither_changed(file.into())?;
}
} else {
self.change_file(fperm, new_mode, file)?;
}
// A bare mode such as `-w` is umask-relative, so the umask can keep permissions that
// the user asked to drop. GNU reports that as an error, but only when the mode was
// written in the option-like form (`chmod -w f`), where it doubles as a hint that the
// argument was consumed as a mode. After `--` the operand is unambiguous and GNU stays
// silent, so the diagnostic is suppressed here too.
if self.option_like_mode && (new_mode & !naively_expected_new_mode) != 0 {
return Err(ChmodError::NewPermissions(
file.into(),
display_permissions_unix(new_mode, false),
display_permissions_unix(naively_expected_new_mode, false),
)
.into());
}
self.change_file(fperm, self.fmode.unwrap_or(new_mode), file)?;
}

// A bare mode such as `-w` is umask-relative, so the umask can keep permissions that
// the user asked to drop. GNU reports that as an error, but only when the mode was
// written in the option-like form (`chmod -w f`), where it doubles as a hint that the
// argument was consumed as a mode. After `--` the operand is unambiguous and GNU stays
// silent, so the diagnostic is suppressed here too.
if self.fmode.is_none()
&& self.option_like_mode
&& (new_mode & !naively_expected_new_mode) != 0
{
return Err(ChmodError::NewPermissions(
file.into(),
display_permissions_unix(new_mode, false),
display_permissions_unix(naively_expected_new_mode, false),
)
.into());
}

Ok(())
Expand Down
Loading