use std::fs::File;
use std::io::Read;
use std::path::PathBuf;
use tar::*;
use util;
use xz2::read::XzDecoder;
pub fn tar_check(tar_file: PathBuf) {
let tar_str = tar_file.to_str().unwrap();
let archive = File::open(&tar_file).expect(&format!("cannot open file {}", tar_str));
if tar_str.ends_with(".tar.xz") {
tar_check_archive(Archive::new(XzDecoder::new(archive)), tar_str);
} else if tar_str.ends_with(".tar") {
tar_check_archive(Archive::new(archive), tar_str);
} else {
panic!("Unsupported file format for tar_check function: {}", tar_str)
};
}
fn tar_check_archive<R: Read>(mut archive: Archive<R>, path_str: &str) {
let mut install_file = String::new();
let mut all_files = Vec::new();
let mut executable_files = Vec::new();
let mut suid_files = Vec::new();
let archive_files = archive.entries().expect(&format!("cannot open archive {}", path_str));
for file in archive_files {
let mut file = file.expect(&format!("cannot access tar file in {}", path_str));
let path = {
let path = file.header().path()
.expect(&format!("Failed to extract tar file metadata for file in {}", path_str));
path.to_str().unwrap().to_owned()
};
let mode = file.header().mode().unwrap();
let is_normal = !path.ends_with("/") && !path.starts_with(".");
if is_normal { all_files.push(path.clone()); }
if is_normal && (mode & 0o111 > 0) { executable_files.push(path.clone()); }
if mode > 0o777 { suid_files.push(path.clone()); }
if &path == ".INSTALL" {
file.read_to_string(&mut install_file)
.expect(&format!("Failed to read INSTALL script from tar file {}", path_str));
}
}
let has_install = !install_file.is_empty();
loop {
if suid_files.is_empty() {
eprint!("\nPackage {} has no SUID files.\n", path_str);
} else {
eprint!("\n!!!WARNING!!! Package {} has SUID files.\n[S]=list SUID files, ", path_str)
};
if has_install { eprint!("[I]=show install file, "); };
eprint!("[E]=list executable files, [L]=list all files, \
[T]=run shell to inspect, [O]=ok, proceed. ");
let string = util::console_get_line();
eprintln!();
if string == "s" && !suid_files.is_empty() {
for path in &suid_files {
eprintln!("{}", path);
}
} else if string == "e" {
for path in &executable_files {
eprintln!("{}", path);
}
} else if string == "l" {
for path in &all_files {
eprintln!("{}", path);
}
} else if string == "i" && has_install {
eprintln!("{}", &install_file);
} else if string == "t" {
eprintln!("Exit the shell with `logout` or Ctrl-D...");
util::run_env_command("SHELL", "bash", &[]);
} else if string == "o" {
break;
}
}
}