1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
//! rust-fs-btrfs — pure-Rust Btrfs filesystem driver.
//!
//! Exposes a stable C ABI (`fs_btrfs_*`) so FFI consumers (Swift/C/Go/…)
//! can link `libfs_btrfs.a` and `#include "fs_btrfs.h"`.
//!
//! # Byte order
//!
//! Btrfs is **little-endian on disk** on every host, checksums included.
//! Every on-disk integer in this crate is decoded with `from_le_bytes`.
//! That is worth stating up front because the sister XFS driver is
//! big-endian *except* for its CRC, and carrying either half of that
//! habit across produces a reader that agrees with its own test fixtures
//! and with nothing else.
//!
//! # Reading order
//!
//! Btrfs addresses everything — tree roots, node children, file extents —
//! in a single flat logical address space, and the table that translates
//! it lives inside the filesystem it describes. Bootstrapping therefore
//! runs in a fixed order:
//!
//! 1. Read the superblock from a fixed physical offset
//! ([`superblock::SUPER_OFFSETS`]) and verify its checksum.
//! 2. Build the bootstrap address map from the superblock's embedded
//! `sys_chunk_array` ([`chunk::ChunkMap::bootstrap`]).
//! 3. Use that map to reach the chunk tree, and extend the map with
//! every chunk item it holds.
//! 4. Only then is `root` — and through it the rest of the volume —
//! readable.
//!
//! All four steps are implemented, in [`fs::Filesystem::mount`].
//!
//! # Status
//!
//! Reads a volume -- directories, files including compressed extents,
//! symlinks, extended attributes, subvolumes, multi-device pools. It
//! writes file data in place to files marked nodatacow and nodatasum
//! ([`fs::Filesystem::write_at`]: no tree is rewritten and no generation
//! committed), and copy-on-write to files that are nodatasum but not
//! nodatacow ([`fs::Filesystem::write`], see [`cow_write`]): each extent
//! touched is copied into a new one and the change committed as a
//! transaction through the transaction and commit modules. Checksummed
//! files, growing a file and shared extents are still refused. Unit tests here are
//! deliberately treated as necessary-but-not-sufficient: a fixture this
//! crate builds itself cannot catch this crate misreading the on-disk
//! format, because the misreading would be baked into both sides.
//! Correctness against real media is established by cross-validating
//! against `mkfs.btrfs` output and the kernel's own writes.
//!
//! Architecture:
//! - [`error`] — driver error type, mapped to errno by the C ABI
//! - [`superblock`] — superblock parse + validation, checksum algorithms,
//! feature gating; [`super_write`] re-stamps it for a commit
//! - [`chunk`] — chunk items and the logical-to-physical address map
//! - [`btree`] — tree blocks, descent and walks; [`leaf_edit`] and
//! [`tree_write`] build new ones
//! - [`fs`] — the mounted volume: inodes, directories, file data;
//! [`inode`], [`dir`], [`xattr`], [`subvol`], [`compression`] and
//! [`csum`] each decode one kind of item
//! - [`write`](mod@write) — the in-place file write, which commits nothing
//! - [`cow_write`] — the copy-on-write file write, which commits a transaction
//! - [`transaction`], [`extent_write`], [`block_group`] and [`commit`] — tree
//! rewrites and the commit of a new generation, separate from file writes
//! - [`capi`] — the C ABI
pub use ;
pub use ;
pub use Filesystem;
pub use ;
pub use XattrEntry;
// DOES THIS BUILD ACTUALLY TRAP AN ARITHMETIC OVERFLOW?
//
// Inline in `lib.rs` rather than a module of its own under `src/`: a
// separate file hangs off one `mod` line, and losing that line leaves
// the file present, uncompiled and asserting nothing, with no lint to
// say so. That has already happened once on a sibling repository's
// version of this fix -- a `git reset --hard` took the declaration, the
// file stayed, and seven assertions quietly stopped existing. Inline,
// there is no declaration to lose. It cannot live in `tests/` either:
// the question it answers is about the library target that the debug
// run builds, so it has to be part of that target.