Skip to content
API Documentation
BastionGuard™
xfs Namespace Reference

Namespaces

namespace  anonymous_namespace{xfs_btree.cpp}
namespace  anonymous_namespace{xfs_dir.cpp}

Classes

struct  AGContext
struct  AGF
struct  AGI
struct  AllocatedInode
struct  BtreeLongHeader
struct  BtreeNodeHeader
struct  DinodeCore
struct  DirEntry
struct  Extent
struct  InobtRec
struct  InodeAddress
struct  ShortformDir
struct  Superblock
struct  VolumeContext

Typedefs

using InobtRecordCallback

Functions

bool parse_btree_header (const unsigned char *buf, uint32_t expected_magic_v4, uint32_t expected_magic_v5, BtreeNodeHeader &out)
void parse_inobt_record (const unsigned char *buf, bool is_v5_sparse, InobtRec &out)
bool walk_inode_btree (DiskReader &reader, const VolumeContext &vol, uint32_t agno, const InobtRecordCallback &on_record, std::vector< std::string > &logs, std::string &error)
bool walk_all_inode_records (DiskReader &reader, const VolumeContext &vol, const InobtRecordCallback &on_record, std::vector< std::string > &logs)
bool walk_free_inode_btree (DiskReader &reader, const VolumeContext &vol, uint32_t agno, const InobtRecordCallback &on_record, std::vector< std::string > &logs, std::string &error)
bool walk_all_free_inode_records (DiskReader &reader, const VolumeContext &vol, const InobtRecordCallback &on_record, std::vector< std::string > &logs)
void expand_chunk (const InobtRec &rec, uint32_t agno, const VolumeContext &vol, std::vector< AllocatedInode > &out)
void expand_chunk_free (const InobtRec &rec, uint32_t agno, const VolumeContext &vol, std::vector< AllocatedInode > &out)
bool parse_btree_long_header (const unsigned char *buf, uint32_t expected_magic_v4, uint32_t expected_magic_v5, BtreeLongHeader &out)
bool walk_extent_btree_root (DiskReader &reader, const VolumeContext &vol, const unsigned char *root_buf, uint32_t root_len, bool is_v5_volume, uint32_t max_extents, std::vector< Extent > &out, std::vector< std::string > &logs, std::string &error)
uint32_t btree_header_size (bool is_v5)
uint32_t btree_long_header_size (bool is_v5)
bool parse_shortform_dir (const unsigned char *data, uint32_t data_len, bool has_ftype, ShortformDir &out)
bool parse_dir_data_block (const unsigned char *block_buf, uint32_t block_size, bool is_v5, bool has_ftype, bool accept_block_magic, bool accept_data_magic, std::vector< DirEntry > &out)
bool parse_superblock (const unsigned char *buf, Superblock &out)
bool parse_agf (const unsigned char *buf, AGF &out)
bool parse_agi (const unsigned char *buf, AGI &out)
bool parse_agi (const unsigned char *buf, bool is_v5, AGI &out)
InodeAddress crack_inode (uint64_t ino, const Superblock &sb)
uint16_t be16 (const unsigned char *p)
uint32_t be32 (const unsigned char *p)
uint64_t be64 (const unsigned char *p)
bool parse_dinode_core (const unsigned char *buf, DinodeCore &out)
uint32_t dinode_data_fork_length (const DinodeCore &core, uint32_t inode_size)
void decode_extent_record (const unsigned char *buf16, Extent &out)
uint64_t fsb_to_disk_offset (uint64_t fsb, const VolumeContext &vol)
bool decode_extents_inline (const unsigned char *data_fork_buf, uint32_t nextents, uint32_t max_bytes, std::vector< Extent > &out)
uint32_t dinode_data_fork_offset (const DinodeCore &core)

Variables

constexpr uint32_t NULLAGBLOCK = 0xFFFFFFFFu
constexpr uint64_t NULLFSBLOCK = 0xFFFFFFFFFFFFFFFFull
constexpr uint32_t XFS_BMBT_MAGIC_V4 = 0x424D4150u
constexpr uint32_t XFS_BMBT_MAGIC_V5 = 0x424D4133u
constexpr uint32_t BMBT_KEY_SIZE_LONG = 8
constexpr uint32_t BMBT_PTR_SIZE_LONG = 8
constexpr uint32_t BMBT_REC_SIZE = 16
constexpr uint8_t XFS_DIR3_FT_UNKNOWN = 0
constexpr uint8_t XFS_DIR3_FT_REG_FILE = 1
constexpr uint8_t XFS_DIR3_FT_DIR = 2
constexpr uint8_t XFS_DIR3_FT_CHRDEV = 3
constexpr uint8_t XFS_DIR3_FT_BLKDEV = 4
constexpr uint8_t XFS_DIR3_FT_FIFO = 5
constexpr uint8_t XFS_DIR3_FT_SOCK = 6
constexpr uint8_t XFS_DIR3_FT_SYMLINK = 7
constexpr uint32_t XFS_DIR2_BLOCK_MAGIC = 0x58443242u
constexpr uint32_t XFS_DIR3_BLOCK_MAGIC = 0x58444233u
constexpr uint32_t XFS_DIR2_DATA_MAGIC = 0x58443244u
constexpr uint32_t XFS_DIR3_DATA_MAGIC = 0x58444433u
constexpr uint16_t XFS_DIR2_DATA_FREE_TAG = 0xFFFFu
constexpr uint32_t XFS_SB_MAGIC = 0x58465342u
constexpr uint32_t XFS_AGF_MAGIC_V4 = 0x58414746u
constexpr uint32_t XFS_AGF_MAGIC_V5 = 0x58414746u
constexpr uint32_t XFS_AGI_MAGIC_V4 = 0x58414749u
constexpr uint32_t XFS_AGI_MAGIC_V5 = 0x58414749u
constexpr uint32_t XFS_AGFL_MAGIC_V5 = 0x5841464Cu
constexpr uint32_t XFS_DINODE_MAGIC = 0x494Eu
constexpr uint32_t XFS_ABTB_MAGIC_V4 = 0x41425442u
constexpr uint32_t XFS_ABTB_MAGIC_V5 = 0x41423342u
constexpr uint32_t XFS_ABTC_MAGIC_V4 = 0x41425443u
constexpr uint32_t XFS_ABTC_MAGIC_V5 = 0x41423343u
constexpr uint32_t XFS_IBT_MAGIC_V4 = 0x49414254u
constexpr uint32_t XFS_IBT_MAGIC_V5 = 0x49414233u
constexpr uint32_t XFS_FIBT_MAGIC_V4 = 0x46494254u
constexpr uint32_t XFS_FIBT_MAGIC_V5 = 0x46494233u
constexpr uint32_t XFS_BMAP_MAGIC_V4 = 0x424D4150u
constexpr uint32_t XFS_BMAP_MAGIC_V5 = 0x424D4133u
constexpr uint16_t XFS_SB_VERSION_NUMBITS = 0x000F
constexpr uint16_t XFS_SB_VERSION_4 = 4
constexpr uint16_t XFS_SB_VERSION_5 = 5
constexpr uint16_t XFS_SB_VERSION_ATTRBIT = 0x0010
constexpr uint16_t XFS_SB_VERSION_NLINKBIT = 0x0020
constexpr uint16_t XFS_SB_VERSION_QUOTABIT = 0x0040
constexpr uint16_t XFS_SB_VERSION_ALIGNBIT = 0x0080
constexpr uint16_t XFS_SB_VERSION_DALIGNBIT = 0x0100
constexpr uint16_t XFS_SB_VERSION_SHAREDBIT = 0x0200
constexpr uint16_t XFS_SB_VERSION_LOGV2BIT = 0x0400
constexpr uint16_t XFS_SB_VERSION_SECTORBIT = 0x0800
constexpr uint16_t XFS_SB_VERSION_EXTFLGBIT = 0x1000
constexpr uint16_t XFS_SB_VERSION_DIRV2BIT = 0x2000
constexpr uint16_t XFS_SB_VERSION_BORGBIT = 0x4000
constexpr uint16_t XFS_SB_VERSION_MOREBITSBIT = 0x8000
constexpr uint32_t XFS_SB_FEAT_RO_COMPAT_FINOBT = 0x00000001
constexpr uint32_t XFS_SB_FEAT_RO_COMPAT_RMAPBT = 0x00000002
constexpr uint32_t XFS_SB_FEAT_RO_COMPAT_REFLINK = 0x00000004
constexpr uint32_t XFS_SB_FEAT_RO_COMPAT_INOBTCNT = 0x00000008
constexpr uint32_t XFS_SB_FEAT_INCOMPAT_FTYPE = 0x00000001
constexpr uint32_t XFS_SB_FEAT_INCOMPAT_SPINODES = 0x00000002
constexpr uint32_t XFS_SB_FEAT_INCOMPAT_META_UUID = 0x00000004
constexpr uint32_t XFS_SB_FEAT_INCOMPAT_BIGTIME = 0x00000008
constexpr uint32_t XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR = 0x00000010
constexpr uint32_t XFS_SB_FEAT_INCOMPAT_NREXT64 = 0x00000020
constexpr uint8_t XFS_DINODE_FMT_DEV = 0
constexpr uint8_t XFS_DINODE_FMT_LOCAL = 1
constexpr uint8_t XFS_DINODE_FMT_EXTENTS = 2
constexpr uint8_t XFS_DINODE_FMT_BTREE = 3
constexpr uint8_t XFS_DINODE_FMT_UUID = 4
constexpr uint16_t MODE_TYPE_MASK = 0xF000
constexpr uint16_t MODE_IFREG = 0x8000
constexpr uint16_t MODE_IFDIR = 0x4000
constexpr uint16_t MODE_IFLNK = 0xA000
constexpr uint16_t MODE_IFCHR = 0x2000
constexpr uint16_t MODE_IFBLK = 0x6000
constexpr uint16_t MODE_IFIFO = 0x1000
constexpr uint16_t MODE_IFSOCK = 0xC000
constexpr uint16_t XFS_DINODE_MAGIC_BE = 0x494E

Typedef Documentation

◆ InobtRecordCallback

Initial value:
std::function<bool(const InobtRec& rec, uint32_t agno)>

Definition at line 165 of file xfs_btree.hpp.

Function Documentation

◆ be16()

