Initial import

This commit is contained in:
Moritz Bitsch 2021-06-14 18:07:37 +02:00
commit a7c17caebd
3 changed files with 143 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
/target
Cargo.lock

10
Cargo.toml Normal file
View file

@ -0,0 +1,10 @@
[package]
name = "e2size"
version = "0.1.0"
authors = ["Moritz Bitsch"]
edition = "2018"
[dependencies]
byteorder = "1.4.3"
positioned-io = "0.2.2"
thiserror = "1.0.25"

131
src/lib.rs Normal file
View file

@ -0,0 +1,131 @@
use byteorder::{ByteOrder, LittleEndian};
use positioned_io::ReadAt;
use thiserror::Error;
#[derive(Error, Debug)]
/// Errors returned by e2size
pub enum E2SizeError {
/// Error reading superblock
#[error("Can't read superblock")]
Read(#[from] std::io::Error),
/// Bad magic value of superblock (corrupt fs?)
#[error("Invalid magic value (expected: 0xEF53 got: 0x{0:X})")]
BadMagic(u16),
/// Blocksize was outside allowed range (corrupt fs?)
#[error("Invalid block size: {0}")]
InvalidBlockSize(u32),
/// Filesystem outside seekable range (corrupt fs?)
#[error("Filesystem too Big")]
FilesystemTooBig,
}
/// Retrieves the size of a ext2/3/4 filesystem in bytes
///
/// Reads the superblock (1024 bytes at 1024 byte offset) from reader
pub fn e2size<T>(reader: T) -> std::result::Result<u64, E2SizeError>
where
T: ReadAt,
{
let mut superblock = [0u8; 1024];
reader.read_exact_at(1024, &mut superblock)?;
let magic = LittleEndian::read_u16(&superblock[0x38..]);
if magic != 0xEF53 {
return Err(E2SizeError::BadMagic(magic));
}
let block_count = LittleEndian::read_u32(&superblock[0x4..]);
let block_size_shift = LittleEndian::read_u32(&superblock[0x18..]);
let block_size = 1u64
.checked_shl(10 + block_size_shift)
.ok_or_else(|| E2SizeError::InvalidBlockSize(block_size_shift))?;
(block_size as u64)
.checked_mul(block_count as u64)
.ok_or_else(|| E2SizeError::FilesystemTooBig)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[cfg(not(tarpaulin_include))]
fn valid_superblock() -> Result<(), E2SizeError> {
let mut superblock = [0u8; 2048];
LittleEndian::write_u16(&mut superblock[1024 + 0x38..], 0xEF53);
LittleEndian::write_u32(&mut superblock[1024 + 0x4..], 256);
LittleEndian::write_u32(&mut superblock[1024 + 0x18..], 2);
assert_eq!(e2size(&superblock[..])?, 1048576);
Ok(())
}
#[test]
#[cfg(not(tarpaulin_include))]
fn huge_filesystem() -> Result<(), E2SizeError> {
let mut superblock = [0u8; 2048];
LittleEndian::write_u16(&mut superblock[1024 + 0x38..], 0xEF53);
LittleEndian::write_u32(&mut superblock[1024 + 0x4..], 1 << 31);
LittleEndian::write_u32(&mut superblock[1024 + 0x18..], 22);
assert_eq!(e2size(&superblock[..])?, 9223372036854775808);
Ok(())
}
#[test]
#[cfg(not(tarpaulin_include))]
fn invalid_magic() -> Result<(), E2SizeError> {
let mut superblock = [0u8; 2048];
LittleEndian::write_u16(&mut superblock[1024 + 0x38..], 0xEF52);
LittleEndian::write_u32(&mut superblock[1024 + 0x4..], 1);
LittleEndian::write_u32(&mut superblock[1024 + 0x18..], 0);
match e2size(&superblock[..]) {
Err(E2SizeError::BadMagic(e)) => assert_eq!(e, 0xEF52),
_ => panic!("not reached!"),
};
Ok(())
}
#[test]
#[cfg(not(tarpaulin_include))]
fn invalid_block_size() -> Result<(), E2SizeError> {
let mut superblock = [0u8; 2048];
LittleEndian::write_u16(&mut superblock[1024 + 0x38..], 0xEF53);
LittleEndian::write_u32(&mut superblock[1024 + 0x4..], 1);
LittleEndian::write_u32(&mut superblock[1024 + 0x18..], 54);
match e2size(&superblock[..]) {
Err(E2SizeError::InvalidBlockSize(_)) => {}
Err(e) => panic!("not expected error: {}", e),
_ => panic!("not reached!"),
};
Ok(())
}
#[test]
#[cfg(not(tarpaulin_include))]
fn filesystem_too_big() -> Result<(), E2SizeError> {
let mut superblock = [0u8; 2048];
LittleEndian::write_u16(&mut superblock[1024 + 0x38..], 0xEF53);
LittleEndian::write_u32(&mut superblock[1024 + 0x4..], 1 << 31);
LittleEndian::write_u32(&mut superblock[1024 + 0x18..], 23);
match e2size(&superblock[..]) {
Err(E2SizeError::FilesystemTooBig) => {}
Err(e) => panic!("not expected error: {}", e),
_ => panic!("not reached!"),
};
Ok(())
}
}