forked from bonsai/harakit
Merge branch libfileis
This commit is contained in:
commit
941f931f8b
14
Makefile
14
Makefile
@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2023–2024 Emma Tebibyte <emma@tebibyte.media>
|
||||
# Copyright (c) 2023–2025 Emma Tebibyte <emma@tebibyte.media>
|
||||
# Copyright (c) 2023–2024 DTB <trinity@trinity.moe>
|
||||
# Copyright (c) 2023 Sasha Koshka <sashakoshka@tebibyte.media>
|
||||
# Copyright (c) 2024 Aaditya Aryal <aryalaadi123@gmail.com>
|
||||
@ -42,7 +42,7 @@ BIN = build/bin
|
||||
default: all test
|
||||
|
||||
.PHONY: all
|
||||
all: dj false fop hru intcmp mm npc peek rpn scrut str strcmp swab true
|
||||
all: dj false fileis fop hru intcmp mm npc peek rpn str strcmp swab true
|
||||
|
||||
# keep build/include until bindgen(1) has stdin support
|
||||
# https://github.com/rust-lang/rust-bindgen/issues/2703
|
||||
@ -112,6 +112,11 @@ false: build/bin/false
|
||||
build/bin/false: src/false.c build
|
||||
$(CC) $(CFLAGS) -o $@ src/false.c
|
||||
|
||||
.PHONY: fileis
|
||||
fileis: build/bin/fileis
|
||||
build/bin/fileis: src/fileis.rs build
|
||||
$(RUSTC) $(RUSTFLAGS) $(RUSTLIBS) -o $@ src/fileis.rs
|
||||
|
||||
.PHONY: fop
|
||||
fop: build/bin/fop
|
||||
build/bin/fop: src/fop.rs build rustlibs
|
||||
@ -147,11 +152,6 @@ rpn: build/bin/rpn
|
||||
build/bin/rpn: src/rpn.rs build rustlibs
|
||||
$(RUSTC) $(RUSTFLAGS) -o $@ src/rpn.rs
|
||||
|
||||
.PHONY: scrut
|
||||
scrut: build/bin/scrut
|
||||
build/bin/scrut: src/scrut.c build
|
||||
$(CC) $(CFLAGS) -o $@ src/scrut.c
|
||||
|
||||
.PHONY: str
|
||||
str: build/bin/str
|
||||
build/bin/str: src/str.c build
|
||||
|
@ -1,15 +1,15 @@
|
||||
.\" Copyright (c) 2024 DTB <trinity@trinity.moe>
|
||||
.\" Copyright (c) 2024 Emma Tebibyte <emma@tebibyte.media>
|
||||
.\" Copyright (c) 2024–2025 Emma Tebibyte <emma@tebibyte.media>
|
||||
.\"
|
||||
.\" This work is licensed under CC BY-SA 4.0. To see a copy of this license,
|
||||
.\" visit <http://creativecommons.org/licenses/by-sa/4.0/>.
|
||||
.\"
|
||||
.TH SCRUT 1 2024-06-06 "Harakit X.X.X"
|
||||
.TH FILEIS 1 2025-02-24 "Harakit X.X.X"
|
||||
.SH NAME
|
||||
scrut \(en scrutinize file properties
|
||||
fileis \(en scrutinize file properties
|
||||
.SH SYNOPSIS
|
||||
|
||||
scrut
|
||||
fileis
|
||||
.RB [ -LSbcdefgkprsuwx ]
|
||||
.B file...
|
||||
.\"
|
||||
@ -82,5 +82,6 @@ Copyright \(co 2024 DTB. License AGPLv3+: GNU AGPL version 3 or later
|
||||
.\"
|
||||
.SH SEE ALSO
|
||||
.BR access (3p),
|
||||
.BR chown (1p),
|
||||
.BR lstat (3p),
|
||||
.BR test (1p)
|
91
src/fileis.rs
Normal file
91
src/fileis.rs
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2024 DTB <trinity@trinity.moe>
|
||||
* Copyright (c) 2024 Emma Tebibyte <emma@tebibyte.media>
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
use std::{
|
||||
env::args,
|
||||
fs::metadata,
|
||||
os::unix::fs::{ FileTypeExt, MetadataExt },
|
||||
process::ExitCode,
|
||||
};
|
||||
|
||||
extern crate getopt;
|
||||
extern crate strerror;
|
||||
extern crate sysexits;
|
||||
|
||||
use getopt::GetOpt;
|
||||
use strerror::StrError;
|
||||
use sysexits::EX_USAGE;
|
||||
|
||||
const OPTS: &str = "bcdefgkprsuwxLS";
|
||||
|
||||
fn usage(argv0: &str) -> ExitCode {
|
||||
eprintln!("Usage: {} [-{}] file...", argv0, OPTS);
|
||||
ExitCode::from(EX_USAGE)
|
||||
}
|
||||
|
||||
fn main() -> ExitCode {
|
||||
let argv = args().collect::<Vec<_>>();
|
||||
|
||||
let mut sel = String::with_capacity(OPTS.len()); // selected options
|
||||
let mut optind: usize = 1; // argv[0]
|
||||
|
||||
while let Some(opt) = argv.getopt(OPTS) {
|
||||
if let Ok(optchr) = opt.opt() { sel.push_str(optchr); }
|
||||
else { return usage(&argv[0]); }
|
||||
|
||||
optind = opt.ind();
|
||||
}
|
||||
|
||||
if optind == argv.len() { return usage(&argv[0]); }
|
||||
|
||||
for arg in argv.iter().skip(optind) {
|
||||
let fmeta = match metadata(arg) {
|
||||
Ok(m) => m,
|
||||
Err(e) => { // no perms or nonexistent
|
||||
eprintln!("{}: {}: {}", argv[0], arg, e.strerror());
|
||||
return ExitCode::FAILURE;
|
||||
},
|
||||
};
|
||||
|
||||
let fmode = fmeta.mode();
|
||||
let ftype = fmeta.file_type();
|
||||
|
||||
for selection in sel.chars() { // run all selected tests
|
||||
match selection {
|
||||
'b' if ftype.is_block_device() => (),
|
||||
'c' if ftype.is_char_device() => (),
|
||||
'e' => (), // exists or metadata would have errored
|
||||
'd' if fmeta.is_dir() => (),
|
||||
'f' if fmeta.is_file() => (),
|
||||
'g' if fmode & 0o2000 /* S_ISGID */ != 0 => (), // setgid
|
||||
'k' if fmode & 0o1000 /* S_ISVTX */ != 0 => (), // setvtx
|
||||
'p' if ftype.is_fifo() => (),
|
||||
'r' if fmode & 0o0400 /* S_IRUSR */ != 0 => (), // read access
|
||||
'u' if fmode & 0o4000 /* S_ISUID */ != 0 => (), // setuid
|
||||
'w' if fmode & 0o0200 /* S_IWUSR */ != 0 => (), // write access
|
||||
'x' if fmode & 0o0100 /* S_IXUSR */ != 0 => (), // exec access
|
||||
'L' if fmeta.is_symlink() => (),
|
||||
'S' if ftype.is_socket() => (),
|
||||
_ => { return ExitCode::FAILURE; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ExitCode::SUCCESS
|
||||
}
|
Loading…
Reference in New Issue
Block a user