uint16_t xfs::be16 ( const unsigned char * p)
inline

Definition at line 38 of file xfs_format.hpp.

38 {
39 return static_cast<uint16_t>((p[0] << 8) | p[1]);
40}

References be16().

Referenced by be16(), parse_btree_header(), parse_btree_long_header(), parse_dinode_core(), parse_dir_data_block(), parse_inobt_record(), parse_superblock(), and walk_extent_btree_root().

◆ be32()

uint32_t xfs::be32 ( const unsigned char * p)
inline

Definition at line 41 of file xfs_format.hpp.

41 {
42 return (static_cast<uint32_t>(p[0]) << 24) |
43 (static_cast<uint32_t>(p[1]) << 16) |
44 (static_cast<uint32_t>(p[2]) << 8) |
45 static_cast<uint32_t>(p[3]);
46}

References be32().

Referenced by be32(), anonymous_namespace{xfs_recovery.cpp}::collect_dir_entries_block_or_leaf(), parse_agf(), parse_agi(), parse_btree_header(), parse_btree_long_header(), parse_dinode_core(), parse_dir_data_block(), parse_inobt_record(), parse_superblock(), xfs::anonymous_namespace{xfs_dir.cpp}::read_u32_be(), and xfs::anonymous_namespace{xfs_btree.cpp}::walk_ibt_block().

◆ be64()

uint64_t xfs::be64 ( const unsigned char * p)
inline

Definition at line 47 of file xfs_format.hpp.

47 {
48 return (static_cast<uint64_t>(p[0]) << 56) |
49 (static_cast<uint64_t>(p[1]) << 48) |
50 (static_cast<uint64_t>(p[2]) << 40) |
51 (static_cast<uint64_t>(p[3]) << 32) |
52 (static_cast<uint64_t>(p[4]) << 24) |
53 (static_cast<uint64_t>(p[5]) << 16) |
54 (static_cast<uint64_t>(p[6]) << 8) |
55 static_cast<uint64_t>(p[7]);
56}

References be64().

Referenced by be64(), xfs::anonymous_namespace{xfs_btree.cpp}::decode_bmbt_record_local(), decode_extent_record(), parse_btree_header(), parse_btree_long_header(), parse_dinode_core(), parse_dir_data_block(), parse_inobt_record(), parse_superblock(), xfs::anonymous_namespace{xfs_dir.cpp}::read_u64_be(), xfs::anonymous_namespace{xfs_btree.cpp}::walk_bmbt_block(), and walk_extent_btree_root().

◆ btree_header_size()

uint32_t xfs::btree_header_size ( bool is_v5)
inline

Definition at line 105 of file xfs_btree.hpp.

105 {
106 return is_v5 ? 56u : 16u;
107}

References btree_header_size().

Referenced by btree_header_size(), and xfs::anonymous_namespace{xfs_btree.cpp}::walk_ibt_block().

◆ btree_long_header_size()

uint32_t xfs::btree_long_header_size ( bool is_v5)
inline

Definition at line 333 of file xfs_btree.hpp.

333 {
334 return is_v5 ? 72u : 24u;
335}

References btree_long_header_size().

Referenced by btree_long_header_size(), and xfs::anonymous_namespace{xfs_btree.cpp}::walk_bmbt_block().

◆ crack_inode()

InodeAddress xfs::crack_inode ( uint64_t ino,
const Superblock & sb )

Definition at line 208 of file xfs_format.cpp.

208 {
209 InodeAddress a;
210 const unsigned agno_shift = sb.agblklog + sb.inopblog;
211 const unsigned agbno_shift = sb.inopblog;
212 const uint64_t inopblock_mask = static_cast<uint64_t>(sb.inopblock) - 1;
213
214 a.agno = static_cast<uint32_t>(ino >> agno_shift);
215 a.agbno = static_cast<uint32_t>((ino >> agbno_shift) & ((1u << sb.agblklog) - 1));
216 a.offset = static_cast<uint32_t>(ino & inopblock_mask);
217 return a;
218}

References xfs::Superblock::agblklog, xfs::InodeAddress::agbno, xfs::InodeAddress::agno, crack_inode(), xfs::Superblock::inopblock, xfs::Superblock::inopblog, and xfs::InodeAddress::offset.

Referenced by crack_inode(), and anonymous_namespace{xfs_recovery.cpp}::read_dinode().

◆ decode_extent_record()

void xfs::decode_extent_record ( const unsigned char * buf16,
Extent & out )

Definition at line 74 of file xfs_inode.cpp.

74 {
75 const uint64_t w0 = be64(buf16 + 0);
76 const uint64_t w1 = be64(buf16 + 8);
77
78 // Bit 63 of w0: flag (unwritten)
79 out.unwritten = ((w0 >> 63) & 1ull) != 0;
80
81 // Bits 62..9 of w0: logical offset (54 bits)
82 const uint64_t logical_mask = (1ull << 54) - 1ull;
83 out.logical_off_blocks = (w0 >> 9) & logical_mask;
84
85 // Bits 8..0 of w0: high 9 bits of physical block
86 const uint64_t phys_high9 = w0 & 0x1FFull;
87 // Bits 63..21 of w1: low 43 bits of physical block
88 const uint64_t phys_low43 = (w1 >> 21) & ((1ull << 43) - 1ull);
89 out.physical_block = (phys_high9 << 43) | phys_low43;
90
91 // Bits 20..0 of w1: length (21 bits)
92 out.length_blocks = static_cast<uint32_t>(w1 & ((1ull << 21) - 1ull));
93}
uint64_t be64(const unsigned char *p)
uint64_t physical_block
uint64_t logical_off_blocks
uint32_t length_blocks

References be64(), decode_extent_record(), xfs::Extent::length_blocks, xfs::Extent::logical_off_blocks, xfs::Extent::physical_block, and xfs::Extent::unwritten.

Referenced by decode_extent_record(), and decode_extents_inline().

◆ decode_extents_inline()

bool xfs::decode_extents_inline ( const unsigned char * data_fork_buf,
uint32_t nextents,
uint32_t max_bytes,
std::vector< Extent > & out )

Definition at line 105 of file xfs_inode.cpp.

108 {
109 if (data_fork_buf == nullptr) return false;
110 if (static_cast<uint64_t>(nextents) * 16ull > max_bytes) {
111 return false;
112 }
113 out.clear();
114 out.reserve(nextents);
115 for (uint32_t i = 0; i < nextents; ++i) {
116 Extent e;
117 decode_extent_record(data_fork_buf + i * 16, e);
118 // Sanity: a length of 0 is impossible
119 if (e.length_blocks == 0) {
120 // Be tolerant: skip and continue rather than abort.
121 continue;
122 }
123 out.push_back(e);
124 }
125 return true;
126}
void decode_extent_record(const unsigned char *buf16, Extent &out)
Definition xfs_inode.cpp:74

References decode_extent_record(), decode_extents_inline(), and xfs::Extent::length_blocks.

Referenced by anonymous_namespace{xfs_recovery.cpp}::collect_extents(), and decode_extents_inline().

◆ dinode_data_fork_length()

uint32_t xfs::dinode_data_fork_length ( const DinodeCore & core,
uint32_t inode_size )

Definition at line 58 of file xfs_inode.cpp.

58 {
59 const uint32_t fork_start = dinode_data_fork_offset(core);
60 if (fork_start >= inode_size) return 0;
61
62 // If forkoff != 0, the attribute fork begins at:
63 // fork_start + forkoff * 8 bytes
64 // ...so the data fork has that many bytes available.
65 if (core.forkoff != 0) {
66 const uint32_t data_len = static_cast<uint32_t>(core.forkoff) * 8u;
67 // Defensive cap: never exceed inode_size - fork_start
68 const uint32_t max_avail = inode_size - fork_start;
69 return std::min(data_len, max_avail);
70 }
71 return inode_size - fork_start;
72}
uint32_t dinode_data_fork_offset(const DinodeCore &core)

References dinode_data_fork_length(), dinode_data_fork_offset(), and xfs::DinodeCore::forkoff.

Referenced by dinode_data_fork_length(), and XfsRecovery::recover().

◆ dinode_data_fork_offset()

uint32_t xfs::dinode_data_fork_offset ( const DinodeCore & core)
inline

Definition at line 154 of file xfs_inode.hpp.

154 {
155 return core.is_v3() ? 176u : 100u;
156}
bool is_v3() const

References dinode_data_fork_offset(), and xfs::DinodeCore::is_v3().

Referenced by dinode_data_fork_length(), dinode_data_fork_offset(), and XfsRecovery::recover().

◆ expand_chunk()

void xfs::expand_chunk ( const InobtRec & rec,
uint32_t agno,
const VolumeContext & vol,
std::vector< AllocatedInode > & out )

Definition at line 391 of file xfs_btree.cpp.

393 {
394 // The chunk starts at AG-relative inode number `rec.startino`.
395 // Convert that to an AG-relative block number for the chunk start:
396 // chunk_agbno = rec.startino / inopblock
397 // in-block-offset of inode i = (rec.startino + i) % inopblock
398 const uint32_t inopblock = vol.sb.inopblock;
399 const uint32_t inode_size = vol.sb.inodesize;
400 if (inopblock == 0 || inode_size == 0) return;
401
402 const uint32_t chunk_count = std::min<uint32_t>(rec.count, 64);
403 for (uint32_t i = 0; i < chunk_count; ++i) {
404 // Sparse: skip holes (16-bit holemask in 4-inode granularity:
405 // each bit covers 4 consecutive inode positions)
406 if (rec.sparse) {
407 const uint32_t hole_bit = i / 4;
408 if (rec.holemask & (1u << hole_bit)) continue;
409 }
410 // Skip inodes marked free
411 if (rec.freemask & (1ull << i)) continue;
412
413 const uint32_t agino = rec.startino + i;
414 const uint32_t chunk_agbno = agino / inopblock;
415 const uint32_t in_block_off = agino % inopblock;
416
417 AllocatedInode ai;
418 ai.agno = agno;
419 ai.agbno = chunk_agbno;
420 ai.in_chunk_index = i;
421 // Reconstruct global 64-bit inode number
422 ai.ino = (static_cast<uint64_t>(agno) <<
423 (vol.sb.agblklog + vol.sb.inopblog))
424 | static_cast<uint64_t>(agino);
425 ai.disk_offset = ag_block_to_disk_offset(vol, agno, chunk_agbno)
426 + static_cast<uint64_t>(in_block_off) * inode_size;
427 out.push_back(ai);
428 }
429}
uint16_t holemask
uint32_t startino
uint64_t freemask

