Something went wrong. Try again.
An xz-compatible LZMA compression tool written in Rust
Something went wrong. Try again.
6.1 kB · 177 lines
Rust
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178//! Per-file driver: figure out output paths, open files, and call into//! the codec helpers.
use std::fs::{self, File};use std::io;use std::path::Path;
use crate::codec::{compress_stream, decompress_or_passthrough, decompress_stream_opts};use crate::options::{Format, Mode, Options};use crate::suffix::{compressed_suffixes, output_path_compress, output_path_decompress};
pub fn process_file(path: &str, opts: &Options) -> io::Result<()> { let input_path = Path::new(path);
if !input_path.exists() { return Err(io::Error::new( io::ErrorKind::NotFound, format!("{path}: No such file or directory"), )); }
match opts.mode { Mode::Compress => { let has_suffix = compressed_suffixes().iter().any(|s| path.ends_with(s)); if has_suffix && !opts.force && opts.suffix.is_none() { if !opts.quiet { eprintln!("xz: {path}: already has a compressed suffix, skipping"); } return Ok(()); }
if opts.stdout { let input = File::open(input_path)?; compress_stream( input, io::stdout().lock(), opts.level, opts.format, opts.filter.as_ref(), )?; return Ok(()); }
let output_path = match output_path_compress( input_path, opts.format, opts.suffix.as_deref(), ) { Some(p) => p, None => { return Err(io::Error::new( io::ErrorKind::InvalidInput, format!( "{path}: no suffix to use for output (use --suffix= with raw format)" ), )); } };
if output_path.exists() && !opts.force { return Err(io::Error::new( io::ErrorKind::AlreadyExists, format!( "{}: already exists; use -f to overwrite", output_path.display() ), )); } let input = File::open(input_path)?; let output = File::create(&output_path)?; compress_stream(input, output, opts.level, opts.format, opts.filter.as_ref())?;
if opts.verbose { eprintln!("xz: {path} -> {}", output_path.display()); }
if !opts.keep { fs::remove_file(input_path)?; } } Mode::Decompress => { // Raw mode requires an explicit --suffix= for both stdin // and file modes when writing back to a file. When writing // to stdout we still need it for *file* inputs because xz // can't infer the output name from a raw stream. if opts.format == Format::Raw && opts.suffix.is_none() { return Err(io::Error::new( io::ErrorKind::InvalidInput, format!("{path}: raw format requires --suffix="), )); }
// When writing to stdout we don't need a known suffix -- // xz happily decodes anything it can recognise. With -f // we additionally fall back to copying unrecognised input // verbatim (matches xz's `-dfc` behaviour). if opts.stdout { let input = File::open(input_path)?; if opts.force { decompress_or_passthrough( input, io::stdout().lock(), opts.no_warn, opts.format, opts.filter.as_ref(), )?; } else { decompress_stream_opts( input, io::stdout().lock(), opts.no_warn, opts.format, opts.filter.as_ref(), )?; } return Ok(()); }
let output_path = match output_path_decompress(input_path, opts.suffix.as_deref()) { Some(p) => p, None => { if !opts.quiet { eprintln!("xz: {path}: unknown suffix -- ignored"); } return Ok(()); } };
if output_path.exists() && !opts.force { return Err(io::Error::new( io::ErrorKind::AlreadyExists, format!( "{}: already exists; use -f to overwrite", output_path.display() ), )); } let input = File::open(input_path)?; let output = File::create(&output_path)?; decompress_stream_opts( input, output, opts.no_warn, opts.format, opts.filter.as_ref(), )?;
if opts.verbose { eprintln!("xz: {} -> {}", path, output_path.display()); }
if !opts.keep { fs::remove_file(input_path)?; } } Mode::Test => { let input = File::open(input_path)?; decompress_stream_opts( input, io::sink(), opts.no_warn, opts.format, opts.filter.as_ref(), )?; if opts.verbose { eprintln!("xz: {path}: OK"); } } Mode::List => { // -l file dispatch happens in main.rs; reaching here would // be a programming error. unreachable!("Mode::List handled in main()"); } }
Ok(())}