Skip to main content

btrfs_core/
lib.rs

1//! `btrfs-core` — a pure-Rust, from-scratch btrfs filesystem reader.
2//!
3//! Phase 0 parses the **superblock** (at physical offset 65536) — geometry,
4//! tree-root logical addresses, the checksum descriptor, and the
5//! `sys_chunk_array` bootstrap chunk map that seeds logical→physical translation
6//! — over any byte source. btrfs is little-endian on disk throughout.
7//!
8//! Phase 1 adds **B-tree node parsing and the chunk tree**: a [`Node`] decodes
9//! any `nodesize`-byte block (`btrfs_header` + leaf items or interior
10//! key-pointers, with non-fatal crc32c status), [`ChunkMap`] walks the chunk
11//! tree into a full logical→physical map, and [`read_node`] reads any node by
12//! its logical address.
13//!
14//! Phase 2 adds **root-tree navigation and FS-tree semantics**: [`fs_tree_root`]
15//! locates the FS_TREE's `ROOT_ITEM` in the root tree, and [`read_inode`],
16//! [`list_dir`], and [`read_by_path`] decode `btrfs_inode_item` metadata (size,
17//! mode, the four timestamps), directory entries (`DIR_ITEM`/`DIR_INDEX`), and
18//! resolve a slash-separated path from the FS_TREE root directory.
19//!
20//! Phase 3 adds **EXTENT_DATA → file content**: [`read_file`] /
21//! [`read_by_path_content`] assemble a file's bytes from its
22//! `btrfs_file_extent_item`s (inline, regular, prealloc, hole zero-fill),
23//! truncated to the inode's size, decompressing zlib / LZO / zstd extents via
24//! [`decompress_extent`] (batteries-included — the decoders are always compiled
25//! in, never feature-gated).
26//!
27//! Import path is `btrfs_core` (the bare `btrfs` crate on crates.io is an
28//! unrelated live-FS ioctl wrapper we do not shadow): `use btrfs_core::Superblock;`.
29//!
30//! # Safety and robustness
31//!
32//! This crate parses untrusted, attacker-controllable disk images. It is
33//! `#![forbid(unsafe_code)]` and every integer is read through bounds-checked
34//! little-endian helpers that yield `0`/`None` out of range rather than panic
35//! (the Paranoid Gatekeeper standard).
36
37#![forbid(unsafe_code)]
38#![cfg_attr(test, allow(clippy::unwrap_used, clippy::expect_used))]
39
40pub mod bytes;
41mod chunk;
42pub mod crc;
43mod error;
44mod extent;
45mod fstree;
46mod node;
47mod superblock;
48#[cfg(feature = "vfs")]
49pub mod vfs;
50
51pub use chunk::{
52    DiskKey, Stripe, SysChunk, BLOCK_GROUP_DATA, BLOCK_GROUP_DUP, BLOCK_GROUP_METADATA,
53    BLOCK_GROUP_SYSTEM, CHUNK_ITEM_KEY, DISK_KEY_SIZE, STRIPE_SIZE, SYS_CHUNK_ARRAY_OFFSET,
54};
55pub use crc::{superblock_crc_status, verify_superblock_crc32c, CsumType, BTRFS_CSUM_SIZE};
56pub use error::BtrfsError;
57pub use extent::{
58    decompress_extent, read_by_path_content, read_file, read_file_from_leaf, Compression,
59    EXTENT_DATA_KEY,
60};
61pub use fstree::{
62    fs_tree_root, list_dir, read_by_path, read_inode, DirEntry, DirItemType, FsTreeRoot, Inode,
63    Timestamp, DIR_INDEX_KEY, DIR_ITEM_KEY, FS_TREE_OBJECTID, FS_TREE_ROOT_DIR_OBJECTID,
64    INODE_ITEM_KEY, INODE_ITEM_SIZE, INODE_REF_KEY, ROOT_ITEM_KEY, TIMESTAMP_SIZE,
65};
66pub use node::{
67    read_node, Chunk, ChunkMap, Header, KeyPtr, Node, BTRFS_HEADER_SIZE, BTRFS_ITEM_SIZE,
68    BTRFS_KEY_PTR_SIZE, CHUNK_HEADER_SIZE, CHUNK_TREE_OBJECTID,
69};
70pub use superblock::{
71    Superblock, BTRFS_FSID_SIZE, BTRFS_LABEL_SIZE, BTRFS_MAGIC, BTRFS_SUPER_INFO_OFFSET,
72    BTRFS_SUPER_INFO_SIZE,
73};