1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-27 11:07:44 +00:00

Merge pull request #983 from knight42/fix-preserve-root

Updated chgrp & chown
This commit is contained in:
mpkh 2016-08-27 22:51:19 +04:00 committed by GitHub
commit b2ded87d39
5 changed files with 102 additions and 41 deletions

View file

@ -13,7 +13,7 @@ walkdir = "*"
[dependencies.uucore] [dependencies.uucore]
path = "../uucore" path = "../uucore"
default-features = false default-features = false
features = ["entries"] features = ["entries", "fs"]
[[bin]] [[bin]]
name = "chgrp" name = "chgrp"

View file

@ -12,6 +12,7 @@
extern crate uucore; extern crate uucore;
use uucore::libc::{self, gid_t, lchown}; use uucore::libc::{self, gid_t, lchown};
pub use uucore::entries; pub use uucore::entries;
use uucore::fs::resolve_relative_path;
extern crate walkdir; extern crate walkdir;
use walkdir::WalkDir; use walkdir::WalkDir;
@ -194,12 +195,6 @@ impl Chgrper {
fn exec(&self) -> i32 { fn exec(&self) -> i32 {
let mut ret = 0; let mut ret = 0;
for f in &self.files { 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 |= self.traverse(f);
} }
ret ret
@ -230,6 +225,28 @@ impl Chgrper {
_ => return 1, _ => 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); let ret = self.wrap_chgrp(path, &meta, follow_arg);
if !self.recursive { if !self.recursive {

View file

@ -14,7 +14,7 @@ walkdir = "0.1"
[dependencies.uucore] [dependencies.uucore]
path = "../uucore" path = "../uucore"
default-features = false default-features = false
features = ["entries"] features = ["entries", "fs"]
[dependencies.clippy] [dependencies.clippy]
version = "*" version = "*"

View file

@ -15,6 +15,7 @@
extern crate uucore; extern crate uucore;
use uucore::libc::{self, uid_t, gid_t, lchown}; use uucore::libc::{self, uid_t, gid_t, lchown};
pub use uucore::entries::{self, Locate, Passwd, Group}; pub use uucore::entries::{self, Locate, Passwd, Group};
use uucore::fs::resolve_relative_path;
extern crate walkdir; extern crate walkdir;
use walkdir::WalkDir; use walkdir::WalkDir;
@ -257,12 +258,6 @@ impl Chowner {
fn exec(&self) -> i32 { fn exec(&self) -> i32 {
let mut ret = 0; let mut ret = 0;
for f in &self.files { 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 |= self.traverse(f);
} }
ret ret
@ -293,6 +288,28 @@ impl Chowner {
_ => return 1, _ => 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()) { let ret = if self.matched(meta.uid(), meta.gid()) {
self.wrap_chown(path, &meta, follow_arg) self.wrap_chown(path, &meta, follow_arg)
} else { } else {
@ -300,10 +317,10 @@ impl Chowner {
}; };
if !self.recursive { if !self.recursive {
return ret; ret
} else {
ret | self.dive_into(&root)
} }
self.dive_into(&root)
} }
fn dive_into<P: AsRef<Path>>(&self, root: P) -> i32 { fn dive_into<P: AsRef<Path>>(&self, root: P) -> i32 {
@ -413,4 +430,3 @@ impl Chowner {
} }
} }
} }

View file

@ -1,18 +1,39 @@
/* // This file is part of the uutils coreutils package.
* This file is part of the uutils coreutils package. //
* // (c) Joseph Crail <jbcrail@gmail.com>
* (c) Joseph Crail <jbcrail@gmail.com> // (c) Jian Zeng <anonymousknight96 AT gmail.com>
* //
* For the full copyright and license information, please view the LICENSE // For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. // file that was distributed with this source code.
*/ //
#[cfg(unix)] #[cfg(unix)]
use super::libc; use super::libc;
use std::env; use std::env;
use std::fs; use std::fs;
use std::io::{Error, ErrorKind, Result}; use std::io::{Error, ErrorKind};
use std::io::Result as IOResult;
use std::path::{Component, Path, PathBuf}; use std::path::{Component, Path, PathBuf};
use std::borrow::Cow;
#[cfg(unix)]
pub fn resolve_relative_path<'a>(path: &'a Path) -> Cow<'a, Path> {
if path.is_absolute() {
return path.into();
}
let mut result = env::current_dir().unwrap_or(PathBuf::from("/"));
for comp in path.components() {
match comp {
Component::ParentDir => {
result.pop();
}
Component::CurDir => (),
Component::Normal(s) => result.push(s),
_ => unreachable!(),
}
}
result.into()
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)] #[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum CanonicalizeMode { pub enum CanonicalizeMode {
@ -22,7 +43,7 @@ pub enum CanonicalizeMode {
Missing, Missing,
} }
fn resolve<P: AsRef<Path>>(original: P) -> Result<PathBuf> { fn resolve<P: AsRef<Path>>(original: P) -> IOResult<PathBuf> {
const MAX_LINKS_FOLLOWED: u32 = 255; const MAX_LINKS_FOLLOWED: u32 = 255;
let mut followed = 0; let mut followed = 0;
let mut result = original.as_ref().to_path_buf(); let mut result = original.as_ref().to_path_buf();
@ -40,7 +61,7 @@ fn resolve<P: AsRef<Path>>(original: P) -> Result<PathBuf> {
Ok(path) => { Ok(path) => {
result.pop(); result.pop();
result.push(path); result.push(path);
}, }
Err(e) => { Err(e) => {
return Err(e); return Err(e);
} }
@ -51,7 +72,7 @@ fn resolve<P: AsRef<Path>>(original: P) -> Result<PathBuf> {
Ok(result) Ok(result)
} }
pub fn canonicalize<P: AsRef<Path>>(original: P, can_mode: CanonicalizeMode) -> Result<PathBuf> { pub fn canonicalize<P: AsRef<Path>>(original: P, can_mode: CanonicalizeMode) -> IOResult<PathBuf> {
// Create an absolute path // Create an absolute path
let original = original.as_ref(); let original = original.as_ref();
let original = if original.is_absolute() { let original = if original.is_absolute() {
@ -61,20 +82,21 @@ pub fn canonicalize<P: AsRef<Path>>(original: P, can_mode: CanonicalizeMode) ->
}; };
let mut result = PathBuf::new(); let mut result = PathBuf::new();
let mut parts = vec!(); let mut parts = vec![];
// Split path by directory separator; add prefix (Windows-only) and root // Split path by directory separator; add prefix (Windows-only) and root
// directory to final path buffer; add remaining parts to temporary // directory to final path buffer; add remaining parts to temporary
// vector for canonicalization. // vector for canonicalization.
for part in original.components() { for part in original.components() {
match part { match part {
Component::Prefix(_) | Component::RootDir => { Component::Prefix(_) |
Component::RootDir => {
result.push(part.as_os_str()); result.push(part.as_os_str());
}, }
Component::CurDir => {}, Component::CurDir => (),
Component::ParentDir => { Component::ParentDir => {
parts.pop(); parts.pop();
}, }
Component::Normal(_) => { Component::Normal(_) => {
parts.push(part.as_os_str()); parts.push(part.as_os_str());
} }
@ -83,7 +105,7 @@ pub fn canonicalize<P: AsRef<Path>>(original: P, can_mode: CanonicalizeMode) ->
// Resolve the symlinks where possible // Resolve the symlinks where possible
if !parts.is_empty() { if !parts.is_empty() {
for part in parts[..parts.len()-1].iter() { for part in parts[..parts.len() - 1].iter() {
result.push(part); result.push(part);
if can_mode == CanonicalizeMode::None { if can_mode == CanonicalizeMode::None {
@ -91,10 +113,12 @@ pub fn canonicalize<P: AsRef<Path>>(original: P, can_mode: CanonicalizeMode) ->
} }
match resolve(&result) { match resolve(&result) {
Err(e) => match can_mode { Err(e) => {
CanonicalizeMode::Missing => continue, match can_mode {
_ => return Err(e) CanonicalizeMode::Missing => continue,
}, _ => return Err(e),
}
}
Ok(path) => { Ok(path) => {
result.pop(); result.pop();
result.push(path); result.push(path);
@ -105,7 +129,11 @@ pub fn canonicalize<P: AsRef<Path>>(original: P, can_mode: CanonicalizeMode) ->
result.push(parts.last().unwrap()); result.push(parts.last().unwrap());
match resolve(&result) { match resolve(&result) {
Err(e) => { if can_mode == CanonicalizeMode::Existing { return Err(e); } }, Err(e) => {
if can_mode == CanonicalizeMode::Existing {
return Err(e);
}
}
Ok(path) => { Ok(path) => {
result.pop(); result.pop();
result.push(path); result.push(path);