Fix truncate and related tests.

This commit is contained in:
Joseph Crail 2015-04-29 19:20:51 -04:00
parent 3eb1d124ec
commit 5ec7f28625
2 changed files with 75 additions and 79 deletions

View file

@ -1,5 +1,5 @@
#![crate_name = "truncate"] #![crate_name = "truncate"]
#![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.
@ -14,8 +14,9 @@ extern crate getopts;
extern crate libc; extern crate libc;
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
use std::old_io::{File, Open, ReadWrite, fs}; use std::fs::{File, metadata, OpenOptions};
use std::old_io::fs::PathExtensions; use std::io::{Result, Write};
use std::path::Path;
#[path = "../common/util.rs"] #[path = "../common/util.rs"]
#[macro_use] #[macro_use]
@ -45,7 +46,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
getopts::optflag("h", "help", "display this help and exit"), getopts::optflag("h", "help", "display this help and exit"),
getopts::optflag("V", "version", "output version information and exit") getopts::optflag("V", "version", "output version information and exit")
]; ];
let matches = match getopts::getopts(args.tail(), &opts) { let matches = match getopts::getopts(&args[1..], &opts) {
Ok(m) => m, Ok(m) => m,
Err(f) => { Err(f) => {
crash!(1, "{}", f) crash!(1, "{}", f)
@ -92,7 +93,7 @@ file based on its current size:
} else { } else {
match truncate(no_create, io_blocks, reference, size, matches.free) { match truncate(no_create, io_blocks, reference, size, matches.free) {
Ok(()) => ( /* pass */ ), Ok(()) => ( /* pass */ ),
Err(e) => return e Err(_) => return 1
} }
} }
} }
@ -100,59 +101,54 @@ file based on its current size:
0 0
} }
fn truncate(no_create: bool, _: bool, reference: Option<String>, size: Option<String>, filenames: Vec<String>) -> Result<(), i32> {
fn truncate(no_create: bool, _: bool, reference: Option<String>, size: Option<String>, filenames: Vec<String>) -> Result<()> {
let (refsize, mode) = match reference { let (refsize, mode) = match reference {
Some(rfilename) => { Some(rfilename) => {
let rfile = match File::open(&Path::new(rfilename.clone())) { let _ = match File::open(Path::new(&rfilename)) {
Ok(m) => m, Ok(m) => m,
Err(f) => { Err(f) => {
crash!(1, "{}", f.to_string()) crash!(1, "{}", f.to_string())
} }
}; };
match fs::stat(rfile.path()) { match metadata(rfilename) {
Ok(stat) => (stat.size, TruncateMode::Reference), Ok(meta) => (meta.len(), TruncateMode::Reference),
Err(f) => { Err(f) => {
show_error!("{}", f.to_string()); crash!(1, "{}", f.to_string())
return Err(1);
} }
} }
} }
None => parse_size(size.unwrap().as_slice()) None => parse_size(size.unwrap().as_ref())
}; };
for filename in filenames.iter() { for filename in filenames.iter() {
let filename = filename.as_slice();
let path = Path::new(filename); let path = Path::new(filename);
if path.exists() || !no_create { match OpenOptions::new().read(true).write(true).create(!no_create).open(path) {
match File::open_mode(&path, Open, ReadWrite) { Ok(file) => {
Ok(mut file) => { let fsize = match metadata(filename) {
let fsize = match fs::stat(file.path()) { Ok(meta) => meta.len(),
Ok(stat) => stat.size, Err(f) => {
Err(f) => { show_warning!("{}", f.to_string());
show_warning!("{}", f.to_string()); continue;
continue;
}
};
let tsize = match mode {
TruncateMode::Reference => refsize,
TruncateMode::Extend => fsize + refsize,
TruncateMode::Reduce => fsize - refsize,
TruncateMode::AtMost => if fsize > refsize { refsize } else { fsize },
TruncateMode::AtLeast => if fsize < refsize { refsize } else { fsize },
TruncateMode::RoundDown => fsize - fsize % refsize,
TruncateMode::RoundUp => fsize + fsize % refsize
};
match file.truncate(tsize as i64) {
Ok(_) => {}
Err(f) => {
show_error!("{}", f.to_string());
return Err(1);
}
} }
} };
Err(f) => { let tsize: u64 = match mode {
show_error!("{}", f.to_string()); TruncateMode::Reference => refsize,
return Err(1); TruncateMode::Extend => fsize + refsize,
} TruncateMode::Reduce => fsize - refsize,
TruncateMode::AtMost => if fsize > refsize { refsize } else { fsize },
TruncateMode::AtLeast => if fsize < refsize { refsize } else { fsize },
TruncateMode::RoundDown => fsize - fsize % refsize,
TruncateMode::RoundUp => fsize + fsize % refsize
};
let _ = match file.set_len(tsize) {
Ok(_) => {},
Err(f) => {
crash!(1, "{}", f.to_string())
}
};
}
Err(f) => {
crash!(1, "{}", f.to_string())
} }
} }
} }
@ -160,7 +156,7 @@ fn truncate(no_create: bool, _: bool, reference: Option<String>, size: Option<St
} }
fn parse_size(size: &str) -> (u64, TruncateMode) { fn parse_size(size: &str) -> (u64, TruncateMode) {
let mode = match size.char_at(0) { let mode = match size.chars().next().unwrap() {
'+' => TruncateMode::Extend, '+' => TruncateMode::Extend,
'-' => TruncateMode::Reduce, '-' => TruncateMode::Reduce,
'<' => TruncateMode::AtMost, '<' => TruncateMode::AtMost,
@ -177,43 +173,43 @@ fn parse_size(size: &str) -> (u64, TruncateMode) {
} else { } else {
&size[1..] &size[1..]
}; };
if slice.char_at(slice.len() - 1).is_alphabetic() { if slice.chars().last().unwrap().is_alphabetic() {
slice = &slice[..slice.len() - 1]; slice = &slice[..slice.len() - 1];
if slice.len() > 0 && slice.char_at(slice.len() - 1).is_alphabetic() { if slice.len() > 0 && slice.chars().last().unwrap().is_alphabetic() {
slice = &slice[..slice.len() - 1]; slice = &slice[..slice.len() - 1];
} }
} }
slice slice
}.to_string(); }.to_string();
let mut number: u64 = match bytes.as_slice().parse() { let mut number: u64 = match bytes.parse() {
Ok(num) => num, Ok(num) => num,
Err(e) => { Err(e) => {
crash!(1, "'{}' is not a valid number: {}", size, e) crash!(1, "'{}' is not a valid number: {}", size, e)
} }
}; };
if size.char_at(size.len() - 1).is_alphabetic() { if size.chars().last().unwrap().is_alphabetic() {
number *= match size.char_at(size.len() - 1).to_ascii_uppercase() { number *= match size.chars().last().unwrap().to_ascii_uppercase() {
'B' => match size.char_at(size.len() - 2).to_ascii_uppercase() { 'B' => match size.chars().nth(size.len() - 2).unwrap().to_ascii_uppercase() {
'K' => 1000, 'K' => 1000u64,
'M' => 1000 * 1000, 'M' => 1000u64.pow(2),
'G' => 1000 * 1000 * 1000, 'G' => 1000u64.pow(3),
'T' => 1000 * 1000 * 1000 * 1000, 'T' => 1000u64.pow(4),
'P' => 1000 * 1000 * 1000 * 1000 * 1000, 'P' => 1000u64.pow(5),
'E' => 1000 * 1000 * 1000 * 1000 * 1000 * 1000, 'E' => 1000u64.pow(6),
'Z' => 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000, 'Z' => 1000u64.pow(7),
'Y' => 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000, 'Y' => 1000u64.pow(8),
letter => { letter => {
crash!(1, "'{}B' is not a valid suffix.", letter) crash!(1, "'{}B' is not a valid suffix.", letter)
} }
}, },
'K' => 1024, 'K' => 1024u64,
'M' => 1024 * 1024, 'M' => 1024u64.pow(2),
'G' => 1024 * 1024 * 1024, 'G' => 1024u64.pow(3),
'T' => 1024 * 1024 * 1024 * 1024, 'T' => 1024u64.pow(4),
'P' => 1024 * 1024 * 1024 * 1024 * 1024, 'P' => 1024u64.pow(5),
'E' => 1024 * 1024 * 1024 * 1024 * 1024 * 1024, 'E' => 1024u64.pow(6),
'Z' => 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024, 'Z' => 1024u64.pow(7),
'Y' => 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024, 'Y' => 1024u64.pow(8),
letter => { letter => {
crash!(1, "'{}' is not a valid suffix.", letter) crash!(1, "'{}' is not a valid suffix.", letter)
} }

View file

@ -1,14 +1,14 @@
#![allow(unstable)] use std::fs::{File, remove_file};
use std::io::{Seek, SeekFrom, Write};
use std::old_io as io; use std::path::Path;
use std::old_io::process::Command; use std::process::Command;
static PROGNAME: &'static str = "./truncate"; static PROGNAME: &'static str = "./truncate";
static TFILE1: &'static str = "truncate_test_1"; static TFILE1: &'static str = "truncate_test_1";
static TFILE2: &'static str = "truncate_test_2"; static TFILE2: &'static str = "truncate_test_2";
fn make_file(name: &str) -> io::File { fn make_file(name: &str) -> File {
match io::File::create(&Path::new(name)) { match File::create(Path::new(name)) {
Ok(f) => f, Ok(f) => f,
Err(_) => panic!() Err(_) => panic!()
} }
@ -20,11 +20,11 @@ fn test_increase_file_size() {
if !Command::new(PROGNAME).args(&["-s", "+5K", TFILE1]).status().unwrap().success() { if !Command::new(PROGNAME).args(&["-s", "+5K", TFILE1]).status().unwrap().success() {
panic!(); panic!();
} }
file.seek(0, io::SeekEnd).unwrap(); file.seek(SeekFrom::End(0)).unwrap();
if file.tell().unwrap() != 5 * 1024 { if file.seek(SeekFrom::Current(0)).unwrap() != 5 * 1024 {
panic!(); panic!();
} }
io::fs::unlink(&Path::new(TFILE1)).unwrap(); remove_file(Path::new(TFILE1)).unwrap();
} }
#[test] #[test]
@ -34,10 +34,10 @@ fn test_decrease_file_size() {
if !Command::new(PROGNAME).args(&["--size=-4", TFILE2]).status().unwrap().success() { if !Command::new(PROGNAME).args(&["--size=-4", TFILE2]).status().unwrap().success() {
panic!(); panic!();
} }
file.seek(0, io::SeekEnd).unwrap(); file.seek(SeekFrom::End(0)).unwrap();
if file.tell().unwrap() != 6 { if file.seek(SeekFrom::Current(0)).unwrap() != 6 {
println!("{:?}", file.tell()); println!("{:?}", file.seek(SeekFrom::Current(0)));
panic!(); panic!();
} }
io::fs::unlink(&Path::new(TFILE2)).unwrap(); remove_file(Path::new(TFILE2)).unwrap();
} }