References xfs::Superblock::agblklog, xfs::AllocatedInode::agbno, xfs::AllocatedInode::agno, xfs::InobtRec::count, xfs::AllocatedInode::disk_offset, expand_chunk(), xfs::InobtRec::freemask, xfs::InobtRec::holemask, xfs::AllocatedInode::in_chunk_index, xfs::AllocatedInode::ino, xfs::Superblock::inodesize, xfs::Superblock::inopblock, xfs::Superblock::inopblog, xfs::VolumeContext::sb, xfs::InobtRec::sparse, and xfs::InobtRec::startino.

Referenced by expand_chunk().

◆ expand_chunk_free()

void xfs::expand_chunk_free ( const InobtRec & rec,
uint32_t agno,
const VolumeContext & vol,
std::vector< AllocatedInode > & out )

Definition at line 435 of file xfs_btree.cpp.

437 {
438 const uint32_t inopblock = vol.sb.inopblock;
439 const uint32_t inode_size = vol.sb.inodesize;
440 if (inopblock == 0 || inode_size == 0) return;
441
442 const uint32_t chunk_count = std::min<uint32_t>(rec.count, 64);
443 for (uint32_t i = 0; i < chunk_count; ++i) {
444 // Sparse: skip holes -- a hole means there's no real inode slot
445 // at this position, so there's nothing to recover.
446 if (rec.sparse) {
447 const uint32_t hole_bit = i / 4;
448 if (rec.holemask & (1u << hole_bit)) continue;
449 }
450 // Emit ONLY free slots (the opposite of expand_chunk).
451 if (!(rec.freemask & (1ull << i))) continue;
452
453 const uint32_t agino = rec.startino + i;
454 const uint32_t chunk_agbno = agino / inopblock;
455 const uint32_t in_block_off = agino % inopblock;
456
457 AllocatedInode ai; // re-using the type, but it's a "free" slot here
458 ai.agno = agno;
459 ai.agbno = chunk_agbno;
460 ai.in_chunk_index = i;
461 ai.ino = (static_cast<uint64_t>(agno) <<
462 (vol.sb.agblklog + vol.sb.inopblog))
463 | static_cast<uint64_t>(agino);
464 ai.disk_offset = ag_block_to_disk_offset(vol, agno, chunk_agbno)
465 + static_cast<uint64_t>(in_block_off) * inode_size;
466 out.push_back(ai);
467 }
468}

References xfs::Superblock::agblklog, xfs::AllocatedInode::agbno, xfs::AllocatedInode::agno, xfs::InobtRec::count, xfs::AllocatedInode::disk_offset, expand_chunk_free(), xfs::InobtRec::freemask, xfs::InobtRec::holemask, xfs::AllocatedInode::in_chunk_index, xfs::AllocatedInode::ino, xfs::Superblock::inodesize, xfs::Superblock::inopblock, xfs::Superblock::inopblog, xfs::VolumeContext::sb, xfs::InobtRec::sparse, and xfs::InobtRec::startino.

Referenced by expand_chunk_free(), and XfsRecovery::recover().

◆ fsb_to_disk_offset()

uint64_t xfs::fsb_to_disk_offset ( uint64_t fsb,
const VolumeContext & vol )

Definition at line 95 of file xfs_inode.cpp.

95 {
96 if (vol.sb.agblklog == 0) return vol.volume_offset + fsb * vol.sb.blocksize;
97 const uint64_t mask = (1ull << vol.sb.agblklog) - 1ull;
98 const uint32_t agno = static_cast<uint32_t>(fsb >> vol.sb.agblklog);
99 const uint32_t agbno = static_cast<uint32_t>(fsb & mask);
100 return vol.volume_offset
101 + static_cast<uint64_t>(agno) * vol.sb.agblocks * vol.sb.blocksize
102 + static_cast<uint64_t>(agbno) * vol.sb.blocksize;
103}

References xfs::Superblock::agblklog, xfs::Superblock::agblocks, xfs::Superblock::blocksize, fsb_to_disk_offset(), xfs::VolumeContext::sb, and xfs::VolumeContext::volume_offset.

Referenced by anonymous_namespace{xfs_recovery.cpp}::collect_dir_entries_block_or_leaf(), fsb_to_disk_offset(), anonymous_namespace{xfs_recovery.cpp}::read_extents_data(), and anonymous_namespace{xfs_recovery.cpp}::write_extents_to_path().

◆ parse_agf()

bool xfs::parse_agf ( const unsigned char * buf,
AGF & out )

Definition at line 130 of file xfs_format.cpp.

130 {
131 if (buf == nullptr) return false;
132
133 out.magicnum = be32(buf + 0x00);
134 if (out.magicnum != XFS_AGF_MAGIC_V4) { // V4/V5 share the same ASCII "XAGF"
135 return false;
136 }
137 out.versionnum = be32(buf + 0x04);
138 out.seqno = be32(buf + 0x08);
139 out.length = be32(buf + 0x0C);
140 out.roots[0] = be32(buf + 0x10);
141 out.roots[1] = be32(buf + 0x14);
142 out.roots[2] = be32(buf + 0x18); // V5 rmap root; on V4 this is reserved/zero
143 out.levels[0] = be32(buf + 0x1C);
144 out.levels[1] = be32(buf + 0x20);
145 out.levels[2] = be32(buf + 0x24);
146 out.flfirst = be32(buf + 0x28);
147 out.fllast = be32(buf + 0x2C);
148 out.flcount = be32(buf + 0x30);
149 out.freeblks = be32(buf + 0x34);
150 out.longest = be32(buf + 0x38);
151 out.btreeblks = be32(buf + 0x3C);
152
153 if (out.versionnum == 0 || out.length == 0) return false;
154 if (out.levels[0] > 16 || out.levels[1] > 16) return false; // sanity
155 return true;
156}
uint32_t be32(const unsigned char *p)
constexpr uint32_t XFS_AGF_MAGIC_V4
uint32_t magicnum
uint32_t freeblks
uint32_t flcount
uint32_t roots[3]
uint32_t longest
uint32_t flfirst
uint32_t length
uint32_t btreeblks
uint32_t seqno
uint32_t fllast
uint32_t versionnum
uint32_t levels[3]

References be32(), xfs::AGF::btreeblks, xfs::AGF::flcount, xfs::AGF::flfirst, xfs::AGF::fllast, xfs::AGF::freeblks, xfs::AGF::length, xfs::AGF::levels, xfs::AGF::longest, xfs::AGF::magicnum, parse_agf(), xfs::AGF::roots, xfs::AGF::seqno, xfs::AGF::versionnum, and XFS_AGF_MAGIC_V4.

Referenced by anonymous_namespace{xfs_recovery.cpp}::load_ag_headers(), and parse_agf().

◆ parse_agi() [1/2]

bool xfs::parse_agi ( const unsigned char * buf,
AGI & out )

Definition at line 158 of file xfs_format.cpp.

158 {
159 return parse_agi(buf, /*is_v5=*/false, out);
160}
bool parse_agi(const unsigned char *buf, AGI &out)

References parse_agi().

Referenced by anonymous_namespace{xfs_recovery.cpp}::load_ag_headers(), parse_agi(), and parse_agi().

◆ parse_agi() [2/2]

bool xfs::parse_agi ( const unsigned char * buf,
bool is_v5,
AGI & out )

Definition at line 162 of file xfs_format.cpp.

162 {
163 if (buf == nullptr) return false;
164
165 out.magicnum = be32(buf + 0x00);
166 if (out.magicnum != XFS_AGI_MAGIC_V4) { // same magic on V4/V5
167 return false;
168 }
169 out.versionnum = be32(buf + 0x04);
170 out.seqno = be32(buf + 0x08);
171 out.length = be32(buf + 0x0C);
172 out.count = be32(buf + 0x10);
173 out.root = be32(buf + 0x14);
174 out.level = be32(buf + 0x18);
175 out.freecount = be32(buf + 0x1C);
176 out.newino = be32(buf + 0x20);
177 out.dirino = be32(buf + 0x24);
178 for (int i = 0; i < 64; ++i) {
179 out.unlinked[i] = be32(buf + 0x28 + i * 4);
180 }
181
182 // V5-only fields: agi_free_root / agi_free_level (FINOBT roots).
183 //
184 // V5 AGI layout after unlinked[64] (offset 0x128):
185 // 0x128 uuid_t agi_uuid (16 bytes)
186 // 0x138 __be32 agi_crc
187 // 0x13C __be32 agi_pad32
188 // 0x140 __be64 agi_lsn
189 // 0x148 __be32 agi_free_root
190 // 0x14C __be32 agi_free_level
191 //
192 // On V4 these bytes are not present (AGI is 296 bytes), so we leave
193 // free_root/free_level at zero unless is_v5 is true.
194 if (is_v5) {
195 out.free_root = be32(buf + 0x148);
196 out.free_level = be32(buf + 0x14C);
197 } else {
198 out.free_root = 0;
199 out.free_level = 0;
200 }
201
202 if (out.versionnum == 0 || out.length == 0) return false;
203 if (out.level > 16) return false;
204 if (out.free_level > 16) return false;
205 return true;
206}
constexpr uint32_t XFS_AGI_MAGIC_V4
uint32_t free_root
uint32_t level
uint32_t length
uint32_t magicnum
uint32_t freecount
uint32_t seqno
uint32_t root
uint32_t unlinked[64]
uint32_t count
uint32_t versionnum
uint32_t newino
uint32_t free_level
uint32_t dirino

References be32(), xfs::AGI::count, xfs::AGI::dirino, xfs::AGI::free_level, xfs::AGI::free_root, xfs::AGI::freecount, xfs::AGI::length, xfs::AGI::level, xfs::AGI::magicnum, xfs::AGI::newino, parse_agi(), xfs::AGI::root, xfs::AGI::seqno, xfs::AGI::unlinked, xfs::AGI::versionnum, and XFS_AGI_MAGIC_V4.

◆ parse_btree_header()

bool xfs::parse_btree_header ( const unsigned char * buf,
uint32_t expected_magic_v4,
uint32_t expected_magic_v5,
BtreeNodeHeader & out )

Definition at line 72 of file xfs_btree.cpp.

75 {
76 if (buf == nullptr) return false;
77 out = {};
78
79 out.magic = be32(buf + 0x00);
80
81 if (out.magic == expected_magic_v5) {
82 out.is_v5_header = true;
83 } else if (out.magic == expected_magic_v4) {
84 out.is_v5_header = false;
85 } else {
86 return false;
87 }
88
89 out.level = be16(buf + 0x04);
90 out.numrecs = be16(buf + 0x06);
91 out.leftsib = be32(buf + 0x08);
92 out.rightsib = be32(buf + 0x0C);
93
94 if (out.is_v5_header) {
95 out.blkno = be64(buf + 0x10);
96 out.lsn = be64(buf + 0x18);
97 // uuid at +0x20..+0x30 ignored
98 out.owner = be32(buf + 0x30);
99 out.crc = be32(buf + 0x34);
100 }
101
102 // Sanity: level must be plausible (XFS B+trees never go beyond ~16)
103 if (out.level > 16) return false;
104 return true;
105}
uint16_t be16(const unsigned char *p)

References be16(), be32(), be64(), xfs::BtreeNodeHeader::blkno, xfs::BtreeNodeHeader::crc, xfs::BtreeNodeHeader::is_v5_header, xfs::BtreeNodeHeader::leftsib, xfs::BtreeNodeHeader::level, xfs::BtreeNodeHeader::lsn, xfs::BtreeNodeHeader::magic, xfs::BtreeNodeHeader::numrecs, xfs::BtreeNodeHeader::owner, parse_btree_header(), and xfs::BtreeNodeHeader::rightsib.

Referenced by parse_btree_header(), and xfs::anonymous_namespace{xfs_btree.cpp}::walk_ibt_block().

◆ parse_btree_long_header()

bool xfs::parse_btree_long_header ( const unsigned char * buf,
uint32_t expected_magic_v4,
uint32_t expected_magic_v5,
BtreeLongHeader & out )

Definition at line 474 of file xfs_btree.cpp.

477 {
478 if (buf == nullptr) return false;
479 out = {};
480 out.magic = be32(buf + 0x00);
481 if (out.magic == expected_magic_v5) out.is_v5_header = true;
482 else if (out.magic == expected_magic_v4) out.is_v5_header = false;
483 else return false;
484
485 out.level = be16(buf + 0x04);
486 out.numrecs = be16(buf + 0x06);
487 out.leftsib = be64(buf + 0x08);
488 out.rightsib = be64(buf + 0x10);
489
490 if (out.is_v5_header) {
491 out.blkno = be64(buf + 0x18);
492 out.lsn = be64(buf + 0x20);
493 // uuid at +0x28..+0x38 ignored
494 out.owner = be64(buf + 0x38);
495 out.crc = be32(buf + 0x40);
496 // pad at +0x44 ignored
497 }
498 if (out.level > 32) return false; // nonsense depth
499 return true;
500}

References be16(), be32(), be64(), xfs::BtreeLongHeader::blkno, xfs::BtreeLongHeader::crc, xfs::BtreeLongHeader::is_v5_header, xfs::BtreeLongHeader::leftsib, xfs::BtreeLongHeader::level, xfs::BtreeLongHeader::lsn, xfs::BtreeLongHeader::magic, xfs::BtreeLongHeader::numrecs, xfs::BtreeLongHeader::owner, parse_btree_long_header(), and xfs::BtreeLongHeader::rightsib.

Referenced by parse_btree_long_header(), and xfs::anonymous_namespace{xfs_btree.cpp}::walk_bmbt_block().

◆ parse_dinode_core()

bool xfs::parse_dinode_core ( const unsigned char * buf,
DinodeCore & out )

Definition at line 15 of file xfs_inode.cpp.

15 {
16 if (buf == nullptr) return false;
17 out = {};
18
19 out.magic = be16(buf + 0x00);
20 if (out.magic != XFS_DINODE_MAGIC_BE) return false;
21
22 out.mode = be16(buf + 0x02);
23 out.version = buf[0x04];
24 out.format = buf[0x05];
25
26 // Sanity: version must be 1, 2, or 3
27 if (out.version < 1 || out.version > 3) return false;
28 // Sanity: format must be 0..4 (we only USE 1,2,3 but accept the others)
29 if (out.format > 4) return false;
30
31 out.uid = be32(buf + 0x08);
32 out.gid = be32(buf + 0x0C);
33 out.nlink = be32(buf + 0x10);
34
35 out.size = static_cast<int64_t>(be64(buf + 0x3C));
36 out.nblocks = be64(buf + 0x44);
37
38 out.nextents = be32(buf + 0x50);
39 out.anextents = be16(buf + 0x54);
40 out.forkoff = buf[0x56];
41 out.aformat = buf[0x57];
42 out.flags = be16(buf + 0x5E);
43 out.gen = be32(buf + 0x60);
44
45 if (out.is_v3()) {
46 // V3 extension fields
47 out.flags2 = be64(buf + 0x7C);
48 out.ino = be64(buf + 0x9C);
49 }
50
51 // Sanity: refuse impossibly-large extent counts (corrupt inode).
52 // 1 million extents in a single fork is already absurd.
53 if (out.nextents > 1'000'000) return false;
54
55 return true;
56}
constexpr uint16_t XFS_DINODE_MAGIC_BE
uint32_t nextents
uint16_t anextents

References xfs::DinodeCore::aformat, xfs::DinodeCore::anextents, be16(), be32(), be64(), xfs::DinodeCore::flags, xfs::DinodeCore::flags2, xfs::DinodeCore::forkoff, xfs::DinodeCore::format, xfs::DinodeCore::gen, xfs::DinodeCore::gid, xfs::DinodeCore::ino, xfs::DinodeCore::is_v3(), xfs::DinodeCore::magic, xfs::DinodeCore::mode, xfs::DinodeCore::nblocks, xfs::DinodeCore::nextents, xfs::DinodeCore::nlink, parse_dinode_core(), xfs::DinodeCore::size, xfs::DinodeCore::uid, xfs::DinodeCore::version, and XFS_DINODE_MAGIC_BE.

Referenced by parse_dinode_core(), and XfsRecovery::recover().

◆ parse_dir_data_block()

bool xfs::parse_dir_data_block ( const unsigned char * block_buf,
uint32_t block_size,
bool is_v5,
bool has_ftype,
bool accept_block_magic,
bool accept_data_magic,
std::vector< DirEntry > & out )

Definition at line 122 of file xfs_dir.cpp.

128 {
129 if (block_buf == nullptr || block_size < 64) return false;
130
131 const uint32_t magic = be32(block_buf + 0x00);
132 bool magic_ok = false;
133 if (is_v5) {
134 if (accept_block_magic && magic == XFS_DIR3_BLOCK_MAGIC) magic_ok = true;
135 if (accept_data_magic && magic == XFS_DIR3_DATA_MAGIC) magic_ok = true;
136 } else {
137 if (accept_block_magic && magic == XFS_DIR2_BLOCK_MAGIC) magic_ok = true;
138 if (accept_data_magic && magic == XFS_DIR2_DATA_MAGIC) magic_ok = true;
139 }
140 if (!magic_ok) return false;
141
142 const uint32_t header_size = is_v5 ? DATA_HDR_SIZE_V5 : DATA_HDR_SIZE_V4;
143 if (block_size <= header_size) return false;
144
145 // Compute the "stop" offset. For BLOCK-format dirs there is a
146 // trailing leaf table whose start we should not enter. The leaf
147 // tail offset lives in the LAST 8 bytes of the block (v4 dir2_block_tail
148 // = u32 count + u32 stale; the leaf table itself is at end - count*8).
149 //
150 // For DATA-format blocks (in leaf-format dirs) there is no tail, so
151 // we iterate to the end of the block.
152 //
153 // Heuristic: for block-format, we trust the block_tail at the end;
154 // when corrupted we still bound by block_size - 8 to be safe.
155 uint32_t stop_offset = block_size;
156 if ((is_v5 && magic == XFS_DIR3_BLOCK_MAGIC) ||
157 (!is_v5 && magic == XFS_DIR2_BLOCK_MAGIC)) {
158 // Block tail at end: u32 count + u32 stale. Leaf table size =
159 // count * 8. Leaf table starts at block_size - 8 - count*8.
160 if (block_size >= 8) {
161 const uint32_t bt_count = be32(block_buf + block_size - 8);
162 const uint32_t leaf_table_bytes = bt_count * 8u;
163 if (8u + leaf_table_bytes <= block_size) {
164 stop_offset = block_size - 8u - leaf_table_bytes;
165 } else {
166 stop_offset = block_size > 8u ? block_size - 8u : 0u;
167 }
168 }
169 }
170 if (stop_offset <= header_size) return false;
171
172 uint32_t pos = header_size;
173 while (pos + 4 <= stop_offset) {
174 // Peek at the first 2 bytes -- a valid entry's first 2 bytes are
175 // the high two bytes of the 64-bit inumber, which CANNOT both be
176 // 0xFF (no inode is 0xFFFF...). The free-record sentinel is
177 // 0xFFFF in those exact 2 bytes.
178 const uint16_t first_word = be16(block_buf + pos);
179 if (first_word == XFS_DIR2_DATA_FREE_TAG) {
180 // Unused record: skip. Length is at +2.
181 if (pos + 6 > stop_offset) break;
182 const uint16_t freelen = be16(block_buf + pos + 2);
183 if (freelen < 16 || pos + freelen > stop_offset) {
184 // Corrupted free-record header -- bail out instead of
185 // looping forever.
186 return !out.empty();
187 }
188 pos += freelen;
189 continue;
190 }
191
192 // It's a data entry: __be64 inumber, __u8 namelen, name[], (ftype),
193 // __be16 tag, then alignment to 8.
194 if (pos + 8 + 1 > stop_offset) break; // need inumber + namelen
195 const uint64_t inumber = be64(block_buf + pos);
196 const uint8_t namelen = block_buf[pos + 8];
197 if (namelen == 0) {
198 return !out.empty(); // malformed -- stop, keep what we got
199 }
200 // entry length: 8 (inumber) + 1 (namelen) + namelen + (has_ftype ? 1 : 0)
201 // + 2 (tag), padded to 8-byte boundary.
202 const uint32_t raw_entry_len = 8u + 1u + namelen +
203 (has_ftype ? 1u : 0u) + 2u;
204 const uint32_t entry_len = align8(raw_entry_len);
205 if (pos + entry_len > stop_offset) {
206 // Truncated trailing entry; keep what we already read.
207 break;
208 }
209
210 DirEntry e;
211 e.name.assign(reinterpret_cast<const char*>(block_buf + pos + 9), namelen);
212 // Reject embedded slashes (corrupt or malicious).
213 if (e.name.find('/') != std::string::npos) {
214 std::replace(e.name.begin(), e.name.end(), '/', '_');
215 }
216
217 if (has_ftype) {
218 e.ftype = block_buf[pos + 9 + namelen];
219 e.ftype_valid = true;
220 }
221 e.ino = inumber;
222
223 // Skip "." and ".." (recovery does not export them; the parent
224 // is exported separately, and "." is the directory itself).
225 if (e.name != "." && e.name != "..") {
226 out.push_back(std::move(e));
227 }
228
229 pos += entry_len;
230 }
231
232 return true;
233}
constexpr uint32_t align8(uint32_t v)
Definition xfs_dir.cpp:118
constexpr uint16_t XFS_DIR2_DATA_FREE_TAG
Definition xfs_dir.hpp:60
constexpr uint32_t XFS_DIR2_BLOCK_MAGIC
Definition xfs_dir.hpp:51
constexpr uint32_t XFS_DIR3_BLOCK_MAGIC
Definition xfs_dir.hpp:52
constexpr uint32_t XFS_DIR3_DATA_MAGIC
Definition xfs_dir.hpp:57
constexpr uint32_t XFS_DIR2_DATA_MAGIC
Definition xfs_dir.hpp:56
std::string name
Definition xfs_dir.hpp:63

References be16(), be32(), be64(), xfs::DirEntry::ftype, xfs::DirEntry::ftype_valid, xfs::DirEntry::ino, xfs::DirEntry::name, parse_dir_data_block(), XFS_DIR2_BLOCK_MAGIC, XFS_DIR2_DATA_FREE_TAG, XFS_DIR2_DATA_MAGIC, XFS_DIR3_BLOCK_MAGIC, and XFS_DIR3_DATA_MAGIC.

Referenced by anonymous_namespace{xfs_recovery.cpp}::collect_dir_entries_block_or_leaf(), and parse_dir_data_block().

◆ parse_inobt_record()

void xfs::parse_inobt_record ( const unsigned char * buf,
bool is_v5_sparse,
InobtRec & out )

Definition at line 107 of file xfs_btree.cpp.

108 {
109 out = {};
110 out.startino = be32(buf + 0x00);
111 if (is_v5_sparse) {
112 // V5 sparse layout: 16-bit holemask, 8-bit count, 8-bit freecount
113 out.holemask = be16(buf + 0x04);
114 out.count = buf[0x06];
115 out.freecount = buf[0x07];
116 if (out.count == 0) out.count = 64; // some early kernels left 0; default
117 out.sparse = true;
118 } else {
119 // Classic layout: 32-bit freecount at offset 4
120 const uint32_t freec32 = be32(buf + 0x04);
121 out.freecount = static_cast<uint8_t>(std::min<uint32_t>(freec32, 64));
122 out.holemask = 0;
123 out.count = 64;
124 out.sparse = false;
125 }
126 out.freemask = be64(buf + 0x08);
127}
uint8_t freecount

References be16(), be32(), be64(), xfs::InobtRec::count, xfs::InobtRec::freecount, xfs::InobtRec::freemask, xfs::InobtRec::holemask, parse_inobt_record(), xfs::InobtRec::sparse, and xfs::InobtRec::startino.

Referenced by parse_inobt_record(), and xfs::anonymous_namespace{xfs_btree.cpp}::walk_ibt_block().

◆ parse_shortform_dir()

bool xfs::parse_shortform_dir ( const unsigned char * data,
uint32_t data_len,
bool has_ftype,
ShortformDir & out )

Definition at line 30 of file xfs_dir.cpp.

33 {
34 if (data == nullptr || data_len < 4) return false;
35 out = {};
36
37 const uint8_t count = data[0];
38 const uint8_t i8count = data[1];
39 const bool use_8byte = (i8count != 0);
40 const uint32_t inumber_size = use_8byte ? 8u : 4u;
41
42 // Parent comes right after the 2-byte header.
43 uint32_t pos = 2;
44 if (pos + inumber_size > data_len) return false;
45 out.parent_ino = use_8byte ? read_u64_be(data + pos)
46 : read_u32_be(data + pos);
47 pos += inumber_size;
48
49 out.entries.reserve(count);
50
51 for (uint8_t i = 0; i < count; ++i) {
52 if (pos + 1 > data_len) return false;
53 const uint8_t namelen = data[pos];
54 ++pos;
55
56 // 2 bytes of "offset" we skip
57 if (pos + 2 > data_len) return false;
58 pos += 2;
59
60 // name
61 if (pos + namelen > data_len) return false;
62 DirEntry e;
63 e.name.assign(reinterpret_cast<const char*>(data + pos), namelen);
64 pos += namelen;
65
66 // Sanity: refuse zero-length names and refuse '/' inside names
67 // (they can never be legal on XFS but corrupted dirs sometimes
68 // contain them).
69 if (namelen == 0) return false;
70 if (e.name.find('/') != std::string::npos) {
71 // Replace any embedded '/' with underscore so the name
72 // doesn't accidentally escape the export directory.
73 std::replace(e.name.begin(), e.name.end(), '/', '_');
74 }
75
76 // V5 + FTYPE: 1-byte ftype before inumber
77 if (has_ftype) {
78 if (pos + 1 > data_len) return false;
79 e.ftype = data[pos];
80 e.ftype_valid = true;
81 ++pos;
82 }
83
84 // inumber
85 if (pos + inumber_size > data_len) return false;
86 e.ino = use_8byte ? read_u64_be(data + pos)
87 : static_cast<uint64_t>(read_u32_be(data + pos));
88 pos += inumber_size;
89
90 // Skip "." and ".." which shouldn't appear in shortform but be
91 // defensive against odd metadata.
92 if (e.name == "." || e.name == "..") continue;
93
94 out.entries.push_back(std::move(e));
95 }
96
97 return true;
98}
uint32_t read_u32_be(const unsigned char *p)
Definition xfs_dir.cpp:20
uint64_t read_u64_be(const unsigned char *p)
Definition xfs_dir.cpp:24
uint64_t parent_ino
Definition xfs_dir.hpp:70
std::vector< DirEntry > entries
Definition xfs_dir.hpp:71

References xfs::ShortformDir::entries, xfs::DirEntry::ftype, xfs::DirEntry::ftype_valid, xfs::DirEntry::ino, xfs::DirEntry::name, xfs::ShortformDir::parent_ino, and parse_shortform_dir().

Referenced by parse_shortform_dir(), and XfsRecovery::recover().

◆ parse_superblock()

bool xfs::parse_superblock ( const unsigned char * buf,
Superblock & out )

Definition at line 19 of file xfs_format.cpp.

19 {
20 if (buf == nullptr) return false;
21
22 out.magicnum = be32(buf + 0x00);
23 if (out.magicnum != XFS_SB_MAGIC) {
24 return false;
25 }
26
27 out.blocksize = be32(buf + 0x04);
28 out.dblocks = be64(buf + 0x08);
29 out.rblocks = be64(buf + 0x10);
30 out.rextents = be64(buf + 0x18);
31 std::copy(buf + 0x20, buf + 0x30, out.uuid.begin());
32 out.logstart = be64(buf + 0x30);
33 out.rootino = be64(buf + 0x38);
34 out.rbmino = be64(buf + 0x40);
35 out.rsumino = be64(buf + 0x48);
36 out.rextsize = be32(buf + 0x50);
37 out.agblocks = be32(buf + 0x54);
38 out.agcount = be32(buf + 0x58);
39 out.rbmblocks = be32(buf + 0x5C);
40 out.logblocks = be32(buf + 0x60);
41 out.versionnum = be16(buf + 0x64);
42 out.sectsize = be16(buf + 0x66);
43 out.inodesize = be16(buf + 0x68);
44 out.inopblock = be16(buf + 0x6A);
45 std::copy(buf + 0x6C, buf + 0x78, out.fname.begin());
46 out.blocklog = buf[0x78];
47 out.sectlog = buf[0x79];
48 out.inodelog = buf[0x7A];
49 out.inopblog = buf[0x7B];
50 out.agblklog = buf[0x7C];
51 out.rextslog = buf[0x7D];
52 out.inprogress = buf[0x7E];
53 out.imax_pct = buf[0x7F];
54 out.icount = be64(buf + 0x80);
55 out.ifree = be64(buf + 0x88);
56 out.fdblocks = be64(buf + 0x90);
57 out.frextents = be64(buf + 0x98);
58 out.uquotino = be64(buf + 0xA0);
59 out.gquotino = be64(buf + 0xA8);
60 out.qflags = be16(buf + 0xB0);
61 out.flags = buf[0xB2];
62 out.shared_vn = buf[0xB3];
63 out.inoalignmt = be32(buf + 0xB4);
64 out.unit = be32(buf + 0xB8);
65 out.width = be32(buf + 0xBC);
66 out.dirblklog = buf[0xC0];
67 out.logsectlog = buf[0xC1];
68 out.logsectsize= be16(buf + 0xC2);
69 out.logsunit = be32(buf + 0xC4);
70 out.features2 = be32(buf + 0xC8);
71
72 // V5-only fields. Read them anyway (cheap), but they're only meaningful
73 // if format_version()==5. The V4 superblock zeroes these bytes (mkfs
74 // wipes the whole sector before writing).
75 out.bad_features2 = be32(buf + 0xCC);
76 out.features_compat = be32(buf + 0xD0);
77 out.features_ro_compat = be32(buf + 0xD4);
78 out.features_incompat = be32(buf + 0xD8);
79 out.features_log_incompat = be32(buf + 0xDC);
80 out.crc = be32(buf + 0xE0);
81 out.spino_align = be32(buf + 0xE4);
82 out.pquotino = be64(buf + 0xE8);
83 out.lsn = be64(buf + 0xF0);
84 std::copy(buf + 0xF8, buf + 0x108, out.meta_uuid.begin());
85
86 // ---- Sanity checks ----
87
88 // blocksize must be a power of 2 in [512, 65536]
89 if (out.blocksize < 512 || out.blocksize > 65536 ||
90 (out.blocksize & (out.blocksize - 1)) != 0) {
91 return false;
92 }
93 // sectsize must be a power of 2 in [256, 32768] and <= blocksize
94 if (out.sectsize < 256 || out.sectsize > 32768 ||
95 (out.sectsize & (out.sectsize - 1)) != 0 ||
96 out.sectsize > out.blocksize) {
97 return false;
98 }
99 // inodesize must be a power of 2 in [256, 2048] and <= blocksize
100 if (out.inodesize < 256 || out.inodesize > 2048 ||
101 (out.inodesize & (out.inodesize - 1)) != 0 ||
102 out.inodesize > out.blocksize) {
103 return false;
104 }
105 // log2 fields must agree with the explicit values
106 if ((1u << out.blocklog) != out.blocksize ||
107 (1u << out.sectlog) != out.sectsize ||
108 (1u << out.inodelog) != out.inodesize) {
109 return false;
110 }
111 if (out.inopblock == 0 || (1u << out.inopblog) != out.inopblock) {
112 return false;
113 }
114 // agblocks/agcount must be plausible
115 if (out.agblocks == 0 || out.agcount == 0) {
116 return false;
117 }
118 // dblocks must be at least one AG worth
119 if (out.dblocks < out.agblocks) {
120 return false;
121 }
122 // version must be 4 or 5
123 const unsigned ver = out.format_version();
124 if (ver != XFS_SB_VERSION_4 && ver != XFS_SB_VERSION_5) {
125 return false;
126 }
127 return true;
128}
constexpr uint16_t XFS_SB_VERSION_5
constexpr uint32_t XFS_SB_MAGIC
constexpr uint16_t XFS_SB_VERSION_4
uint32_t bad_features2
uint32_t features_incompat
unsigned format_version() const
std::array< uint8_t, 16 > meta_uuid
uint32_t features_log_incompat
std::array< char, 12 > fname
uint32_t inoalignmt
std::array< uint8_t, 16 > uuid
uint32_t features_ro_compat
uint16_t logsectsize
uint16_t versionnum
uint32_t spino_align
uint32_t features_compat

References xfs::Superblock::agblklog, xfs::Superblock::agblocks, xfs::Superblock::agcount, xfs::Superblock::bad_features2, be16(), be32(), be64(), xfs::Superblock::blocklog, xfs::Superblock::blocksize, xfs::Superblock::crc, xfs::Superblock::dblocks, xfs::Superblock::dirblklog, xfs::Superblock::fdblocks, xfs::Superblock::features2, xfs::Superblock::features_compat, xfs::Superblock::features_incompat, xfs::Superblock::features_log_incompat, xfs::Superblock::features_ro_compat, xfs::Superblock::flags, xfs::Superblock::fname, xfs::Superblock::format_version(), xfs::Superblock::frextents, xfs::Superblock::gquotino, xfs::Superblock::icount, xfs::Superblock::ifree, xfs::Superblock::imax_pct, xfs::Superblock::inoalignmt, xfs::Superblock::inodelog, xfs::Superblock::inodesize, xfs::Superblock::inopblock, xfs::Superblock::inopblog, xfs::Superblock::inprogress, xfs::Superblock::logblocks, xfs::Superblock::logsectlog, xfs::Superblock::logsectsize, xfs::Superblock::logstart, xfs::Superblock::logsunit, xfs::Superblock::lsn, xfs::Superblock::magicnum, xfs::Superblock::meta_uuid, parse_superblock(), xfs::Superblock::pquotino, xfs::Superblock::qflags, xfs::Superblock::rblocks, xfs::Superblock::rbmblocks, xfs::Superblock::rbmino, xfs::Superblock::rextents, xfs::Superblock::rextsize, xfs::Superblock::rextslog, xfs::Superblock::rootino, xfs::Superblock::rsumino, xfs::Superblock::sectlog, xfs::Superblock::sectsize, xfs::Superblock::shared_vn, xfs::Superblock::spino_align, xfs::Superblock::unit, xfs::Superblock::uquotino, xfs::Superblock::uuid, xfs::Superblock::versionnum, xfs::Superblock::width, XFS_SB_MAGIC, XFS_SB_VERSION_4, and XFS_SB_VERSION_5.

Referenced by parse_superblock(), XfsRecovery::recover(), anonymous_namespace{filesystem_probes.cpp}::xfs_probe(), and anonymous_namespace{lost_partition_finder.cpp}::xfs_size_bytes().

◆ walk_all_free_inode_records()

bool xfs::walk_all_free_inode_records ( DiskReader & reader,
const VolumeContext & vol,
const InobtRecordCallback & on_record,
std::vector< std::string > & logs )

Definition at line 371 of file xfs_btree.cpp.

374 {
375 if (!vol.sb.is_v5() ||
377 // V4 or feature missing -- nothing to do.
378 return true;
379 }
380 bool any_error = false;
381 for (uint32_t agno = 0; agno < vol.sb.agcount && agno < vol.ag.size(); ++agno) {
382 std::string err;
383 if (!walk_free_inode_btree(reader, vol, agno, on_record, logs, err)) {
384 any_error = true;
385 logs.push_back("XFS FINOBT (AG " + std::to_string(agno) + "): " + err);
386 }
387 }
388 return !any_error;
389}
bool walk_free_inode_btree(DiskReader &reader, const VolumeContext &vol, uint32_t agno, const InobtRecordCallback &on_record, std::vector< std::string > &logs, std::string &error)
constexpr uint32_t XFS_SB_FEAT_RO_COMPAT_FINOBT
bool is_v5() const
std::vector< AGContext > ag

References xfs::VolumeContext::ag, xfs::Superblock::agcount, xfs::Superblock::features_ro_compat, xfs::Superblock::is_v5(), xfs::VolumeContext::sb, walk_all_free_inode_records(), walk_free_inode_btree(), and XFS_SB_FEAT_RO_COMPAT_FINOBT.

Referenced by XfsRecovery::recover(), and walk_all_free_inode_records().

◆ walk_all_inode_records()

bool xfs::walk_all_inode_records ( DiskReader & reader,
const VolumeContext & vol,
const InobtRecordCallback & on_record,
std::vector< std::string > & logs )

Definition at line 303 of file xfs_btree.cpp.

306 {
307 bool any_error = false;
308 for (uint32_t agno = 0; agno < vol.sb.agcount && agno < vol.ag.size(); ++agno) {
309 std::string err;
310 if (!walk_inode_btree(reader, vol, agno, on_record, logs, err)) {
311 any_error = true;
312 logs.push_back("XFS IBT (AG " + std::to_string(agno) + "): "
313 + err);
314 }
315 }
316 return !any_error;
317}
bool walk_inode_btree(DiskReader &reader, const VolumeContext &vol, uint32_t agno, const InobtRecordCallback &on_record, std::vector< std::string > &logs, std::string &error)

References xfs::VolumeContext::ag, xfs::Superblock::agcount, xfs::VolumeContext::sb, walk_all_inode_records(), and walk_inode_btree().

Referenced by walk_all_inode_records().

◆ walk_extent_btree_root()

bool xfs::walk_extent_btree_root ( DiskReader & reader,
const VolumeContext & vol,
const unsigned char * root_buf,
uint32_t root_len,
bool is_v5_volume,
uint32_t max_extents,
std::vector< Extent > & out,
std::vector< std::string > & logs,
std::string & error )

Definition at line 663 of file xfs_btree.cpp.

671 {
672 // bmdr "root" header in the data fork: 2 bytes level + 2 bytes numrecs
673 // followed by numrecs keys (8 each) and numrecs pointers (8 each).
674 // No magic, no CRC. The compact root is what fits inside the dinode
675 // and points to the first level of REAL on-disk BMBT blocks.
676 if (root_buf == nullptr || root_len < 4) {
677 error = "BMBT: data fork too small for bmdr root";
678 return false;
679 }
680 const uint16_t level = be16(root_buf + 0);
681 const uint16_t numrecs = be16(root_buf + 2);
682 if (level == 0) {
683 // No internal levels -- the "root" is itself a leaf. In bmdr, leaf
684 // records are 16-byte BMBT records.
685 if (4u + static_cast<uint32_t>(numrecs) * 16u > root_len) {
686 error = "BMBT: bmdr leaf records overflow data fork";
687 return false;
688 }
689 for (uint16_t i = 0; i < numrecs; ++i) {
690 LocalBmbtRec r;
691 decode_bmbt_record_local(root_buf + 4 + i * 16, r);
692 if (r.length_blocks == 0) continue;
693 push_extent(out, r);
694 if (out.size() >= max_extents) return true;
695 }
696 return true;
697 }
698
699 // Internal root: layout is keys[numrecs] then ptrs[numrecs] (in
700 // bmdr, no maxrecs reservation -- it's compact).
701 if (4u + static_cast<uint32_t>(numrecs) * 16u > root_len) {
702 error = "BMBT: bmdr root records overflow data fork";
703 return false;
704 }
705 std::set<uint64_t> visited;
706 size_t nodes_visited = 0;
707 const uint32_t ptrs_off = 4u + numrecs * 8u; // keys are 8 each
708 for (uint16_t i = 0; i < numrecs; ++i) {
709 const uint64_t child_fsb = be64(root_buf + ptrs_off + i * 8u);
710 if (!walk_bmbt_block(reader, vol, child_fsb, level - 1,
711 is_v5_volume, out, logs, max_extents,
712 visited, nodes_visited)) {
713 return false;
714 }
715 if (out.size() >= max_extents) {
716 logs.push_back("XFS BMBT: extent cap reached ("
717 + std::to_string(max_extents) + ")");
718 break;
719 }
720 }
721 return true;
722}
void push_extent(std::vector< Extent > &out, const LocalBmbtRec &r)
void decode_bmbt_record_local(const unsigned char *buf16, LocalBmbtRec &r)
bool walk_bmbt_block(DiskReader &reader, const VolumeContext &vol, uint64_t child_fsb, uint32_t expected_level, bool is_v5, std::vector< Extent > &out, std::vector< std::string > &logs, uint32_t max_extents, std::set< uint64_t > &visited, size_t &nodes_visited)

References be16(), be64(), and walk_extent_btree_root().

Referenced by anonymous_namespace{xfs_recovery.cpp}::collect_extents(), and walk_extent_btree_root().

◆ walk_free_inode_btree()

bool xfs::walk_free_inode_btree ( DiskReader & reader,
const VolumeContext & vol,
uint32_t agno,
const InobtRecordCallback & on_record,
std::vector< std::string > & logs,
std::string & error )

Definition at line 323 of file xfs_btree.cpp.

328 {
329 if (agno >= vol.ag.size()) {
330 error = "walk_free_inode_btree: agno out of range";
331 return false;
332 }
333 const auto& agctx = vol.ag[agno];
334 if (!agctx.agi_loaded) {
335 std::ostringstream m;
336 m << "XFS FINOBT (AG " << agno << "): AGI not loaded, skipping";
337 logs.push_back(m.str());
338 return true;
339 }
340 if (!vol.sb.is_v5() ||
342 // No FINOBT on this volume.
343 return true;
344 }
345
346 const uint32_t root = agctx.agi.free_root;
347 const uint32_t depth = agctx.agi.free_level;
348
349 if (root == 0 || root == NULLAGBLOCK) {
350 std::ostringstream m;
351 m << "XFS FINOBT (AG " << agno << "): empty (root=" << root << ")";
352 logs.push_back(m.str());
353 return true;
354 }
355 if (depth > 16) {
356 std::ostringstream m;
357 m << "XFS FINOBT (AG " << agno << "): implausible depth " << depth;
358 logs.push_back(m.str());
359 return true;
360 }
361
362 std::set<uint32_t> visited;
363 size_t nodes_visited = 0;
364 bool callback_stopped = false;
365 return walk_ibt_block(reader, vol, agno, root, depth,
367 on_record, visited, nodes_visited,
368 logs, error, callback_stopped);
369}
bool walk_ibt_block(DiskReader &reader, const VolumeContext &vol, uint32_t agno, uint32_t agbno, uint32_t expected_level, uint32_t magic_v4, uint32_t magic_v5, const char *tree_label, const InobtRecordCallback &on_record, std::set< uint32_t > &visited, size_t &nodes_visited, std::vector< std::string > &logs, std::string &error, bool &callback_stopped)
constexpr uint32_t NULLAGBLOCK
Definition xfs_btree.hpp:85
constexpr uint32_t XFS_FIBT_MAGIC_V5
constexpr uint32_t XFS_FIBT_MAGIC_V4

References xfs::VolumeContext::ag, xfs::Superblock::features_ro_compat, xfs::Superblock::is_v5(), NULLAGBLOCK, xfs::VolumeContext::sb, walk_free_inode_btree(), XFS_FIBT_MAGIC_V4, XFS_FIBT_MAGIC_V5, and XFS_SB_FEAT_RO_COMPAT_FINOBT.

Referenced by walk_all_free_inode_records(), and walk_free_inode_btree().

◆ walk_inode_btree()

bool xfs::walk_inode_btree ( DiskReader & reader,
const VolumeContext & vol,
uint32_t agno,
const InobtRecordCallback & on_record,
std::vector< std::string > & logs,
std::string & error )

Definition at line 261 of file xfs_btree.cpp.

266 {
267 if (agno >= vol.ag.size()) {
268 error = "walk_inode_btree: agno out of range";
269 return false;
270 }
271 const auto& agctx = vol.ag[agno];
272 if (!agctx.agi_loaded) {
273 std::ostringstream m;
274 m << "XFS IBT (AG " << agno << "): AGI not loaded, skipping";
275 logs.push_back(m.str());
276 return true;
277 }
278 const uint32_t root = agctx.agi.root;
279 const uint32_t depth = agctx.agi.level;
280
281 if (root == 0 || root == NULLAGBLOCK) {
282 std::ostringstream m;
283 m << "XFS IBT (AG " << agno << "): empty (root=" << root << ")";
284 logs.push_back(m.str());
285 return true;
286 }
287 if (depth > 16) {
288 std::ostringstream m;
289 m << "XFS IBT (AG " << agno << "): implausible depth " << depth;
290 logs.push_back(m.str());
291 return true;
292 }
293
294 std::set<uint32_t> visited;
295 size_t nodes_visited = 0;
296 bool callback_stopped = false;
297 return walk_ibt_block(reader, vol, agno, root, depth,
299 on_record, visited, nodes_visited,
300 logs, error, callback_stopped);
301}
constexpr uint32_t XFS_IBT_MAGIC_V5
constexpr uint32_t XFS_IBT_MAGIC_V4

References xfs::VolumeContext::ag, NULLAGBLOCK, walk_inode_btree(), XFS_IBT_MAGIC_V4, and XFS_IBT_MAGIC_V5.

Referenced by walk_all_inode_records(), and walk_inode_btree().

Variable Documentation

◆ BMBT_KEY_SIZE_LONG

uint32_t xfs::BMBT_KEY_SIZE_LONG = 8
constexpr

◆ BMBT_PTR_SIZE_LONG

uint32_t xfs::BMBT_PTR_SIZE_LONG = 8
constexpr

◆ BMBT_REC_SIZE

uint32_t xfs::BMBT_REC_SIZE = 16
constexpr

◆ MODE_IFBLK

uint16_t xfs::MODE_IFBLK = 0x6000
constexpr

Definition at line 109 of file xfs_inode.hpp.

Referenced by xfs::DinodeCore::is_special().

◆ MODE_IFCHR

uint16_t xfs::MODE_IFCHR = 0x2000
constexpr

Definition at line 108 of file xfs_inode.hpp.

Referenced by xfs::DinodeCore::is_special().

◆ MODE_IFDIR

uint16_t xfs::MODE_IFDIR = 0x4000
constexpr

Definition at line 106 of file xfs_inode.hpp.

Referenced by xfs::DinodeCore::is_dir().

◆ MODE_IFIFO

uint16_t xfs::MODE_IFIFO = 0x1000
constexpr

Definition at line 110 of file xfs_inode.hpp.

Referenced by xfs::DinodeCore::is_special().

◆ MODE_IFLNK

uint16_t xfs::MODE_IFLNK = 0xA000
constexpr

Definition at line 107 of file xfs_inode.hpp.

Referenced by xfs::DinodeCore::is_symlink().

◆ MODE_IFREG

uint16_t xfs::MODE_IFREG = 0x8000
constexpr

Definition at line 105 of file xfs_inode.hpp.

Referenced by xfs::DinodeCore::is_reg().

◆ MODE_IFSOCK

uint16_t xfs::MODE_IFSOCK = 0xC000
constexpr

Definition at line 111 of file xfs_inode.hpp.

Referenced by xfs::DinodeCore::is_special().

◆ MODE_TYPE_MASK

uint16_t xfs::MODE_TYPE_MASK = 0xF000
constexpr

◆ NULLAGBLOCK

uint32_t xfs::NULLAGBLOCK = 0xFFFFFFFFu
constexpr

◆ NULLFSBLOCK

uint64_t xfs::NULLFSBLOCK = 0xFFFFFFFFFFFFFFFFull
constexpr

◆ XFS_ABTB_MAGIC_V4

uint32_t xfs::XFS_ABTB_MAGIC_V4 = 0x41425442u
constexpr

Definition at line 71 of file xfs_format.hpp.

◆ XFS_ABTB_MAGIC_V5

uint32_t xfs::XFS_ABTB_MAGIC_V5 = 0x41423342u
constexpr

Definition at line 72 of file xfs_format.hpp.

◆ XFS_ABTC_MAGIC_V4

uint32_t xfs::XFS_ABTC_MAGIC_V4 = 0x41425443u
constexpr

Definition at line 73 of file xfs_format.hpp.

◆ XFS_ABTC_MAGIC_V5

uint32_t xfs::XFS_ABTC_MAGIC_V5 = 0x41423343u
constexpr

Definition at line 74 of file xfs_format.hpp.

◆ XFS_AGF_MAGIC_V4

uint32_t xfs::XFS_AGF_MAGIC_V4 = 0x58414746u
constexpr

Definition at line 63 of file xfs_format.hpp.

Referenced by parse_agf().

◆ XFS_AGF_MAGIC_V5

uint32_t xfs::XFS_AGF_MAGIC_V5 = 0x58414746u
constexpr

Definition at line 64 of file xfs_format.hpp.

◆ XFS_AGFL_MAGIC_V5

uint32_t xfs::XFS_AGFL_MAGIC_V5 = 0x5841464Cu
constexpr

Definition at line 67 of file xfs_format.hpp.

◆ XFS_AGI_MAGIC_V4

uint32_t xfs::XFS_AGI_MAGIC_V4 = 0x58414749u
constexpr

Definition at line 65 of file xfs_format.hpp.

Referenced by parse_agi().

◆ XFS_AGI_MAGIC_V5

uint32_t xfs::XFS_AGI_MAGIC_V5 = 0x58414749u
constexpr

Definition at line 66 of file xfs_format.hpp.

◆ XFS_BMAP_MAGIC_V4

uint32_t xfs::XFS_BMAP_MAGIC_V4 = 0x424D4150u
constexpr

Definition at line 79 of file xfs_format.hpp.

◆ XFS_BMAP_MAGIC_V5

uint32_t xfs::XFS_BMAP_MAGIC_V5 = 0x424D4133u
constexpr

Definition at line 80 of file xfs_format.hpp.

◆ XFS_BMBT_MAGIC_V4

uint32_t xfs::XFS_BMBT_MAGIC_V4 = 0x424D4150u
constexpr

◆ XFS_BMBT_MAGIC_V5

uint32_t xfs::XFS_BMBT_MAGIC_V5 = 0x424D4133u
constexpr

◆ XFS_DINODE_FMT_BTREE

uint8_t xfs::XFS_DINODE_FMT_BTREE = 3
constexpr

◆ XFS_DINODE_FMT_DEV

uint8_t xfs::XFS_DINODE_FMT_DEV = 0
constexpr

Definition at line 97 of file xfs_inode.hpp.

◆ XFS_DINODE_FMT_EXTENTS

uint8_t xfs::XFS_DINODE_FMT_EXTENTS = 2
constexpr

◆ XFS_DINODE_FMT_LOCAL

uint8_t xfs::XFS_DINODE_FMT_LOCAL = 1
constexpr

Definition at line 98 of file xfs_inode.hpp.

Referenced by XfsRecovery::recover().

◆ XFS_DINODE_FMT_UUID

uint8_t xfs::XFS_DINODE_FMT_UUID = 4
constexpr

Definition at line 101 of file xfs_inode.hpp.

◆ XFS_DINODE_MAGIC

uint32_t xfs::XFS_DINODE_MAGIC = 0x494Eu
constexpr

Definition at line 68 of file xfs_format.hpp.

◆ XFS_DINODE_MAGIC_BE

uint16_t xfs::XFS_DINODE_MAGIC_BE = 0x494E
constexpr

Definition at line 113 of file xfs_inode.hpp.

Referenced by parse_dinode_core().

◆ XFS_DIR2_BLOCK_MAGIC

uint32_t xfs::XFS_DIR2_BLOCK_MAGIC = 0x58443242u
constexpr

◆ XFS_DIR2_DATA_FREE_TAG

uint16_t xfs::XFS_DIR2_DATA_FREE_TAG = 0xFFFFu
constexpr

Definition at line 60 of file xfs_dir.hpp.

Referenced by parse_dir_data_block().

◆ XFS_DIR2_DATA_MAGIC

uint32_t xfs::XFS_DIR2_DATA_MAGIC = 0x58443244u
constexpr

◆ XFS_DIR3_BLOCK_MAGIC

uint32_t xfs::XFS_DIR3_BLOCK_MAGIC = 0x58444233u
constexpr

◆ XFS_DIR3_DATA_MAGIC

uint32_t xfs::XFS_DIR3_DATA_MAGIC = 0x58444433u
constexpr

◆ XFS_DIR3_FT_BLKDEV

uint8_t xfs::XFS_DIR3_FT_BLKDEV = 4
constexpr

Definition at line 44 of file xfs_dir.hpp.

◆ XFS_DIR3_FT_CHRDEV

uint8_t xfs::XFS_DIR3_FT_CHRDEV = 3
constexpr

Definition at line 43 of file xfs_dir.hpp.

◆ XFS_DIR3_FT_DIR

uint8_t xfs::XFS_DIR3_FT_DIR = 2
constexpr

Definition at line 42 of file xfs_dir.hpp.

◆ XFS_DIR3_FT_FIFO

uint8_t xfs::XFS_DIR3_FT_FIFO = 5
constexpr

Definition at line 45 of file xfs_dir.hpp.

◆ XFS_DIR3_FT_REG_FILE

uint8_t xfs::XFS_DIR3_FT_REG_FILE = 1
constexpr

Definition at line 41 of file xfs_dir.hpp.

◆ XFS_DIR3_FT_SOCK

uint8_t xfs::XFS_DIR3_FT_SOCK = 6
constexpr

Definition at line 46 of file xfs_dir.hpp.

◆ XFS_DIR3_FT_SYMLINK

uint8_t xfs::XFS_DIR3_FT_SYMLINK = 7
constexpr

Definition at line 47 of file xfs_dir.hpp.

◆ XFS_DIR3_FT_UNKNOWN

uint8_t xfs::XFS_DIR3_FT_UNKNOWN = 0
constexpr

Definition at line 40 of file xfs_dir.hpp.

◆ XFS_FIBT_MAGIC_V4

uint32_t xfs::XFS_FIBT_MAGIC_V4 = 0x46494254u
constexpr

Definition at line 77 of file xfs_format.hpp.

Referenced by walk_free_inode_btree().

◆ XFS_FIBT_MAGIC_V5

uint32_t xfs::XFS_FIBT_MAGIC_V5 = 0x46494233u
constexpr

Definition at line 78 of file xfs_format.hpp.

Referenced by walk_free_inode_btree().

◆ XFS_IBT_MAGIC_V4

uint32_t xfs::XFS_IBT_MAGIC_V4 = 0x49414254u
constexpr

Definition at line 75 of file xfs_format.hpp.

Referenced by walk_inode_btree().

◆ XFS_IBT_MAGIC_V5

uint32_t xfs::XFS_IBT_MAGIC_V5 = 0x49414233u
constexpr

Definition at line 76 of file xfs_format.hpp.

Referenced by walk_inode_btree().

◆ XFS_SB_FEAT_INCOMPAT_BIGTIME

uint32_t xfs::XFS_SB_FEAT_INCOMPAT_BIGTIME = 0x00000008
constexpr

Definition at line 113 of file xfs_format.hpp.

Referenced by XfsRecovery::recover().

◆ XFS_SB_FEAT_INCOMPAT_FTYPE

uint32_t xfs::XFS_SB_FEAT_INCOMPAT_FTYPE = 0x00000001
constexpr

Definition at line 110 of file xfs_format.hpp.

Referenced by xfs::Superblock::has_ftype(), and XfsRecovery::recover().

◆ XFS_SB_FEAT_INCOMPAT_META_UUID

uint32_t xfs::XFS_SB_FEAT_INCOMPAT_META_UUID = 0x00000004
constexpr

Definition at line 112 of file xfs_format.hpp.

◆ XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR

uint32_t xfs::XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR = 0x00000010
constexpr

Definition at line 114 of file xfs_format.hpp.

◆ XFS_SB_FEAT_INCOMPAT_NREXT64

uint32_t xfs::XFS_SB_FEAT_INCOMPAT_NREXT64 = 0x00000020
constexpr

Definition at line 115 of file xfs_format.hpp.

Referenced by XfsRecovery::recover().

◆ XFS_SB_FEAT_INCOMPAT_SPINODES

uint32_t xfs::XFS_SB_FEAT_INCOMPAT_SPINODES = 0x00000002
constexpr

◆ XFS_SB_FEAT_RO_COMPAT_FINOBT

uint32_t xfs::XFS_SB_FEAT_RO_COMPAT_FINOBT = 0x00000001
constexpr

◆ XFS_SB_FEAT_RO_COMPAT_INOBTCNT

uint32_t xfs::XFS_SB_FEAT_RO_COMPAT_INOBTCNT = 0x00000008
constexpr

Definition at line 108 of file xfs_format.hpp.

◆ XFS_SB_FEAT_RO_COMPAT_REFLINK

uint32_t xfs::XFS_SB_FEAT_RO_COMPAT_REFLINK = 0x00000004
constexpr

◆ XFS_SB_FEAT_RO_COMPAT_RMAPBT

uint32_t xfs::XFS_SB_FEAT_RO_COMPAT_RMAPBT = 0x00000002
constexpr

Definition at line 106 of file xfs_format.hpp.

◆ XFS_SB_MAGIC

uint32_t xfs::XFS_SB_MAGIC = 0x58465342u
constexpr

Definition at line 62 of file xfs_format.hpp.

Referenced by parse_superblock().

◆ XFS_SB_VERSION_4

uint16_t xfs::XFS_SB_VERSION_4 = 4
constexpr

Definition at line 87 of file xfs_format.hpp.

Referenced by xfs::Superblock::is_v4(), and parse_superblock().

◆ XFS_SB_VERSION_5

uint16_t xfs::XFS_SB_VERSION_5 = 5
constexpr

Definition at line 88 of file xfs_format.hpp.

Referenced by xfs::Superblock::is_v5(), and parse_superblock().

◆ XFS_SB_VERSION_ALIGNBIT

uint16_t xfs::XFS_SB_VERSION_ALIGNBIT = 0x0080
constexpr

Definition at line 94 of file xfs_format.hpp.

◆ XFS_SB_VERSION_ATTRBIT

uint16_t xfs::XFS_SB_VERSION_ATTRBIT = 0x0010
constexpr

Definition at line 91 of file xfs_format.hpp.

◆ XFS_SB_VERSION_BORGBIT

uint16_t xfs::XFS_SB_VERSION_BORGBIT = 0x4000
constexpr

Definition at line 101 of file xfs_format.hpp.

◆ XFS_SB_VERSION_DALIGNBIT

uint16_t xfs::XFS_SB_VERSION_DALIGNBIT = 0x0100
constexpr

Definition at line 95 of file xfs_format.hpp.

◆ XFS_SB_VERSION_DIRV2BIT

uint16_t xfs::XFS_SB_VERSION_DIRV2BIT = 0x2000
constexpr

Definition at line 100 of file xfs_format.hpp.

◆ XFS_SB_VERSION_EXTFLGBIT

uint16_t xfs::XFS_SB_VERSION_EXTFLGBIT = 0x1000
constexpr

Definition at line 99 of file xfs_format.hpp.

◆ XFS_SB_VERSION_LOGV2BIT

uint16_t xfs::XFS_SB_VERSION_LOGV2BIT = 0x0400
constexpr

Definition at line 97 of file xfs_format.hpp.

◆ XFS_SB_VERSION_MOREBITSBIT

uint16_t xfs::XFS_SB_VERSION_MOREBITSBIT = 0x8000
constexpr

Definition at line 102 of file xfs_format.hpp.

◆ XFS_SB_VERSION_NLINKBIT

uint16_t xfs::XFS_SB_VERSION_NLINKBIT = 0x0020
constexpr

Definition at line 92 of file xfs_format.hpp.

◆ XFS_SB_VERSION_NUMBITS

uint16_t xfs::XFS_SB_VERSION_NUMBITS = 0x000F
constexpr

Definition at line 86 of file xfs_format.hpp.

Referenced by xfs::Superblock::format_version().

◆ XFS_SB_VERSION_QUOTABIT

uint16_t xfs::XFS_SB_VERSION_QUOTABIT = 0x0040
constexpr

Definition at line 93 of file xfs_format.hpp.

◆ XFS_SB_VERSION_SECTORBIT

uint16_t xfs::XFS_SB_VERSION_SECTORBIT = 0x0800
constexpr

Definition at line 98 of file xfs_format.hpp.

◆ XFS_SB_VERSION_SHAREDBIT

uint16_t xfs::XFS_SB_VERSION_SHAREDBIT = 0x0200
constexpr

Definition at line 96 of file xfs_format.hpp.