mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-30 04:27:45 +00:00
Update hashsum.
Most of the work centered around fixing lifetime issues.
This commit is contained in:
parent
3cc357e118
commit
1837146134
2 changed files with 45 additions and 52 deletions
|
@ -1,5 +1,5 @@
|
||||||
#![crate_name = "hashsum"]
|
#![crate_name = "hashsum"]
|
||||||
#![feature(collections, core, old_io, old_path, rustc_private)]
|
#![feature(rustc_private)]
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file is part of the uutils coreutils package.
|
* This file is part of the uutils coreutils package.
|
||||||
|
@ -17,17 +17,15 @@ extern crate regex;
|
||||||
extern crate crypto;
|
extern crate crypto;
|
||||||
extern crate getopts;
|
extern crate getopts;
|
||||||
|
|
||||||
use std::ascii::AsciiExt;
|
|
||||||
use std::old_io::fs::File;
|
|
||||||
use std::old_io::stdio::stdin_raw;
|
|
||||||
use std::old_io::BufferedReader;
|
|
||||||
use std::old_io::IoError;
|
|
||||||
use std::old_io::EndOfFile;
|
|
||||||
use regex::Regex;
|
|
||||||
use crypto::digest::Digest;
|
use crypto::digest::Digest;
|
||||||
use crypto::md5::Md5;
|
use crypto::md5::Md5;
|
||||||
use crypto::sha1::Sha1;
|
use crypto::sha1::Sha1;
|
||||||
use crypto::sha2::{Sha224, Sha256, Sha384, Sha512};
|
use crypto::sha2::{Sha224, Sha256, Sha384, Sha512};
|
||||||
|
use regex::Regex;
|
||||||
|
use std::ascii::AsciiExt;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{self, BufRead, BufReader, Read, stdin, Write};
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
#[path = "../common/util.rs"]
|
#[path = "../common/util.rs"]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
@ -91,18 +89,17 @@ fn detect_algo(program: &str, matches: &getopts::Matches) -> (&'static str, Box<
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn uumain(args: Vec<String>) -> i32 {
|
pub fn uumain(args: Vec<String>) -> i32 {
|
||||||
let program = args[0].clone();
|
let program = &args[0];
|
||||||
let binary = Path::new(program.as_slice());
|
let binary_name = Path::new(program).file_name().unwrap().to_str().unwrap();
|
||||||
let binary_name = binary.filename_str().unwrap();
|
|
||||||
|
|
||||||
// Default binary in Windows, text mode otherwise
|
// Default binary in Windows, text mode otherwise
|
||||||
let binary_flag_default = cfg!(windows);
|
let binary_flag_default = cfg!(windows);
|
||||||
|
|
||||||
let mut opts: Vec<getopts::OptGroup> = vec!(
|
let mut opts: Vec<getopts::OptGroup> = vec!(
|
||||||
getopts::optflag("b", "binary", format!("read in binary mode{}", if binary_flag_default { " (default)" } else { "" }).as_slice()),
|
getopts::optflag("b", "binary", &format!("read in binary mode{}", if binary_flag_default { " (default)" } else { "" })),
|
||||||
getopts::optflag("c", "check", "read hashsums from the FILEs and check them"),
|
getopts::optflag("c", "check", "read hashsums from the FILEs and check them"),
|
||||||
getopts::optflag("", "tag", "create a BSD-style checksum"),
|
getopts::optflag("", "tag", "create a BSD-style checksum"),
|
||||||
getopts::optflag("t", "text", format!("read in text mode{}", if binary_flag_default { "" } else { " (default)" }).as_slice()),
|
getopts::optflag("t", "text", &format!("read in text mode{}", if binary_flag_default { "" } else { " (default)" })),
|
||||||
getopts::optflag("q", "quiet", "don't print OK for each successfully verified file"),
|
getopts::optflag("q", "quiet", "don't print OK for each successfully verified file"),
|
||||||
getopts::optflag("s", "status", "don't output anything, status code shows success"),
|
getopts::optflag("s", "status", "don't output anything, status code shows success"),
|
||||||
getopts::optflag("", "strict", "exit non-zero for improperly formatted checksum lines"),
|
getopts::optflag("", "strict", "exit non-zero for improperly formatted checksum lines"),
|
||||||
|
@ -111,19 +108,19 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
||||||
getopts::optflag("V", "version", "output version information and exit"),
|
getopts::optflag("V", "version", "output version information and exit"),
|
||||||
);
|
);
|
||||||
|
|
||||||
opts.extend(get_algo_opts(binary_name.as_slice()).into_iter());
|
opts.extend(get_algo_opts(binary_name).into_iter());
|
||||||
|
|
||||||
let matches = match getopts::getopts(args.tail(), opts.as_slice()) {
|
let matches = match getopts::getopts(&args[1..], &opts) {
|
||||||
Ok(m) => m,
|
Ok(m) => m,
|
||||||
Err(f) => crash!(1, "{}", f)
|
Err(f) => crash!(1, "{}", f)
|
||||||
};
|
};
|
||||||
|
|
||||||
if matches.opt_present("help") {
|
if matches.opt_present("help") {
|
||||||
usage(program.as_slice(), binary_name.as_slice(), opts.as_slice());
|
usage(program, binary_name, &opts);
|
||||||
} else if matches.opt_present("version") {
|
} else if matches.opt_present("version") {
|
||||||
version();
|
version();
|
||||||
} else {
|
} else {
|
||||||
let (name, algo) = detect_algo(binary_name.as_slice(), &matches);
|
let (name, algo) = detect_algo(binary_name, &matches);
|
||||||
|
|
||||||
let binary_flag = matches.opt_present("binary");
|
let binary_flag = matches.opt_present("binary");
|
||||||
let text_flag = matches.opt_present("text");
|
let text_flag = matches.opt_present("text");
|
||||||
|
@ -168,7 +165,7 @@ fn usage(program: &str, binary_name: &str, opts: &[getopts::OptGroup]) {
|
||||||
pipe_print!("{}", getopts::usage("Compute and check message digests.", opts));
|
pipe_print!("{}", getopts::usage("Compute and check message digests.", opts));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hashsum(algoname: &str, mut digest: Box<Digest>, files: Vec<String>, binary: bool, check: bool, tag: bool, status: bool, quiet: bool, strict: bool, warn: bool) -> Result<(), i32> {
|
fn hashsum<'a>(algoname: &str, mut digest: Box<Digest+'a>, files: Vec<String>, binary: bool, check: bool, tag: bool, status: bool, quiet: bool, strict: bool, warn: bool) -> Result<(), i32> {
|
||||||
let mut bad_format = 0;
|
let mut bad_format = 0;
|
||||||
let mut failed = 0;
|
let mut failed = 0;
|
||||||
let binary_marker = if binary {
|
let binary_marker = if binary {
|
||||||
|
@ -177,16 +174,16 @@ fn hashsum(algoname: &str, mut digest: Box<Digest>, files: Vec<String>, binary:
|
||||||
" "
|
" "
|
||||||
};
|
};
|
||||||
for filename in files.iter() {
|
for filename in files.iter() {
|
||||||
let filename: &str = filename.as_slice();
|
let filename: &str = filename;
|
||||||
let mut stdin_buf;
|
let mut stdin_buf;
|
||||||
let mut file_buf;
|
let mut file_buf;
|
||||||
let mut file = BufferedReader::new(
|
let mut file = BufReader::new(
|
||||||
if filename == "-" {
|
if filename == "-" {
|
||||||
stdin_buf = stdin_raw();
|
stdin_buf = stdin();
|
||||||
&mut stdin_buf as &mut Reader
|
Box::new(stdin_buf) as Box<Read>
|
||||||
} else {
|
} else {
|
||||||
file_buf = safe_unwrap!(File::open(&Path::new(filename)));
|
file_buf = safe_unwrap!(File::open(filename));
|
||||||
&mut file_buf as &mut Reader
|
Box::new(file_buf) as Box<Read>
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if check {
|
if check {
|
||||||
|
@ -194,30 +191,30 @@ fn hashsum(algoname: &str, mut digest: Box<Digest>, files: Vec<String>, binary:
|
||||||
let bytes = digest.output_bits() / 4;
|
let bytes = digest.output_bits() / 4;
|
||||||
let gnu_re = safe_unwrap!(
|
let gnu_re = safe_unwrap!(
|
||||||
Regex::new(
|
Regex::new(
|
||||||
format!(
|
&format!(
|
||||||
r"^(?P<digest>[a-fA-F0-9]{{{}}}) (?P<binary>[ \*])(?P<fileName>.*)",
|
r"^(?P<digest>[a-fA-F0-9]{{{}}}) (?P<binary>[ \*])(?P<fileName>.*)",
|
||||||
bytes
|
bytes
|
||||||
).as_slice()
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
let bsd_re = safe_unwrap!(
|
let bsd_re = safe_unwrap!(
|
||||||
Regex::new(
|
Regex::new(
|
||||||
format!(
|
&format!(
|
||||||
r"^{algorithm} \((?P<fileName>.*)\) = (?P<digest>[a-fA-F0-9]{{{digest_size}}})",
|
r"^{algorithm} \((?P<fileName>.*)\) = (?P<digest>[a-fA-F0-9]{{{digest_size}}})",
|
||||||
algorithm = algoname,
|
algorithm = algoname,
|
||||||
digest_size = bytes
|
digest_size = bytes
|
||||||
).as_slice()
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut buffer = file;
|
let buffer = file;
|
||||||
for (i, line) in buffer.lines().enumerate() {
|
for (i, line) in buffer.lines().enumerate() {
|
||||||
let line = safe_unwrap!(line);
|
let line = safe_unwrap!(line);
|
||||||
let (ck_filename, sum, binary_check) = match gnu_re.captures(line.as_slice()) {
|
let (ck_filename, sum, binary_check) = match gnu_re.captures(&line) {
|
||||||
Some(caps) => (caps.name("fileName").unwrap(),
|
Some(caps) => (caps.name("fileName").unwrap(),
|
||||||
caps.name("digest").unwrap().to_ascii_lowercase(),
|
caps.name("digest").unwrap().to_ascii_lowercase(),
|
||||||
caps.name("binary").unwrap() == "*"),
|
caps.name("binary").unwrap() == "*"),
|
||||||
None => match bsd_re.captures(line.as_slice()) {
|
None => match bsd_re.captures(&line) {
|
||||||
Some(caps) => (caps.name("fileName").unwrap(),
|
Some(caps) => (caps.name("fileName").unwrap(),
|
||||||
caps.name("digest").unwrap().to_ascii_lowercase(),
|
caps.name("digest").unwrap().to_ascii_lowercase(),
|
||||||
true),
|
true),
|
||||||
|
@ -233,10 +230,11 @@ fn hashsum(algoname: &str, mut digest: Box<Digest>, files: Vec<String>, binary:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let mut ckf = safe_unwrap!(File::open(&Path::new(ck_filename)));
|
let f = safe_unwrap!(File::open(ck_filename));
|
||||||
|
let mut ckf = BufReader::new(Box::new(f) as Box<Read>);
|
||||||
let real_sum = safe_unwrap!(digest_reader(&mut digest, &mut ckf, binary_check))
|
let real_sum = safe_unwrap!(digest_reader(&mut digest, &mut ckf, binary_check))
|
||||||
.as_slice().to_ascii_lowercase();
|
.to_ascii_lowercase();
|
||||||
if sum.as_slice() == real_sum.as_slice() {
|
if sum == real_sum {
|
||||||
if !quiet {
|
if !quiet {
|
||||||
pipe_println!("{}: OK", ck_filename);
|
pipe_println!("{}: OK", ck_filename);
|
||||||
}
|
}
|
||||||
|
@ -270,21 +268,21 @@ fn hashsum(algoname: &str, mut digest: Box<Digest>, files: Vec<String>, binary:
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn digest_reader(digest: &mut Box<Digest>, reader: &mut Reader, binary: bool) -> Result<String, IoError> {
|
fn digest_reader<'a, T: Read>(digest: &mut Box<Digest+'a>, reader: &mut BufReader<T>, binary: bool) -> io::Result<String> {
|
||||||
digest.reset();
|
digest.reset();
|
||||||
|
|
||||||
// Digest file, do not hold too much in memory at any given moment
|
// Digest file, do not hold too much in memory at any given moment
|
||||||
let windows = cfg!(windows);
|
let windows = cfg!(windows);
|
||||||
let mut buffer = [0; 524288];
|
let mut buffer = Vec::with_capacity(524288);
|
||||||
let mut vec = Vec::with_capacity(524288);
|
let mut vec = Vec::with_capacity(524288);
|
||||||
let mut looking_for_newline = false;
|
let mut looking_for_newline = false;
|
||||||
loop {
|
loop {
|
||||||
match reader.read(&mut buffer) {
|
match reader.read_to_end(&mut buffer) {
|
||||||
Ok(0) => {},
|
Ok(0) => { break; },
|
||||||
Ok(nread) => {
|
Ok(nread) => {
|
||||||
if windows && !binary {
|
if windows && !binary {
|
||||||
// Windows text mode returns '\n' when reading '\r\n'
|
// Windows text mode returns '\n' when reading '\r\n'
|
||||||
for i in range(0, nread) {
|
for i in 0 .. nread {
|
||||||
if looking_for_newline {
|
if looking_for_newline {
|
||||||
if buffer[i] != ('\n' as u8) {
|
if buffer[i] != ('\n' as u8) {
|
||||||
vec.push('\r' as u8);
|
vec.push('\r' as u8);
|
||||||
|
@ -299,25 +297,18 @@ fn digest_reader(digest: &mut Box<Digest>, reader: &mut Reader, binary: bool) ->
|
||||||
looking_for_newline = true;
|
looking_for_newline = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
digest.input(vec.as_slice());
|
digest.input(&vec);
|
||||||
vec.clear();
|
vec.clear();
|
||||||
} else {
|
} else {
|
||||||
digest.input(&buffer[..nread]);
|
digest.input(&buffer[..nread]);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(e) => match e.kind {
|
Err(e) => return Err(e)
|
||||||
EndOfFile => {
|
|
||||||
break;
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
return Err(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if windows && looking_for_newline {
|
if windows && looking_for_newline {
|
||||||
vec.push('\r' as u8);
|
vec.push('\r' as u8);
|
||||||
digest.input(vec.as_slice());
|
digest.input(&vec);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(digest.result_str())
|
Ok(digest.result_str())
|
||||||
|
|
|
@ -21,13 +21,15 @@ use std::path::Path;
|
||||||
static NAME: &'static str = "uutils";
|
static NAME: &'static str = "uutils";
|
||||||
static VERSION: &'static str = "1.0.0";
|
static VERSION: &'static str = "1.0.0";
|
||||||
|
|
||||||
fn util_map() -> HashMap<&'static str, fn(Vec<String>) -> i32> {
|
type UtilityMap = HashMap<&'static str, fn(Vec<String>) -> i32>;
|
||||||
let mut map = HashMap::new();
|
|
||||||
|
fn util_map() -> UtilityMap {
|
||||||
|
let mut map: UtilityMap = HashMap::new();
|
||||||
@UTIL_MAP@
|
@UTIL_MAP@
|
||||||
map
|
map
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(cmap: &HashMap<&'static str, fn(Vec<String>) -> i32>) {
|
fn usage(cmap: &UtilityMap) {
|
||||||
println!("{} {}", NAME, VERSION);
|
println!("{} {}", NAME, VERSION);
|
||||||
println!("");
|
println!("");
|
||||||
println!("Usage:");
|
println!("Usage:");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue