#![allow(dead_code)]
use std::{
ffi::{OsStr, OsString},
fmt::{self, Display, Formatter},
mem::size_of,
time::SystemTime,
};
use bincode::{Decode, Encode};
pub const FS_UFS2_MAGIC: i32 = 0x19540119;
pub const MAGIC_OFFSET: u64 = 1372;
pub const CG_MAGIC: i32 = 0x090255;
pub const SBLOCK_UFS2: usize = 65536;
pub const SBLOCKSIZE: usize = 8192;
pub const CGSIZE: usize = 32768;
pub const MAXFRAG: usize = 8;
pub type UfsTime = i64;
pub type UfsDaddr = i64;
pub const DIRBLKSIZE: usize = 512;
#[derive(Debug, Decode, Encode, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[repr(transparent)]
pub struct InodeNum(u32);
impl InodeNum {
pub const ROOT: Self = Self(2);
pub fn get(&self) -> u32 {
self.0
}
pub fn get64(&self) -> u64 {
self.0.into()
}
pub unsafe fn new(inr: u32) -> Self {
Self(inr)
}
}
pub const MAXMNTLEN: usize = 468;
pub const MAXVOLLEN: usize = 32;
pub const FSMAXSNAP: usize = 20;
pub const NOCSPTRS: usize = (128 / size_of::<usize>()) - 1;
pub const UFS_NXADDR: usize = 2;
pub const UFS_NDADDR: usize = 12;
pub const UFS_MAXNAMELEN: usize = 255;
pub const UFS_NIADDR: usize = 3;
pub const UFS_SLLEN: usize = (UFS_NDADDR + UFS_NIADDR) * size_of::<UfsDaddr>();
pub const UFS_INOSZ: usize = 256;
pub const UFS_EXTATTR_MAXNAMELEN: usize = 64;
pub const S_IFMT: u16 = 0o170000;
pub const S_IFIFO: u16 = 0o010000;
pub const S_IFCHR: u16 = 0o020000;
pub const S_IFDIR: u16 = 0o040000;
pub const S_IFBLK: u16 = 0o060000;
pub const S_IFREG: u16 = 0o100000;
pub const S_IFLNK: u16 = 0o120000;
pub const S_IFSOCK: u16 = 0o140000;
pub const DT_UNKNOWN: u8 = 0;
pub const DT_FIFO: u8 = 1;
pub const DT_CHR: u8 = 2;
pub const DT_DIR: u8 = 4;
pub const DT_BLK: u8 = 6;
pub const DT_REG: u8 = 8;
pub const DT_LNK: u8 = 10;
pub const DT_SOCK: u8 = 12;
pub const DT_WHT: u8 = 14;
#[derive(Debug, Decode, Encode)]
pub struct Csum {
pub ndir: i32, pub nbfree: i32, pub nifree: i32, pub nffree: i32, }
#[derive(Debug, Decode, Encode)]
pub struct CsumTotal {
pub ndir: i64, pub nbfree: i64, pub nifree: i64, pub nffree: i64, pub numclusters: i64, pub spare: [i64; 3], }
#[derive(Debug, Decode, Encode)]
pub struct Superblock {
pub firstfield: i32, pub unused_1: i32, pub sblkno: i32, pub cblkno: i32, pub iblkno: i32, pub dblkno: i32, pub old_cgoffset: i32, pub old_cgmask: i32, pub old_time: i32, pub old_size: i32, pub old_dsize: i32, pub ncg: u32, pub bsize: i32, pub fsize: i32, pub frag: i32, pub minfree: i32, pub old_rotdelay: i32, pub old_rps: i32, pub bmask: i32, pub fmask: i32, pub bshift: i32, pub fshift: i32, pub fs_maxcontig: i32, pub fs_maxbpg: i32, pub fragshift: i32, pub fsbtodb: i32, pub sbsize: i32, pub spare1: [i32; 2], pub nindir: i32, pub inopb: u32, pub old_nspf: i32, pub optim: i32, pub old_npsect: i32, pub old_interleave: i32, pub old_trackskew: i32, pub id: [i32; 2], pub old_csaddr: i32, pub cssize: i32, pub cgsize: i32, pub spare2: i32, pub old_nsect: i32, pub old_spc: i32, pub old_ncyl: i32, pub old_cpg: i32, pub ipg: u32, pub fpg: i32, pub old_cstotal: Csum, pub fmod: i8, pub clean: i8, pub ronly: i8, pub old_flags: i8, pub fsmnt: [u8; MAXMNTLEN], pub volname: [u8; MAXVOLLEN], pub swuid: u64, pub pad: i32, pub cgrotor: i32, pub ocsp: [usize; NOCSPTRS], pub si: usize, pub old_cpc: i32, pub maxbsize: i32, pub unrefs: i64, pub providersize: i64, pub metaspace: i64, pub sparecon64: [i64; 13], pub sblockactualloc: i64, pub sblockloc: i64, pub cstotal: CsumTotal, pub time: UfsTime, pub size: i64, pub dsize: i64, pub csaddr: UfsDaddr, pub pendingblocks: i64, pub pendinginodes: u32, pub snapinum: [u32; FSMAXSNAP], pub avgfilesize: u32, pub avgfpdir: u32, pub save_cgsize: i32, pub mtime: UfsTime, pub sujfree: i32, pub sparecon32: [i32; 21], pub ckhash: u32, pub metackhash: u32, pub flags: i32, pub contigsumsize: i32, pub maxsymlinklen: i32, pub old_inodefmt: i32, pub maxfilesize: u64, pub qbmask: i64, pub qfmask: i64, pub state: i32, pub old_postblformat: i32, pub old_nrpos: i32, pub spare5: [i32; 2], pub magic: i32, }
#[derive(Debug, Decode, Encode)]
#[allow(dead_code)]
pub struct CylGroup {
pub firstfield: i32, pub magic: i32, pub old_time: i32, pub cgx: u32, pub old_ncyl: i16, pub old_niblk: i16, pub ndblk: u32, pub cs: Csum, pub rotor: u32, pub frotor: u32, pub irotor: u32, pub frsum: [u32; MAXFRAG], pub old_btotoff: i32, pub old_boff: i32, pub iusedoff: u32, pub freeoff: u32, pub nextfreeoff: u32, pub clustersumoff: u32, pub clusteroff: u32, pub nclusterblks: u32, pub niblk: u32, pub initediblk: u32, pub unrefs: u32, pub sparecon32: [i32; 1], pub ckhash: u32, pub time: UfsTime, pub sparecon64: [i64; 3], }
#[derive(Debug, Default, Clone, Decode, Encode)]
pub struct InodeBlocks {
pub direct: [UfsDaddr; UFS_NDADDR],
pub indirect: [UfsDaddr; UFS_NIADDR],
}
#[derive(Debug, Clone)]
pub enum InodeData {
Blocks(InodeBlocks),
Shortlink([u8; UFS_SLLEN]),
}
#[allow(dead_code)]
#[derive(Debug, Encode)]
pub struct Inode {
pub mode: u16, pub nlink: u16, pub uid: u32, pub gid: u32, pub blksize: u32, pub size: u64, pub blocks: u64, pub atime: UfsTime, pub mtime: UfsTime, pub ctime: UfsTime, pub birthtime: UfsTime, pub mtimensec: u32, pub atimensec: u32, pub ctimensec: u32, pub birthnsec: u32, pub gen: u32, pub kernflags: u32, pub flags: u32, pub extsize: u32, pub extb: [UfsDaddr; UFS_NXADDR], pub data: InodeData, pub modrev: u64, pub ignored: u32, pub ckhash: u32, pub spare: [u32; 2], }
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum InodeType {
RegularFile,
Directory,
Symlink,
CharDevice,
BlockDevice,
Socket,
NamedPipe,
}
#[derive(Debug)]
#[doc(alias = "Stat")]
pub struct InodeAttr {
pub inr: InodeNum,
pub perm: u16,
pub kind: InodeType,
pub size: u64,
pub blocks: u64,
pub atime: SystemTime,
pub mtime: SystemTime,
pub ctime: SystemTime,
pub btime: SystemTime,
pub nlink: u16,
pub uid: u32,
pub gid: u32,
pub gen: u32,
pub blksize: u32,
pub flags: u32,
pub kernflags: u32,
pub extsize: u32,
}
pub enum InodeBlock {
Direct(usize),
Indirect1(usize),
Indirect2(usize, usize),
Indirect3(usize, usize, usize),
}
#[derive(Debug, Clone, Copy, Decode, PartialEq, Eq)]
#[repr(u8)]
pub enum ExtattrNamespace {
Empty = 0,
User = 1,
System = 2,
}
#[derive(Debug, Decode)]
pub struct ExtattrHeader {
pub len: u32,
pub namespace: u8,
pub contentpadlen: u8,
pub namelen: u8,
}
#[derive(Debug)]
pub struct BlockInfo {
pub off: u64,
pub blkidx: u64,
pub size: u64,
}
impl Superblock {
pub fn cgsize(&self) -> u64 {
self.fpg as u64 * self.fsize as u64
}
pub fn cgsize_struct(&self) -> usize {
size_of::<CylGroup>() +
howmany(self.fpg as usize, 8) +
howmany(self.ipg as usize, 8) +
size_of::<i32>() +
(if self.contigsumsize <= 0 {
0usize
} else {
self.contigsumsize as usize * size_of::<i32>() +
howmany(self.fpg as usize >> (self.fshift as usize), 8)
})
}
pub fn ino_to_cg(&self, inr: InodeNum) -> u64 {
inr.get64() / self.ipg as u64
}
pub fn ino_in_cg(&self, inr: InodeNum) -> (u64, u64) {
let ipg = self.ipg as u64;
let inr = inr.get64();
(inr / ipg, inr % ipg)
}
pub fn blocks_to_frags(&self, blocks: u64) -> u64 {
blocks << self.fragshift as u32
}
pub fn ino_to_fso(&self, inr: InodeNum) -> u64 {
let ipg = self.ipg as u64;
let fpg = self.fpg as u64;
let fs = self.fsize as u64;
let cgi = inr.get64() / ipg;
let off = inr.get64() % ipg;
let cgstart = cgi * fpg * fs;
let cgistart = cgstart + (self.iblkno as u64 * fs);
cgistart + (off * UFS_INOSZ as u64)
}
}
const fn howmany(x: usize, y: usize) -> usize {
x.div_ceil(y)
}
impl ExtattrHeader {
pub fn namespace(&self) -> Option<ExtattrNamespace> {
match self.namespace {
0 => Some(ExtattrNamespace::Empty),
1 => Some(ExtattrNamespace::User),
2 => Some(ExtattrNamespace::System),
_ => None,
}
}
}
impl ExtattrNamespace {
pub fn with_name(self, name: &OsStr) -> OsString {
let ns = match self {
Self::Empty => "",
Self::User => "user.",
Self::System => "system.",
};
let mut out = OsString::from(ns);
out.push(name);
out
}
}
impl Display for InodeNum {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}