-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcat.rs
71 lines (59 loc) · 1.74 KB
/
cat.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
//! Output a file.
use ap_storage::{file::File, msg2err, Error, FileSystem, Read};
use ap_storage_linux::LinuxDiskRO;
use gumdrop::Options;
use std::io::Write;
#[derive(Debug, Options)]
struct CommandOptions {
/// Print the help message.
help: bool,
/// Buffer size.
#[options(default = "65536")]
buffer: usize,
/// The bytes to skip.
skip: u64,
/// The bytes to skip in the disk file.
offset: u64,
/// Maximum number of bytes to read.
size: MaxSize,
/// Name of the file.
#[options(default = "/")]
start: String,
}
/// An u64 that is default u64::MAX.
#[derive(Debug)]
struct MaxSize(pub u64);
impl Default for MaxSize {
fn default() -> Self {
Self(u64::MAX)
}
}
impl core::str::FromStr for MaxSize {
type Err = core::num::ParseIntError;
fn from_str(v: &str) -> Result<Self, <Self as core::str::FromStr>::Err> {
Ok(Self(str::parse::<u64>(v)?))
}
}
fn main() -> Result<(), Error> {
let opts = CommandOptions::parse_args_default_or_exit();
let disk = LinuxDiskRO::new("/dev/stdin", opts.offset)?;
let fs = ap_storage_unified::UnifiedFs::new(&disk).ok_or(msg2err!("no filesystem found"))?;
let start = &opts.start;
let file = fs.root()?.lookup_path(start.as_bytes())?;
let mut buf = vec![0; opts.buffer];
let mut offset = opts.skip;
let mut stdout = std::io::stdout();
let mut size = opts.size.0;
while size != 0 {
let maxn = core::cmp::min(buf.len() as u64, size) as usize;
match file.read_bytes(offset, &mut buf[..maxn])? {
0 => break,
n => {
stdout.write_all(&buf[..n])?;
offset += n as u64;
size -= n as u64;
}
}
}
Ok(())
}