diff --git a/src/chgrp/Cargo.toml b/src/chgrp/Cargo.toml index 58e26e3cb..cfcfbd4e3 100644 --- a/src/chgrp/Cargo.toml +++ b/src/chgrp/Cargo.toml @@ -13,7 +13,7 @@ walkdir = "*" [dependencies.uucore] path = "../uucore" default-features = false -features = ["entries"] +features = ["entries", "fs"] [[bin]] name = "chgrp" diff --git a/src/chgrp/chgrp.rs b/src/chgrp/chgrp.rs index 1a8be92e5..2455592de 100644 --- a/src/chgrp/chgrp.rs +++ b/src/chgrp/chgrp.rs @@ -12,6 +12,7 @@ extern crate uucore; use uucore::libc::{self, gid_t, lchown}; pub use uucore::entries; +use uucore::fs::resolve_relative_path; extern crate walkdir; use walkdir::WalkDir; @@ -194,12 +195,6 @@ impl Chgrper { fn exec(&self) -> i32 { let mut ret = 0; for f in &self.files { - if f == "/" && self.preserve_root && self.recursive { - show_info!("it is dangerous to operate recursively on '/'"); - show_info!("use --no-preserve-root to override this failsafe"); - ret = 1; - continue; - } ret |= self.traverse(f); } ret @@ -230,6 +225,28 @@ impl Chgrper { _ => return 1, }; + // Prohibit only if: + // (--preserve-root and -R present) && + // ( + // (argument is not symlink && resolved to be '/') || + // (argument is symlink && should follow argument && resolved to be '/') + // ) + if self.recursive && self.preserve_root { + let may_exist = if follow_arg { + path.canonicalize().ok() + } else { + Some(resolve_relative_path(path).into_owned()) + }; + + if let Some(p) = may_exist { + if p.parent().is_none() { + show_info!("it is dangerous to operate recursively on '/'"); + show_info!("use --no-preserve-root to override this failsafe"); + return 1; + } + } + } + let ret = self.wrap_chgrp(path, &meta, follow_arg); if !self.recursive { diff --git a/src/chown/Cargo.toml b/src/chown/Cargo.toml index 599d65b9c..b0da5635e 100644 --- a/src/chown/Cargo.toml +++ b/src/chown/Cargo.toml @@ -14,7 +14,7 @@ walkdir = "0.1" [dependencies.uucore] path = "../uucore" default-features = false -features = ["entries"] +features = ["entries", "fs"] [dependencies.clippy] version = "*" diff --git a/src/chown/chown.rs b/src/chown/chown.rs index f4c27710d..8b1fabbad 100644 --- a/src/chown/chown.rs +++ b/src/chown/chown.rs @@ -15,6 +15,7 @@ extern crate uucore; use uucore::libc::{self, uid_t, gid_t, lchown}; pub use uucore::entries::{self, Locate, Passwd, Group}; +use uucore::fs::resolve_relative_path; extern crate walkdir; use walkdir::WalkDir; @@ -257,12 +258,6 @@ impl Chowner { fn exec(&self) -> i32 { let mut ret = 0; for f in &self.files { - if f == "/" && self.preserve_root && self.recursive { - show_info!("it is dangerous to operate recursively on '/'"); - show_info!("use --no-preserve-root to override this failsafe"); - ret = 1; - continue; - } ret |= self.traverse(f); } ret @@ -293,6 +288,28 @@ impl Chowner { _ => return 1, }; + // Prohibit only if: + // (--preserve-root and -R present) && + // ( + // (argument is not symlink && resolved to be '/') || + // (argument is symlink && should follow argument && resolved to be '/') + // ) + if self.recursive && self.preserve_root { + let may_exist = if follow_arg { + path.canonicalize().ok() + } else { + Some(resolve_relative_path(path).into_owned()) + }; + + if let Some(p) = may_exist { + if p.parent().is_none() { + show_info!("it is dangerous to operate recursively on '/'"); + show_info!("use --no-preserve-root to override this failsafe"); + return 1; + } + } + } + let ret = if self.matched(meta.uid(), meta.gid()) { self.wrap_chown(path, &meta, follow_arg) } else { @@ -300,10 +317,10 @@ impl Chowner { }; if !self.recursive { - return ret; + ret + } else { + ret | self.dive_into(&root) } - - self.dive_into(&root) } fn dive_into>(&self, root: P) -> i32 { @@ -413,4 +430,3 @@ impl Chowner { } } } -