Skip to content
API Documentation
BastionGuard™
anonymous_namespace{btrfs_recovery.cpp} Namespace Reference

Classes

struct  BtrfsKey
struct  BtrfsItem
struct  BtrfsKeyPtr
struct  ChunkStripe
struct  ChunkMapEntry
struct  RootEntry
struct  InodeInfo
struct  DirEdge
struct  FileExtentInfo
struct  FsRootState

Functions

uint16_t le16 (const unsigned char *p)
uint32_t le32 (const unsigned char *p)
uint64_t le64 (const unsigned char *p)
std::string sanitize (const std::string &in)
std::string to_hex (uint64_t v)
BtrfsKey parse_key (const unsigned char *p)
bool decompress_payload (const std::vector< unsigned char > &in, uint8_t compression, size_t expected_size, std::vector< unsigned char > &out)
uint8_t gf_mul_byte (uint8_t a, uint8_t b)
uint8_t gf_pow2 (size_t exp)
uint8_t gf_inv_byte (uint8_t a)
uint32_t crc32c_update (uint32_t crc, const unsigned char *data, size_t len)
bool validate_tree_block_checksum (const std::vector< unsigned char > &block)
bool validate_tree_block_header (const std::vector< unsigned char > &block, uint64_t logical_bytenr, uint32_t nodesize, const std::array< unsigned char, 16 > *fsid=nullptr, uint64_t max_generation=0)

Variables

constexpr uint8_t BTRFS_INODE_ITEM_KEY = 1
constexpr uint8_t BTRFS_INODE_REF_KEY = 12
constexpr uint8_t BTRFS_DIR_ITEM_KEY = 84
constexpr uint8_t BTRFS_DIR_INDEX_KEY = 96
constexpr uint8_t BTRFS_EXTENT_DATA_KEY = 108
constexpr uint8_t BTRFS_ROOT_ITEM_KEY = 132
constexpr uint8_t BTRFS_ROOT_BACKREF_KEY = 144
constexpr uint8_t BTRFS_ROOT_REF_KEY = 156
constexpr uint8_t BTRFS_CHUNK_ITEM_KEY = 228
constexpr uint8_t BTRFS_FILE_EXTENT_INLINE = 0
constexpr uint8_t BTRFS_FILE_EXTENT_REG = 1
constexpr uint8_t BTRFS_FILE_EXTENT_PREALLOC = 2
constexpr uint64_t BTRFS_BLOCK_GROUP_RAID0 = 1ull << 3
constexpr uint64_t BTRFS_BLOCK_GROUP_RAID1 = 1ull << 4
constexpr uint64_t BTRFS_BLOCK_GROUP_DUP = 1ull << 5
constexpr uint64_t BTRFS_BLOCK_GROUP_RAID10 = 1ull << 6
constexpr uint64_t BTRFS_BLOCK_GROUP_RAID5 = 1ull << 7
constexpr uint64_t BTRFS_BLOCK_GROUP_RAID6 = 1ull << 8

Function Documentation

◆ crc32c_update()

uint32_t anonymous_namespace{btrfs_recovery.cpp}::crc32c_update ( uint32_t crc,
const unsigned char * data,
size_t len )

Definition at line 301 of file btrfs_recovery.cpp.

301 {
302 static uint32_t table[256]{};
303 static bool init = false;
304 if (!init) {
305 for (uint32_t i = 0; i < 256; ++i) {
306 uint32_t r = i;
307 for (int j = 0; j < 8; ++j) r = (r >> 1) ^ (0x82F63B78u & static_cast<uint32_t>(-(static_cast<int32_t>(r & 1u))));
308 table[i] = r;
309 }
310 init = true;
311 }
312 crc = ~crc;
313 for (size_t i = 0; i < len; ++i) crc = table[(crc ^ data[i]) & 0xFFu] ^ (crc >> 8);
314 return ~crc;
315}

References crc32c_update().

Referenced by crc32c_update(), and validate_tree_block_checksum().

◆ decompress_payload()

bool anonymous_namespace{btrfs_recovery.cpp}::decompress_payload ( const std::vector< unsigned char > & in,
uint8_t compression,
size_t expected_size,
std::vector< unsigned char > & out )

Definition at line 182 of file btrfs_recovery.cpp.

185 {
186 if (compression == 0) {
187 out = in;
188 if (out.size() > expected_size) out.resize(expected_size);
189 return true;
190 }
191#ifdef HAVE_ZLIB
192 if (compression == 1) {
193 // Btrfs zlib: single zlib stream per extent (max 128 KiB output).
194 out.resize(expected_size);
195 uLongf dest_len = static_cast<uLongf>(out.size());
196 int rc = ::uncompress(out.data(), &dest_len, in.data(), static_cast<uLong>(in.size()));
197 if (rc != Z_OK) return false;
198 out.resize(static_cast<size_t>(dest_len));
199 return true;
200 }
201#endif
202#ifdef HAVE_LZO
203 if (compression == 2) {
204 // Btrfs LZO chunked decoder.
205 constexpr size_t kBtrfsLzoPageSize = 4096;
206 if (in.size() < 4) return false;
207 const uint32_t total_len = le32(in.data());
208 if (total_len > in.size()) return false;
209 // Chunks start at offset 4 (after the total length header).
210 // The kernel writer pads chunks so that no chunk header straddles
211 // a 4 KiB page boundary in the COMPRESSED stream. We mirror that:
212 // when the next chunk header would straddle a page, we skip to
213 // the next page.
214 size_t pos = 4;
215 out.clear();
216 out.reserve(expected_size);
217 while (pos + 4 <= total_len && out.size() < expected_size) {
218 // Page-boundary skip: if a 4-byte chunk header would not fit
219 // in the remaining bytes of the current page, advance to the
220 // next page.
221 const size_t page_off = pos % kBtrfsLzoPageSize;
222 if (page_off + 4 > kBtrfsLzoPageSize) {
223 pos += kBtrfsLzoPageSize - page_off;
224 if (pos + 4 > total_len) break;
225 }
226 const uint32_t chunk_len = le32(in.data() + pos);
227 pos += 4;
228 if (chunk_len == 0 || chunk_len > total_len - pos) return false;
229
230 std::vector<unsigned char> chunk_out(kBtrfsLzoPageSize);
231 lzo_uint dest_len = static_cast<lzo_uint>(chunk_out.size());
232 const int rc = lzo1x_decompress_safe(
233 in.data() + pos, static_cast<lzo_uint>(chunk_len),
234 chunk_out.data(), &dest_len, nullptr);
235 if (rc != LZO_E_OK) return false;
236 chunk_out.resize(static_cast<size_t>(dest_len));
237 out.insert(out.end(), chunk_out.begin(), chunk_out.end());
238 pos += chunk_len;
239 }
240 if (out.size() > expected_size) out.resize(expected_size);
241 return true;
242 }
243#endif
244#ifdef HAVE_ZSTD
245 if (compression == 3) {
246 // Btrfs zstd chunked decoder.
247 // Format: per-chunk: __le32 chunk_len + <chunk_len bytes zstd frame>.
248 // Each chunk decompresses to up to 128 KiB.
249 constexpr size_t kBtrfsZstdMaxChunkOutput = 128 * 1024;
250 size_t pos = 0;
251 out.clear();
252 out.reserve(expected_size);
253 while (pos + 4 <= in.size() && out.size() < expected_size) {
254 const uint32_t chunk_len = le32(in.data() + pos);
255 pos += 4;
256 if (chunk_len == 0 || chunk_len > in.size() - pos) return false;
257
258 std::vector<unsigned char> chunk_out(kBtrfsZstdMaxChunkOutput);
259 const size_t rc = ZSTD_decompress(
260 chunk_out.data(), chunk_out.size(),
261 in.data() + pos, chunk_len);
262 if (ZSTD_isError(rc)) return false;
263 chunk_out.resize(rc);
264 out.insert(out.end(), chunk_out.begin(), chunk_out.end());
265 pos += chunk_len;
266 }
267 if (out.size() > expected_size) out.resize(expected_size);
268 return true;
269 }
270#endif
271 return false;
272}
uint32_t le32(const unsigned char *p)

References decompress_payload(), and le32().

Referenced by decompress_payload(), and BtrfsRecoveryImpl::render_extent().

◆ gf_inv_byte()

uint8_t anonymous_namespace{btrfs_recovery.cpp}::gf_inv_byte ( uint8_t a)

Definition at line 292 of file btrfs_recovery.cpp.

292 {
293 if (a == 0) return 0;
294 for (int i = 1; i < 256; ++i) {
295 if (gf_mul_byte(a, static_cast<uint8_t>(i)) == 1u) return static_cast<uint8_t>(i);
296 }
297 return 0;
298}
uint8_t gf_mul_byte(uint8_t a, uint8_t b)

References gf_inv_byte(), and gf_mul_byte().

Referenced by gf_inv_byte(), and BtrfsRecoveryImpl::reconstruct_raid56_read().

◆ gf_mul_byte()

uint8_t anonymous_namespace{btrfs_recovery.cpp}::gf_mul_byte ( uint8_t a,
uint8_t b )

Definition at line 274 of file btrfs_recovery.cpp.

274 {
275 uint8_t p = 0;
276 for (int i = 0; i < 8; ++i) {
277 if (b & 1u) p ^= a;
278 const bool hi = (a & 0x80u) != 0;
279 a = static_cast<uint8_t>(a << 1u);
280 if (hi) a ^= 0x1du;
281 b = static_cast<uint8_t>(b >> 1u);
282 }
283 return p;
284}

References gf_mul_byte().

Referenced by gf_inv_byte(), gf_mul_byte(), gf_pow2(), BtrfsRecoveryImpl::reconstruct_raid56_read(), and BtrfsRecoveryImpl::validate_raid6_candidate().

◆ gf_pow2()

uint8_t anonymous_namespace{btrfs_recovery.cpp}::gf_pow2 ( size_t exp)

Definition at line 286 of file btrfs_recovery.cpp.

286 {
287 uint8_t v = 1;
288 for (size_t i = 0; i < exp; ++i) v = gf_mul_byte(v, 2);
289 return v;
290}

References gf_mul_byte(), and gf_pow2().

Referenced by gf_pow2(), BtrfsRecoveryImpl::reconstruct_raid56_read(), and BtrfsRecoveryImpl::validate_raid6_candidate().

◆ le16()

uint16_t anonymous_namespace{btrfs_recovery.cpp}::le16 ( const unsigned char * p)

Definition at line 52 of file btrfs_recovery.cpp.

52 {
53 return static_cast<uint16_t>(p[0]) | (static_cast<uint16_t>(p[1]) << 8);
54}

References le16().

Referenced by le16(), BtrfsRecoveryImpl::load_chunk_tree(), BtrfsRecoveryImpl::load_root_tree(), and BtrfsRecoveryImpl::parse_system_chunk_array().

◆ le32()

uint32_t anonymous_namespace{btrfs_recovery.cpp}::le32 ( const unsigned char * p)

Definition at line 56 of file btrfs_recovery.cpp.

56 {
57 return static_cast<uint32_t>(p[0]) |
58 (static_cast<uint32_t>(p[1]) << 8) |
59 (static_cast<uint32_t>(p[2]) << 16) |
60 (static_cast<uint32_t>(p[3]) << 24);
61}

References le32().

Referenced by decompress_payload(), le32(), BtrfsRecoveryImpl::recover(), validate_tree_block_checksum(), validate_tree_block_header(), and BtrfsRecoveryImpl::walk_tree_internal().

◆ le64()

uint64_t anonymous_namespace{btrfs_recovery.cpp}::le64 ( const unsigned char * p)

Definition at line 63 of file btrfs_recovery.cpp.

63 {
64 return static_cast<uint64_t>(p[0]) |
65 (static_cast<uint64_t>(p[1]) << 8) |
66 (static_cast<uint64_t>(p[2]) << 16) |
67 (static_cast<uint64_t>(p[3]) << 24) |
68 (static_cast<uint64_t>(p[4]) << 32) |
69 (static_cast<uint64_t>(p[5]) << 40) |
70 (static_cast<uint64_t>(p[6]) << 48) |
71 (static_cast<uint64_t>(p[7]) << 56);
72}

References le64().

Referenced by le64(), BtrfsRecoveryImpl::load_chunk_tree(), BtrfsRecoveryImpl::load_root_tree(), parse_key(), BtrfsRecoveryImpl::parse_system_chunk_array(), BtrfsRecoveryImpl::recover(), validate_tree_block_header(), and BtrfsRecoveryImpl::walk_tree_internal().

◆ parse_key()

BtrfsKey anonymous_namespace{btrfs_recovery.cpp}::parse_key ( const unsigned char * p)

Definition at line 156 of file btrfs_recovery.cpp.

156 {
157 return {le64(p), p[8], le64(p + 9)};
158}
uint64_t le64(const unsigned char *p)

References le64(), and parse_key().

Referenced by parse_key(), BtrfsRecoveryImpl::parse_system_chunk_array(), and BtrfsRecoveryImpl::walk_tree_internal().

◆ sanitize()

std::string anonymous_namespace{btrfs_recovery.cpp}::sanitize ( const std::string & in)

Definition at line 74 of file btrfs_recovery.cpp.

74 {
75 // Bug #15 fix: btrfs filenames are stored as UTF-8 byte sequences. The
76 // previous ASCII-only sanitizer turned every accented character into '_'.
77 // We reuse the shared helper which preserves valid UTF-8 multibyte runs.
78 auto out = text_utils::sanitize_component(in);
79 if (out == "unnamed") out = "item";
80 return out;
81}
std::string sanitize_component(const std::string &in)

References sanitize(), and text_utils::sanitize_component().

Referenced by BtrfsRecoveryImpl::export_fs_root(), BtrfsRecoveryImpl::load_root_tree(), and sanitize().

◆ to_hex()

std::string anonymous_namespace{btrfs_recovery.cpp}::to_hex ( uint64_t v)

Definition at line 83 of file btrfs_recovery.cpp.

83 {
84 std::ostringstream oss;
85 oss << "0x" << std::hex << std::uppercase << v;
86 return oss.str();
87}

References to_hex().

Referenced by BtrfsRecoveryImpl::recover(), and to_hex().

◆ validate_tree_block_checksum()

bool anonymous_namespace{btrfs_recovery.cpp}::validate_tree_block_checksum ( const std::vector< unsigned char > & block)

Definition at line 317 of file btrfs_recovery.cpp.

317 {
318 if (block.size() < 0x100) return false;
319 const uint32_t stored = le32(block.data());
320 const uint32_t calc = crc32c_update(0, block.data() + 0x20, block.size() - 0x20);
321 return stored == calc;
322}
uint32_t crc32c_update(uint32_t crc, const unsigned char *data, size_t len)

References crc32c_update(), le32(), and validate_tree_block_checksum().

Referenced by validate_tree_block_checksum(), and validate_tree_block_header().

◆ validate_tree_block_header()

bool anonymous_namespace{btrfs_recovery.cpp}::validate_tree_block_header ( const std::vector< unsigned char > & block,
uint64_t logical_bytenr,
uint32_t nodesize,
const std::array< unsigned char, 16 > * fsid = nullptr,
uint64_t max_generation = 0 )

Definition at line 324 of file btrfs_recovery.cpp.

328 {
329 if (block.size() < 101) return false;
330 if (!validate_tree_block_checksum(block)) return false;
331 if (le64(block.data() + 48) != logical_bytenr) return false;
332 if (fsid != nullptr && !std::equal(fsid->begin(), fsid->end(), block.data() + 32)) return false;
333 const uint64_t generation = le64(block.data() + 80);
334 if (generation == 0) return false;
335 if (max_generation != 0 && generation > max_generation + 1024) return false;
336 const uint32_t nritems = le32(block.data() + 96);
337 const uint8_t level = block[100];
338 if (level > 8) return false;
339 const size_t header_size = 101;
340 const size_t item_size = (level == 0) ? 25 : 33;
341 const uint64_t need = static_cast<uint64_t>(header_size) + static_cast<uint64_t>(nritems) * item_size;
342 if (need > nodesize) return false;
343 return true;
344}
bool validate_tree_block_checksum(const std::vector< unsigned char > &block)

References le32(), le64(), validate_tree_block_checksum(), and validate_tree_block_header().

Referenced by BtrfsRecoveryImpl::read_tree_block(), and validate_tree_block_header().

Variable Documentation

◆ BTRFS_BLOCK_GROUP_DUP

uint64_t anonymous_namespace{btrfs_recovery.cpp}::BTRFS_BLOCK_GROUP_DUP = 1ull << 5
constexpr

Definition at line 47 of file btrfs_recovery.cpp.

Referenced by BtrfsRecoveryImpl::logical_to_physical().

◆ BTRFS_BLOCK_GROUP_RAID0

uint64_t anonymous_namespace{btrfs_recovery.cpp}::BTRFS_BLOCK_GROUP_RAID0 = 1ull << 3
constexpr

Definition at line 45 of file btrfs_recovery.cpp.

Referenced by BtrfsRecoveryImpl::logical_to_physical().

◆ BTRFS_BLOCK_GROUP_RAID1

uint64_t anonymous_namespace{btrfs_recovery.cpp}::BTRFS_BLOCK_GROUP_RAID1 = 1ull << 4
constexpr

Definition at line 46 of file btrfs_recovery.cpp.

