Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ftw: impl FilesystemStatistics, symlink_metadata and use it #310

Draft
wants to merge 16 commits into
base: main
Choose a base branch
from
Draft
4 changes: 3 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions file/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ rust-version.workspace = true

[dependencies]
plib = { path = "../plib" }
ftw = { path = "../ftw" }
clap.workspace = true
gettext-rs.workspace = true
libc.workspace = true
Expand Down
116 changes: 42 additions & 74 deletions file/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@
mod magic;

use std::fs::read_link;
use std::os::unix::fs::FileTypeExt;
use std::path::PathBuf;
use std::{fs, io};
use std::io;
use std::path::{Path, PathBuf};

use clap::Parser;
use ftw::{symlink_metadata, FileType};
use gettextrs::{bind_textdomain_codeset, gettext, setlocale, textdomain, LocaleCategory};

use crate::magic::{get_type_from_magic_file_dbs, DEFAULT_MAGIC_FILE};
Expand Down Expand Up @@ -110,83 +110,45 @@ fn get_magic_files(args: &Args) -> Vec<PathBuf> {
magic_files
}

fn analyze_file(mut path: String, args: &Args, magic_files: &Vec<PathBuf>) {
if path == "-" {
path = String::new();
io::stdin().read_line(&mut path).unwrap();
path = path.trim().to_string();
}

let met = match fs::symlink_metadata(&path) {
Ok(met) => met,
Err(_) => {
println!("{path}: cannot open");
return;
}
fn analyze_file<P: AsRef<Path>>(path: P, args: &Args, magic_files: &Vec<PathBuf>) -> String {
let meta = match symlink_metadata(&path) {
Ok(m) => m,
Err(_) => return gettext("cannot open"),
};

let file_type = met.file_type();

if file_type.is_symlink() {
if args.identify_as_symbolic_link {
println!("{path}: symbolic link");
return;
}
match read_link(&path) {
Ok(file_p) => {
// trace the file pointed by symbolic link
if file_p.exists() {
println!("{path}: symbolic link to {}", file_p.to_str().unwrap());
} else {
println!(
"{path}: broken symbolic link to {}",
file_p.to_str().unwrap()
);
}
match meta.file_type() {
FileType::Socket => gettext("socket"),
FileType::BlockDevice => gettext("block special"),
FileType::Directory => gettext("directory"),
FileType::CharacterDevice => gettext("character special"),
FileType::Fifo => gettext("fifo"),
FileType::SymbolicLink => {
if args.identify_as_symbolic_link {
return gettext("symbolic link");
}
Err(_) => {
println!("{path}: symbolic link");
match read_link(&path) {
Ok(file_p) => {
// trace the file pointed by symbolic link
if file_p.exists() {
gettext!("symbolic link to {}", file_p.to_str().unwrap())
} else {
gettext!("broken symbolic link to {}", file_p.to_str().unwrap())
}
}
Err(_) => gettext("symbolic link"),
}
}
return;
}
if file_type.is_char_device() {
println!("{path}: character special");
return;
}
if file_type.is_dir() {
println!("{path}: directory");
return;
}
if file_type.is_fifo() {
println!("{path}: fifo");
return;
}
if file_type.is_socket() {
println!("{path}: socket");
return;
}
if file_type.is_block_device() {
println!("{path}: block special");
return;
}
if file_type.is_file() {
if args.no_further_file_classification {
assert!(magic_files.is_empty());
println!("{path}: regular file");
return;
}
if met.len() == 0 {
println!("{path}: empty");
return;
}
match get_type_from_magic_file_dbs(&PathBuf::from(&path), magic_files) {
Some(f_type) => println!("{path}: {f_type}"),
None => println!("{path}: data"),
FileType::RegularFile => {
if args.no_further_file_classification {
assert!(magic_files.is_empty());
return gettext("regular file");
}
if meta.is_empty() {
return gettext("empty");
}
get_type_from_magic_file_dbs(path, &magic_files).unwrap_or_else(|| gettext("data"))
}
return;
}
unreachable!();
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
Expand All @@ -199,7 +161,13 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let magic_files = get_magic_files(&args);

for file in &args.files {
analyze_file(file.clone(), &args, &magic_files);
let mut file = file.clone();
if file == "-" {
file = String::new();
io::stdin().read_line(&mut file).unwrap();
file = file.trim().to_string();
}
println!("{}: {}", &file, analyze_file(&file, &args, &magic_files));
}

Ok(())
Expand Down
15 changes: 8 additions & 7 deletions file/magic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use std::{
fmt,
fs::File,
io::{self, BufRead, BufReader, ErrorKind, Read, Seek, SeekFrom},
path::PathBuf,
path::{Path, PathBuf},
};

#[cfg(target_os = "macos")]
Expand All @@ -24,13 +24,14 @@ pub const DEFAULT_MAGIC_FILE: &str = "/usr/share/file/magic/magic";
pub const DEFAULT_MAGIC_FILE: &str = "/etc/magic";

/// Get type for the file from the magic file databases (traversed in order of argument)
pub fn get_type_from_magic_file_dbs(
test_file: &PathBuf,
pub fn get_type_from_magic_file_dbs<P: AsRef<Path>>(
test_file: P,
magic_file_dbs: &[PathBuf],
) -> Option<String> {
magic_file_dbs.iter().find_map(|magic_file| {
parse_magic_file_and_test(&PathBuf::from(magic_file), &PathBuf::from(test_file)).ok()
})
let test_file = test_file.as_ref();
magic_file_dbs
.iter()
.find_map(|magic_file| parse_magic_file_and_test(test_file, magic_file).ok())
}

/// Errors that can occur during parsing of a raw magic line.
Expand Down Expand Up @@ -478,8 +479,8 @@ impl RawMagicFileLine {
/// line by line. It parses each line of the magic database file and tests it against
/// the content of the test file.
fn parse_magic_file_and_test(
test_file: &Path,
magic_file: &PathBuf,
test_file: &PathBuf,
) -> Result<String, Box<dyn std::error::Error>> {
let mf_reader = BufReader::new(File::open(magic_file)?);
let mut tf_reader = BufReader::new(File::open(test_file)?);
Expand Down
2 changes: 1 addition & 1 deletion fs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ edition.workspace = true
rust-version.workspace = true

[dependencies]
ftw = { path = "../ftw" }
clap.workspace = true
gettext-rs.workspace = true
libc.workspace = true
Expand All @@ -18,4 +19,3 @@ workspace = true
[[bin]]
name = "df"
path = "./df.rs"

Loading