Skip to content
API Documentation
BastionGuard™
hfs_attributes.hpp
Go to the documentation of this file.
1// hfs_attributes.hpp -- HFS+ Attributes file walker (extended attributes
2// stored in the attributes B-tree, special file #6).
3//
4// The Attributes file is a B-tree using the standard HFS+ B-tree format
5// (same as Catalog and Extents Overflow). Each record has:
6//
7// KEY:
8// __be16 keyLength
9// __be16 pad
10// __be32 fileID
11// __be32 startBlock (= 0 for non-extent records)
12// __be16 attrNameLength (= number of UTF-16 code units, NOT bytes)
13// UTF-16BE attrName[attrNameLength]
14//
15// BODY (3 record types):
16// kHFSPlusAttrInlineData (0x10):
17// __be32 recordType (= 0x10)
18// __be32 reserved[2]
19// __be32 attrSize (in bytes)
20// attribute data[attrSize]
21//
22// kHFSPlusAttrForkData (0x20):
23// __be32 recordType (= 0x20)
24// __be32 reserved
25// HFSPlusForkData theFork (80 bytes)
26//
27// kHFSPlusAttrExtents (0x30):
28// __be32 recordType (= 0x30)
29// __be32 reserved
30// HFSPlusExtentRecord extents (8 ForkExtents, 64 bytes total)
31//
32// For decmpfs (type 3 = zlib in xattr) the data is ALMOST ALWAYS stored
33// inline (the inline limit on HFS+ is large -- thousands of bytes).
34// We support ONLY the Inline record type here. ForkData and Extents
35// variants are rare for decmpfs and out of scope.
36
37#pragma once
38
39#include "hfs_format.hpp"
40#include "hfs_btree.hpp"
41#include "disk_reader.hpp"
42
43#include <cstdint>
44#include <string>
45#include <vector>
46
47namespace hfs {
48
49constexpr uint32_t kHFSPlusAttrInlineData = 0x10;
50constexpr uint32_t kHFSPlusAttrForkData = 0x20;
51constexpr uint32_t kHFSPlusAttrExtents = 0x30;
52
53// Find the inline data of an attribute named `attr_name` for the file
54// with CNID `fileID`. The Attributes file content must be already
55// loaded in `attributes_btree_buffer` (loaded lazily via read_fork_full
56// like the Extents Overflow file).
57//
58// `attr_name` is the UTF-8 attribute name (e.g. "com.apple.decmpfs").
59// Internally we convert it to UTF-16BE for matching against the key.
60//
61// Returns true and fills `out` with the attribute's bytes if found.
62// Returns false if not found, if the record type is non-inline
63// (ForkData / Extents -- not supported), or if the B-tree is malformed.
64bool find_inline_attribute(const std::vector<unsigned char>& attributes_btree_buffer,
65 uint32_t fileID,
66 const std::string& attr_name,
67 std::vector<unsigned char>& out,
68 std::vector<std::string>& logs);
69
70} // namespace hfs
constexpr uint32_t kHFSPlusAttrInlineData
constexpr uint32_t kHFSPlusAttrExtents
constexpr uint32_t kHFSPlusAttrForkData
bool find_inline_attribute(const std::vector< unsigned char > &attributes_btree_buffer, uint32_t fileID, const std::string &attr_name, std::vector< unsigned char > &out, std::vector< std::string > &logs)