mirror of
https://github.com/uutils/coreutils
synced 2024-11-16 01:38:04 +00:00
Fix truncate and related tests.
This commit is contained in:
parent
3eb1d124ec
commit
5ec7f28625
2 changed files with 75 additions and 79 deletions
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue