linuxutils_disk/
isosize.rs1use linuxutils_common::man::ManContent;
2
3pub const MAN: ManContent = ManContent::empty();
4
5use clap::Parser;
6use std::{
7 fs::File,
8 io::{Read, Seek, SeekFrom},
9 process::ExitCode,
10};
11
12const PVD_OFFSET: u64 = 0x8000;
13const PVD_TYPE_PRIMARY: u8 = 1;
14const CD001_MAGIC: &[u8; 5] = b"CD001";
15
16#[derive(Parser)]
17#[command(
18 name = "isosize",
19 about = "Output the length of an iso9660 filesystem",
20 override_usage = "isosize [options] <iso9660_image_file> ..."
21)]
22pub struct Args {
23 #[arg(short = 'x', long = "sectors")]
25 sectors: bool,
26
27 #[arg(
29 short = 'd',
30 long = "divisor",
31 value_name = "number",
32 default_value_t = 1
33 )]
34 divisor: u64,
35
36 #[arg(required = true)]
38 files: Vec<String>,
39}
40
41fn isosize(path: &str) -> Result<(u32, u16), String> {
42 let mut file = File::open(path)
43 .map_err(|e| format!("isosize: failed to open '{}': {}", path, e))?;
44
45 let mut pvd = [0u8; 132];
46 file.seek(SeekFrom::Start(PVD_OFFSET))
47 .map_err(|e| format!("isosize: failed to seek in '{}': {}", path, e))?;
48 file.read_exact(&mut pvd).map_err(|e| {
49 format!("isosize: failed to read from '{}': {}", path, e)
50 })?;
51
52 if pvd[0] != PVD_TYPE_PRIMARY || &pvd[1..6] != CD001_MAGIC {
53 return Err(format!(
54 "isosize: '{}': might not be an iso9660 filesystem",
55 path
56 ));
57 }
58
59 let block_count = u32::from_le_bytes([pvd[80], pvd[81], pvd[82], pvd[83]]);
60 let block_size = u16::from_le_bytes([pvd[128], pvd[129]]);
61
62 Ok((block_count, block_size))
63}
64
65pub fn run(args: Args) -> ExitCode {
66 if args.divisor == 0 {
67 eprintln!("isosize: invalid divisor: 0");
68 return ExitCode::from(1);
69 }
70
71 let multiple = args.files.len() > 1;
72 let mut failures = 0usize;
73
74 for path in &args.files {
75 match isosize(path) {
76 Ok((block_count, block_size)) => {
77 let prefix = if multiple {
78 format!("{}\t", path)
79 } else {
80 String::new()
81 };
82
83 if args.sectors {
84 println!(
85 "{}sector count: {}, sector size: {}",
86 prefix, block_count, block_size
87 );
88 } else {
89 let size = block_size as u64 * block_count as u64;
90 println!("{}{}", prefix, size / args.divisor);
91 }
92 }
93 Err(e) => {
94 eprintln!("{}", e);
95 failures += 1;
96 }
97 }
98 }
99
100 if failures == args.files.len() {
101 ExitCode::from(32)
102 } else if failures > 0 {
103 ExitCode::from(64)
104 } else {
105 ExitCode::SUCCESS
106 }
107}