ls: (--context/-Z) add support for invalid utf8

If security context byte slice contains invalid utf8:
* issue warning
* show replacement characters for invalid utf8 sequences
This commit is contained in:
Jan Scheer 2021-09-13 13:24:44 +02:00
parent e018a45b54
commit cd2153eac6
No known key found for this signature in database
GPG key ID: C62AD4C29E2B9828
2 changed files with 43 additions and 12 deletions

View file

@ -40,6 +40,7 @@ use std::{
time::Duration,
};
use term_grid::{Cell, Direction, Filling, Grid, GridOptions};
use uucore::display::Quotable;
use uucore::error::{set_exit_code, FromIo, UError, UResult};
use unicode_width::UnicodeWidthStr;
@ -1256,27 +1257,41 @@ impl PathData {
None => OnceCell::new(),
};
let substitute_string = "?".to_string();
let security_context = if config.context {
if config.selinux_supported {
#[cfg(feature = "selinux")]
{
if let Ok(Some(context)) =
selinux::SecurityContext::of_path(&p_buf, must_dereference, false)
{
String::from_utf8_lossy(context.as_bytes())
.trim_end_matches(char::from(0))
.to_string()
} else {
// TODO: print warning with error to stderr
"?".to_string()
match selinux::SecurityContext::of_path(&p_buf, must_dereference, false) {
Err(_r) => {
// TODO: show the actual reason why it failed
show_warning!("failed to get security context of: {}", p_buf.quote());
substitute_string
}
Ok(None) => substitute_string,
Ok(Some(context)) => {
let mut context = context.as_bytes();
if context.ends_with(&[0]) {
// TODO: replace with `strip_prefix()` when MSRV >= 1.51
context = &context[..context.len() - 1]
};
String::from_utf8(context.to_vec()).unwrap_or_else(|e| {
show_warning!(
"getting security context of: {}: {}",
p_buf.quote(),
e.to_string()
);
String::from_utf8_lossy(context).into_owned()
})
}
}
}
#[cfg(not(feature = "selinux"))]
{
"?".to_string()
substitute_string
}
} else {
"?".to_string()
substitute_string
}
} else {
String::new()

View file

@ -2282,7 +2282,23 @@ fn test_ls_dangling_symlinks() {
#[test]
#[cfg(feature = "feat_selinux")]
fn test_ls_context() {
fn test_ls_context1() {
use selinux::{self, KernelSupport};
if selinux::kernel_support() == KernelSupport::Unsupported {
println!("test skipped: Kernel has no support for SElinux context",);
return;
}
let file = "test_ls_context_file";
let expected = format!("unconfined_u:object_r:user_tmp_t:s0 {}\n", file);
let (at, mut ucmd) = at_and_ucmd!();
at.touch(file);
ucmd.args(&["-Z", file]).succeeds().stdout_is(expected);
}
#[test]
#[cfg(feature = "feat_selinux")]
fn test_ls_context2() {
use selinux::{self, KernelSupport};
if selinux::kernel_support() == KernelSupport::Unsupported {
println!("test skipped: Kernel has no support for SElinux context",);