Referenced by BtrfsRecoveryImpl::logical_to_physical().

◆ BTRFS_BLOCK_GROUP_RAID10

uint64_t anonymous_namespace{btrfs_recovery.cpp}::BTRFS_BLOCK_GROUP_RAID10 = 1ull << 6
constexpr

Definition at line 48 of file btrfs_recovery.cpp.

Referenced by BtrfsRecoveryImpl::logical_to_physical().

◆ BTRFS_BLOCK_GROUP_RAID5

uint64_t anonymous_namespace{btrfs_recovery.cpp}::BTRFS_BLOCK_GROUP_RAID5 = 1ull << 7
constexpr

◆ BTRFS_BLOCK_GROUP_RAID6

uint64_t anonymous_namespace{btrfs_recovery.cpp}::BTRFS_BLOCK_GROUP_RAID6 = 1ull << 8
constexpr

◆ BTRFS_CHUNK_ITEM_KEY

uint8_t anonymous_namespace{btrfs_recovery.cpp}::BTRFS_CHUNK_ITEM_KEY = 228
constexpr

◆ BTRFS_DIR_INDEX_KEY

uint8_t anonymous_namespace{btrfs_recovery.cpp}::BTRFS_DIR_INDEX_KEY = 96
constexpr

Definition at line 34 of file btrfs_recovery.cpp.

Referenced by BtrfsRecoveryImpl::collect_fs_root().

◆ BTRFS_DIR_ITEM_KEY

uint8_t anonymous_namespace{btrfs_recovery.cpp}::BTRFS_DIR_ITEM_KEY = 84
constexpr

Definition at line 33 of file btrfs_recovery.cpp.

Referenced by BtrfsRecoveryImpl::collect_fs_root().

◆ BTRFS_EXTENT_DATA_KEY

uint8_t anonymous_namespace{btrfs_recovery.cpp}::BTRFS_EXTENT_DATA_KEY = 108
constexpr

Definition at line 35 of file btrfs_recovery.cpp.

◆ BTRFS_FILE_EXTENT_INLINE

uint8_t anonymous_namespace{btrfs_recovery.cpp}::BTRFS_FILE_EXTENT_INLINE = 0
constexpr

Definition at line 41 of file btrfs_recovery.cpp.

Referenced by BtrfsRecoveryImpl::render_extent().

◆ BTRFS_FILE_EXTENT_PREALLOC

uint8_t anonymous_namespace{btrfs_recovery.cpp}::BTRFS_FILE_EXTENT_PREALLOC = 2
constexpr

Definition at line 43 of file btrfs_recovery.cpp.

Referenced by BtrfsRecoveryImpl::render_extent().

◆ BTRFS_FILE_EXTENT_REG

uint8_t anonymous_namespace{btrfs_recovery.cpp}::BTRFS_FILE_EXTENT_REG = 1
constexpr

Definition at line 42 of file btrfs_recovery.cpp.

Referenced by BtrfsRecoveryImpl::render_extent().

◆ BTRFS_INODE_ITEM_KEY

uint8_t anonymous_namespace{btrfs_recovery.cpp}::BTRFS_INODE_ITEM_KEY = 1
constexpr

Definition at line 31 of file btrfs_recovery.cpp.

◆ BTRFS_INODE_REF_KEY

uint8_t anonymous_namespace{btrfs_recovery.cpp}::BTRFS_INODE_REF_KEY = 12
constexpr

Definition at line 32 of file btrfs_recovery.cpp.

◆ BTRFS_ROOT_BACKREF_KEY

uint8_t anonymous_namespace{btrfs_recovery.cpp}::BTRFS_ROOT_BACKREF_KEY = 144
constexpr

Definition at line 37 of file btrfs_recovery.cpp.

Referenced by BtrfsRecoveryImpl::load_root_tree().

◆ BTRFS_ROOT_ITEM_KEY

uint8_t anonymous_namespace{btrfs_recovery.cpp}::BTRFS_ROOT_ITEM_KEY = 132
constexpr

Definition at line 36 of file btrfs_recovery.cpp.

Referenced by BtrfsRecoveryImpl::load_root_tree().

◆ BTRFS_ROOT_REF_KEY

uint8_t anonymous_namespace{btrfs_recovery.cpp}::BTRFS_ROOT_REF_KEY = 156
constexpr

Definition at line 38 of file btrfs_recovery.cpp.

Referenced by BtrfsRecoveryImpl::load_root_tree().