Skip to main content

Crate ufs

Crate ufs 

Source
Expand description

ufs-core — a pure-Rust, from-scratch UFS/FFS filesystem reader.

UFS = the Unix File System, a.k.a. the Berkeley Fast File System (FFS). Parses the on-disk UFS structures a forensic tool needs — superblock and geometry, cylinder-group headers and allocation bitmaps, inodes, directories, and file content — over any byte source. The reader targets both UFS1 (4.4BSD/FreeBSD legacy, 128-byte inodes, 32-bit block pointers, superblock at byte 8192, magic 0x00011954) and UFS2 (FreeBSD 5+, 256-byte inodes, 64-bit block pointers, superblock at byte 65536, magic 0x19540119).

Import path is ufs (see [lib] name): use ufs::Superblock;.

UFS is endianness-agnostic on disk — the byte order is that of the host that created the filesystem, and the superblock magic disambiguates it. The reader supports both little- and big-endian images, selecting the order by which interpretation makes the magic match (see Endian).

§Safety and robustness

This crate parses untrusted, attacker-controllable disk images. It is #![forbid(unsafe_code)] and every integer is read through bounds-checked readers that yield 0/None out of range rather than panic (the Paranoid Gatekeeper standard).

Re-exports§

pub use bytes::Endian;

Modules§

bytes
Bounds-checked readers for both byte orders (the Paranoid Gatekeeper standard).

Structs§

CylinderGroup
Parsed cylinder-group header — the per-group allocation map.
DirEntry
One decoded directory entry (struct direct).
Inode
A decoded UFS inode — the metadata and block-pointer arrays a forensic tool needs. Carries the union (superset) of the UFS1 and UFS2 dinode fields; UFS1-absent fields (birthtime) are None. #[non_exhaustive] so later phases add fields without a breaking change.
Superblock
Parsed UFS superblock — geometry and addressing fields the cylinder-group and inode decode (P1) need.
Timespec
A UFS timestamp: whole seconds since the Unix epoch plus a nanosecond fraction. UFS2 stores seconds as a signed 64-bit value; UFS1 as 32-bit (widened here). The nanosecond field is a signed 32-bit count.

Enums§

DirEntryType
A directory-entry file type (d_type, DT_* in dir.h).
FileType
The file type decoded from di_mode & IFMT.
UfsError
Errors surfaced while parsing UFS/FFS on-disk structures.
UfsVersion
The on-disk UFS version, resolved from the superblock magic.

Constants§

CG_MAGIC
The cylinder-group header magic (CG_MAGIC), at offset 4 of the header.
DIRBLKSIZ
The directory block size (DIRBLKSIZ) — a directory’s data is a sequence of these atomically-written blocks.
DIR_ROUNDUP
The directory-entry name roundup (DIR_ROUNDUP): names are padded to a 4-byte boundary.
FS_UFS1_MAGIC
UFS1 superblock magic (FS_UFS1_MAGIC), read at fs_magic (offset 1372).
FS_UFS2_MAGIC
UFS2 superblock magic (FS_UFS2_MAGIC), read at fs_magic (offset 1372).
SBLOCK_UFS1
Byte offset of the primary UFS1 superblock from the filesystem start (SBLOCK_UFS1).
SBLOCK_UFS2
Byte offset of the primary UFS2 superblock from the filesystem start (SBLOCK_UFS2).
UFS1_DINODE_SIZE
Size in bytes of a UFS1 dinode (sizeof(struct ufs1_dinode)).
UFS2_DINODE_SIZE
Size in bytes of a UFS2 dinode (sizeof(struct ufs2_dinode)).
UFS_NDADDR
Number of direct block pointers in a dinode (UFS_NDADDR).
UFS_NIADDR
Number of indirect block pointers in a dinode (UFS_NIADDR): single, double, and triple indirect.
UFS_ROOTINO
The UFS root inode number (UFS_ROOTINO).

Functions§

list_dir
Decode the directory entries of the directory inode dir_ino, returning the live entries (skipping d_ino == 0 free/deleted slots). See list_dir_all to also surface the deleted slots.
list_dir_all
Decode the directory entries of dir_ino, including d_ino == 0 free/deleted slots (flagged deleted). The forensic-relevant superset of list_dir — a deleted slot’s residual d_name bytes are preserved so an analyzer can recover them.
read_block
Read len bytes of a file’s block addr from partition (the filesystem partition bytes, filesystem byte 0). addr is a fragment address as stored in an inode’s di_db[]/di_ib[]; the byte offset is addr * fs_fsize.
read_by_path
Resolve an absolute path (e.g. "/a/b/c") to its (inode number, inode), descending from the root inode (UFS_ROOTINO = 2) and matching each component against the live directory entries at each level.
read_file
Assemble the full byte content of the file inode ino, walking its block map (direct di_db[0..12], then single/double/triple indirect via di_ib[0..3]) up to di_size. A hole (a 0 pointer, at any level of the tree) reads as zeros; the last block is sized to the remaining di_size (fragment tail).
read_inode
Locate and decode the inode numbered ino from partition, the filesystem partition bytes (filesystem byte 0 — a caller holding a whole disk image slices past the BSD-disklabel partition base first).
read_inode_file
Assemble the byte content of an already-decoded inode (the block-map walk read_file performs after locating the inode). Exposed so callers holding an Inode (e.g. after read_by_path) need not re-locate it.
read_path_content
Resolve an absolute path to its file content: read_by_path then read_file. Returns Ok(None) when the path does not resolve (like read_by_path); Ok(Some(bytes)) with the file’s di_size bytes otherwise.
read_symlink_target
The target of a symbolic-link inode. For a fast (inline) symlink (di_size <= fs_maxsymlinklen) the target lives in the block-pointer bytes of the dinode and is returned directly (P1 already decoded it — see Inode::symlink_target). For a slow symlink (di_size > fs_maxsymlinklen) the target is stored in the file’s data block(s), so it is read via the block map like any file’s content and truncated to di_size.