1 #pragma once
2 
3 #include "../base/tsk_base.h"
4 #include "../img/tsk_img.h"
5 #include "../pool/tsk_apfs.hpp"
6 #include "../util/lw_shared_ptr.hpp"
7 #include "../util/span.hpp"
8 
9 #include "tsk_apfs.h"
10 
11 #include <algorithm>
12 #include <array>
13 #include <memory>
14 #include <mutex>
15 #include <new>
16 #include <stack>
17 #include <stdexcept>
18 #include <type_traits>
19 #include <vector>
20 
21 #include "../auto/guid.h"
22 
23 // Helper function to see if a bitfield flag is set
24 template <typename T, typename U,
25           typename = std::enable_if_t<std::numeric_limits<T>::is_integer &&
26                                       std::numeric_limits<U>::is_integer>>
27 constexpr bool bit_is_set(T bitfield, U bitmask) noexcept {
28   return ((bitfield & static_cast<T>(bitmask)) != 0);
29 }
30 
31 // Helper function to extract bitfield value
32 template <typename T,
33           typename = std::enable_if_t<std::numeric_limits<T>::is_integer>>
34 constexpr T bitfield_value(T bitfield, int bits, int shift) noexcept {
35   return (bitfield >> shift) & ((T{1} << bits) - 1);
36 }
37 
38 class APFSPool;
39 
40 class APFSObject : public APFSBlock {
41  protected:
42   inline const apfs_obj_header *obj() const noexcept {
43     return reinterpret_cast<const apfs_obj_header *>(_storage.data());
44   }
45 
46  public:
47   // Use the constructors from APFSBlock
48   using APFSBlock::APFSBlock;
49 
50   bool validate_checksum() const noexcept;
51 
52   inline APFS_OBJ_TYPE_ENUM obj_type() const noexcept {
53     return APFS_OBJ_TYPE_ENUM(obj()->type);
54   }
55 
56   inline uint32_t obj_type_and_flags() const noexcept {
57     return obj()->type_and_flags;
58   }
59 
60   inline uint64_t oid() const noexcept { return obj()->oid; }
61 
62   inline uint64_t xid() const noexcept { return obj()->xid; }
63 
64   inline uint32_t subtype() const noexcept { return obj()->subtype; }
65 };
66 
67 class APFSOmap : public APFSObject {
68  protected:
69   inline const apfs_omap *omap() const noexcept {
70     return reinterpret_cast<const apfs_omap *>(_storage.data());
71   }
72 
73  public:
74   // Use constructors from APFSObject
75   using APFSObject::APFSObject;
76 
77   APFSOmap(const APFSPool &pool, const apfs_block_num block_num);
78 
79   inline uint32_t snapshot_count() const noexcept {
80     return omap()->snapshot_count;
81   }
82 
83   inline APFS_OMAP_TREE_TYPE_ENUM tree_type() const noexcept {
84     return APFS_OMAP_TREE_TYPE_ENUM(omap()->tree_type);
85   }
86 
87   inline apfs_block_num root_block() const noexcept { return omap()->tree_oid; }
88 
89   struct node_tag {};  ///< Tag used to identify OMAP nodes
90 
91   template <typename T,
92             typename = std::enable_if_t<std::is_base_of<node_tag, T>::value>>
93   T root() const {
94     return {_pool, root_block()};
95   }
96 };
97 
98 class APFSJObjBtreeNode;
99 
100 template <typename Node>
101 class APFSBtreeNodeIterator {
102  public:
103   using iterator_category = std::forward_iterator_tag;
104   using difference_type = uint32_t;
105   using value_type = struct {
106     typename Node::key_type key;
107     typename Node::value_type value;
108   };
109   using reference = const value_type &;
110   using pointer = const value_type *;
111 
112  protected:
113   lw_shared_ptr<Node> _node{};
114   uint32_t _index{0};
115 
116   // Leaf nodes will have values and non-leaf nodes will have iterators
117   // to the child node.
118   //
119   // TODO(JTS): If we ever switch to c++17 then we can use a std::variant
120   std::unique_ptr<typename Node::iterator> _child_it{};
121   value_type _val{};
122 
123   inline lw_shared_ptr<Node> own_node(const Node *node) {
124     return own_node(node, node->block_num());
125   }
126 
127   inline lw_shared_ptr<Node> own_node(const Node *node,
128                                       apfs_block_num block_num) {
129     return node->_pool.template get_block<Node>(
130         block_num, node->_pool, block_num, node->_decryption_key);
131   }
132 
133   template <typename Void = void>
134   auto init_value()
135       -> std::enable_if_t<Node::is_variable_kv_node::value, Void> {
136     if (this->_node->has_fixed_kv_size()) {
137       throw std::runtime_error("btree does not have variable sized keys");
138     }
139     const auto &t = _node->_table_data.toc.variable[_index];
140     const auto key_data = _node->_table_data.koff + t.key_offset;
141     const auto val_data = _node->_table_data.voff - t.val_offset;
142 
143     memory_view key{key_data, t.key_length};
144 
145     if (_node->is_leaf()) {
146       memory_view value{val_data, t.val_length};
147 
148       _val = {key, value};
149     } else {
150       const auto block_num = *((apfs_block_num *)val_data);
151 
152       _child_it = std::make_unique<typename Node::iterator>(
153           own_node(_node.get(), block_num), 0);
154     }
155   }
156 
157   template <typename Void = void>
158   auto init_value() -> std::enable_if_t<Node::is_fixed_kv_node::value, Void> {
159     if (!this->_node->has_fixed_kv_size()) {
160       throw std::runtime_error("btree does not have fixed sized keys");
161     }
162     const auto &t = _node->_table_data.toc.fixed[_index];
163     const auto key_data = _node->_table_data.koff + t.key_offset;
164     const auto val_data = _node->_table_data.voff - t.val_offset;
165 
166     if (_node->is_leaf()) {
167       _val = {(typename Node::key_type)key_data,
168               (typename Node::value_type)val_data};
169     } else {
170       const auto block_num = *((apfs_block_num *)val_data);
171 
172       _child_it = std::make_unique<typename Node::iterator>(
173           own_node(_node.get(), block_num), 0);
174     }
175   }
176 
177  public:
178   // Forward iterators must be DefaultConstructible
179   APFSBtreeNodeIterator() = default;
180 
181   APFSBtreeNodeIterator(const Node *node, uint32_t index);
182 
183   APFSBtreeNodeIterator(lw_shared_ptr<Node> &&node, uint32_t index);
184 
185   APFSBtreeNodeIterator(const Node *node, uint32_t index,
186                         typename Node::iterator &&child);
187 
188   virtual ~APFSBtreeNodeIterator() = default;
189 
190   APFSBtreeNodeIterator(const APFSBtreeNodeIterator &rhs) noexcept
191       : _node{rhs._node}, _index{rhs._index} {
192     if (_node->is_leaf()) {
193       _val = rhs._val;
194     } else if (rhs._child_it != nullptr) {
195       _child_it = std::make_unique<typename Node::iterator>(*rhs._child_it);
196     }
197   }
198 
199   APFSBtreeNodeIterator &operator=(const APFSBtreeNodeIterator &rhs) noexcept {
200     if (this != &rhs) {
201       this->~APFSBtreeNodeIterator();
202       new (this) APFSBtreeNodeIterator(rhs);
203     }
204 
205     return (*this);
206   };
207 
208   APFSBtreeNodeIterator(APFSBtreeNodeIterator &&rhs) noexcept
209       : _node{std::move(rhs._node)}, _index{std::move(rhs._index)} {
210     if (_node->is_leaf()) {
211       _val = std::move(rhs._val);
212     } else {
213       _child_it = std::move(rhs._child_it);
214     }
215   };
216 
217   APFSBtreeNodeIterator &operator=(APFSBtreeNodeIterator &&rhs) noexcept {
218     if (this != &rhs) {
219       this->~APFSBtreeNodeIterator();
220       new (this)
221           APFSBtreeNodeIterator(std::forward<APFSBtreeNodeIterator>(rhs));
222     }
223 
224     return (*this);
225   }
226 
227   bool is_valid() const noexcept {
228     if (_node == nullptr) {
229       return false;
230     }
231 
232     return (_index < _node->key_count());
233   }
234 
235   reference operator*() const noexcept {
236     if (_index >= _node->key_count()) {
237       return _val;
238     }
239 
240     // Leaf nodes return the value
241     if (_node->is_leaf()) {
242       return _val;
243     }
244 
245     // Non-Leaf nodes return the pointer
246     return _child_it->operator*();
247   }
248 
249   pointer operator->() const noexcept {
250     if (_index >= _node->key_count()) {
251       return nullptr;
252     }
253 
254     // Leaf nodes return the value
255     if (_node->is_leaf()) {
256       return &_val;
257     }
258 
259     // Non-Leaf nodes return the pointer
260     return _child_it->operator->();
261   }
262 
263   virtual APFSBtreeNodeIterator &operator++() {
264     // If we're a leaf node then we just need to iterate the count
265     if (_node->is_leaf()) {
266       if (_index < _node->key_count()) {
267         _index++;
268 
269         auto node{std::move(_node)};
270         auto index{_index};
271 
272         this->~APFSBtreeNodeIterator();
273         new (this) APFSBtreeNodeIterator(std::move(node), index);
274       }
275       return (*this);
276     }
277 
278     _child_it->operator++();
279 
280     if (*_child_it != _child_it->_node->end()) {
281       return (*this);
282     }
283 
284     _index++;
285 
286     auto node{std::move(_node)};
287     auto index{_index};
288 
289     this->~APFSBtreeNodeIterator();
290     new (this) APFSBtreeNodeIterator(std::move(node), index);
291 
292     return (*this);
293   }
294 
295   APFSBtreeNodeIterator operator++(int) {
296     APFSBtreeNodeIterator it{(*this)};
297 
298     this->operator++();
299 
300     return it;
301   }
302 
303   bool operator==(const APFSBtreeNodeIterator &rhs) const noexcept {
304     // Self check
305     if (this == &rhs) {
306       return true;
307     }
308 
309     // If only one of the nodes is nullptr then we're not a match, but if they
310     // both are then we are a match
311     if (_node == nullptr || rhs._node == nullptr) {
312       return (_node == rhs._node);
313     }
314 
315     // Ensure we have equivalent nodes and indexes
316     if (*_node != *rhs._node || _index != rhs._index) {
317       return false;
318     }
319 
320     // If we're leaves then we're good.
321     if (_node->is_leaf()) {
322       return true;
323     }
324 
325     // Otherwise, let's compare the child iterators.
326     return (*_child_it == *rhs._child_it);
327   }
328 
329   bool operator!=(const APFSBtreeNodeIterator &rhs) const noexcept {
330     return !this->operator==(rhs);
331   }
332 
333   friend Node;
334   friend APFSJObjBtreeNode;
335 };
336 
337 template <typename Key = memory_view, typename Value = memory_view>
338 class APFSBtreeNode : public APFSObject, public APFSOmap::node_tag {
339   using is_variable_kv_node = std::is_same<APFSBtreeNode, APFSBtreeNode<>>;
340   using is_fixed_kv_node =
341       std::integral_constant<bool, !is_variable_kv_node::value>;
342 
343   using key_type =
344       std::conditional_t<is_variable_kv_node::value, Key, const Key *>;
345   using value_type =
346       std::conditional_t<is_variable_kv_node::value, Value, const Value *>;
347   ;
348 
349  protected:
350   struct {
351     union {
352       void *v;
353       apfs_btentry_fixed *fixed;
354       apfs_btentry_variable *variable;
355     } toc;
356     char *voff;
357     char *koff;
358   } _table_data;
359 
360   const uint8_t *_decryption_key{};
361 
362   inline const apfs_btree_node *bn() const noexcept {
363     return reinterpret_cast<const apfs_btree_node *>(_storage.data());
364   }
365 
366   inline ptrdiff_t toffset() const noexcept {
367     // The table space offset is relative to the end of the header
368     return sizeof(apfs_btree_node) + bn()->table_space_offset;
369   }
370 
371   inline ptrdiff_t koffset() const noexcept {
372     // The keys table is immediately after the table space.
373     return toffset() + bn()->table_space_length;
374   }
375 
376   inline ptrdiff_t voffset() const noexcept {
377     // The value table is a negative index relative to the end of the block
378     // unless the node is a root node then it's relative to the footer
379     ptrdiff_t off = _pool.block_size();
380 
381     if (is_root()) {
382       off -= sizeof(apfs_btree_info);
383     }
384 
385     return off;
386   }
387 
388   template <typename KeyType = key_type>
389   inline auto key(uint32_t index) const
390       -> std::enable_if_t<is_variable_kv_node::value, KeyType> {
391     const auto &t = _table_data.toc.variable[index];
392     const auto key_data = _table_data.koff + t.key_offset;
393 
394     return {key_data, t.key_length};
395   }
396 
397   template <typename KeyType = key_type>
398   inline auto key(uint32_t index) const
399       -> std::enable_if_t<is_fixed_kv_node::value, KeyType> {
400     const auto &t = _table_data.toc.fixed[index];
401     const auto key_data = _table_data.koff + t.key_offset;
402 
403     return reinterpret_cast<KeyType>(key_data);
404   }
405 
406   template <typename Compare>
407   inline uint32_t contains_key(const key_type &key, Compare comp) const {
408     for (auto i = 0U; i < key_count(); i++) {
409       const auto k = this->key(i);
410       if (comp(k, key) > 0) {
411         if (i == 0) {
412           break;
413         }
414 
415         return i - 1;
416       }
417     }
418 
419     return key_count();
420   }
421 
422  public:
423   APFSBtreeNode(const APFSPool &pool, const apfs_block_num block_num,
424                 const uint8_t *key = nullptr)
425       : APFSObject(pool, block_num), _decryption_key{key} {
426     // Decrypt node if needed
427     if (key != nullptr) {
428       decrypt(key);
429     }
430 
431     if (obj_type() != APFS_OBJ_TYPE_BTREE_NODE &&
432         obj_type() != APFS_OBJ_TYPE_BTREE_ROOTNODE) {
433       throw std::runtime_error("APFSBtreeNode: invalid object type");
434     }
435 
436     _table_data.toc = {_storage.data() + toffset()};
437     _table_data.voff = _storage.data() + voffset();
438     _table_data.koff = _storage.data() + koffset();
439   }
440 
441   inline bool is_root() const noexcept {
442     return bit_is_set(bn()->flags, APFS_BTNODE_ROOT);
443   }
444 
445   inline bool is_leaf() const noexcept {
446     return bit_is_set(bn()->flags, APFS_BTNODE_LEAF);
447   }
448 
449   inline bool has_fixed_kv_size() const noexcept {
450     return bit_is_set(bn()->flags, APFS_BTNODE_FIXED_KV_SIZE);
451   }
452 
453   inline uint16_t level() const noexcept { return bn()->level; }
454 
455   inline uint32_t key_count() const noexcept { return bn()->key_count; }
456 
457   inline auto entries() const {
458     const auto vec = [&] {
459       std::vector<typename iterator::value_type> v{};
460 
461       std::for_each(begin(), end(), [&v](const auto e) { v.push_back(e); });
462 
463       return v;
464     }();
465 
466     return vec;
467   }
468 
469   inline const apfs_btree_info *info() const noexcept {
470     // Only root nodes contain the info struct
471     if (!is_root()) {
472       return nullptr;
473     }
474 
475     // The info structure is at the end of the object
476     const auto ptr =
477         _storage.data() + _storage.size() - sizeof(apfs_btree_info);
478 
479     return reinterpret_cast<const apfs_btree_info *>(ptr);
480   }
481 
482   // Iterators
483 
484  public:
485   using iterator = APFSBtreeNodeIterator<APFSBtreeNode>;
486 
487   iterator begin() const { return {this, 0}; }
488   iterator end() const { return {this, key_count()}; }
489 
490   template <typename T, typename Compare>
491   iterator find(const T &value, Compare comp) const {
492     // TODO(JTS): It turns out, when a disk has snapshots, there can be more
493     // than one entry in the objects tree that corresponds to the same oid.
494     // Since we do not currently support snapshots, we're always returning the
495     // last object with the id, because that should always be the newest object.
496     // When we support snapshots, this logic likely needs to change.
497 
498     // For leaf nodes we can just search the entries directly
499     if (is_leaf()) {
500       // Search for key that's equal to the value
501       for (auto i = key_count(); i > 0; i--) {
502         const auto &k = key(i - 1);
503 
504         const auto res = comp(k, value);
505 
506         if (res == 0) {
507           // We've found it!
508           return {this, i - 1};
509         }
510 
511         if (res < 0) {
512           // We've gone too far
513           break;
514         }
515       }
516 
517       // Not found
518       return end();
519     }
520 
521     // For non-leaf nodes we can be more efficient by skipping searches of
522     // sub-trees that don't contain the object
523 
524     // Search for the last key that's <= the value
525     for (auto i = key_count(); i > 0; i--) {
526       const auto &k = key(i - 1);
527 
528       if (comp(k, value) <= 0) {
529         iterator it{this, i - 1};
530 
531         auto ret = it._child_it->_node->find(value, comp);
532         if (ret == it._child_it->_node->end()) {
533           return end();
534         }
535 
536         return {this, i - 1, std::move(ret)};
537       }
538     }
539 
540     // Not Found
541     return end();
542   }
543 
544   friend iterator;
545 
546   template <typename T>
547   friend class APFSBtreeNodeIterator;
548 };
549 
550 class APFSObjectBtreeNode
551     : public APFSBtreeNode<apfs_omap_key, apfs_omap_value> {
552   uint64_t _xid;
553 
554  public:
555   APFSObjectBtreeNode(const APFSPool &pool, apfs_block_num block_num);
556   APFSObjectBtreeNode(const APFSPool &pool, apfs_block_num block_num,
557                       uint64_t snap_xid);
558 
559   iterator find(uint64_t oid) const;
560 
561   inline void snapshot(uint64_t snap_xid) { _xid = snap_xid; }
562 };
563 
564 class APFSSnapshotMetaBtreeNode : public APFSBtreeNode<> {
565  public:
566   APFSSnapshotMetaBtreeNode(const APFSPool &pool, apfs_block_num block_num);
567 };
568 
569 class APFSJObjBtreeNode : public APFSBtreeNode<> {
570   const APFSObjectBtreeNode *_obj_root;
571 
572  public:
573   APFSJObjBtreeNode(const APFSObjectBtreeNode *obj_root,
574                     apfs_block_num block_num, const uint8_t *key);
575 
576 
577   APFSJObjBtreeNode(APFSJObjBtreeNode &&) = default;
578 
579   using iterator = APFSBtreeNodeIterator<APFSJObjBtreeNode>;
580 
581   inline bool is_leaf() const noexcept { return (bn()->level == 0); }
582 
583   inline iterator begin() const { return {this, 0}; }
584   inline iterator end() const { return {this, key_count()}; }
585 
586   template <typename T, typename Compare>
587   inline iterator find(const T &value, Compare comp) const {
588     // For leaf nodes we can just search the entries directly
589     if (is_leaf()) {
590       // Search for key that's equal to the value
591       for (auto i = 0U; i < key_count(); i++) {
592         const auto &k = key(i);
593 
594         const auto res = comp(k, value);
595 
596         if (res == 0) {
597           // We've found it!
598           return {this, i};
599         }
600 
601         if (res > 0) {
602           // We've gone too far
603           break;
604         }
605       }
606 
607       // Not found
608       return end();
609     }
610 
611     // For non-leaf nodes we can be more efficient by skipping searches of
612     // sub-trees that don't contain the object
613 
614     uint32_t last = std::numeric_limits<uint32_t>::max();
615     // Search for key that's <= the value
616     for (auto i = 0U; i < key_count(); i++) {
617       const auto &k = key(i);
618 
619       const auto v = comp(k, value);
620 
621       if (v > 0) {
622         break;
623       }
624 
625       last = i;
626 
627       if (v == 0) {
628         // We need to see if the jobj might be in the last node
629         if (last != 0) {
630           iterator it{this, last - 1};
631 
632           auto ret = it._child_it->_node->find(value, comp);
633           if (ret != it._child_it->_node->end()) {
634             return {this, last - 1, std::move(ret)};
635           }
636         }
637 
638         break;
639       }
640     }
641 
642     if (last == std::numeric_limits<uint32_t>::max()) {
643       // Not Found
644       return end();
645     }
646 
647     iterator it{this, last};
648 
649     auto ret = it._child_it->_node->find(value, comp);
650     if (ret == it._child_it->_node->end()) {
651       return end();
652     }
653 
654     return {this, last, std::move(ret)};
655   }
656 
657   template <typename T, typename Compare>
658   inline std::pair<iterator, iterator> find_range(const T &value,
659                                                   Compare comp) const {
660     auto s = find(value, comp);
661 
662     if (s == end()) {
663       // Not found
664       return {end(), end()};
665     }
666 
667     auto e = std::find_if(
668         s, end(), [&](const auto &a) noexcept(noexcept(comp(a.key, value))) {
669           return comp(a.key, value) != 0;
670         });
671 
672     return std::make_pair(std::move(s), std::move(e));
673   }
674 
675   friend iterator;
676 };
677 
678 class APFSSpacemanCIB : public APFSObject {
679  protected:
680   inline const apfs_spaceman_cib *cib() const noexcept {
681     return reinterpret_cast<const apfs_spaceman_cib *>(_storage.data());
682   }
683 
684  public:
685   using APFSObject::APFSObject;
686   APFSSpacemanCIB(const APFSPool &pool, const apfs_block_num block_num);
687 
688   using bm_entry = struct {
689     uint64_t offset;
690     uint32_t total_blocks;
691     uint32_t free_blocks;
692     apfs_block_num bm_block;
693   };
694 
695   const std::vector<bm_entry> bm_entries() const;
696 };
697 
698 class APFSSpacemanCAB : public APFSObject {
699  protected:
700   inline const apfs_spaceman_cab *cab() const noexcept {
701     return reinterpret_cast<const apfs_spaceman_cab *>(_storage.data());
702   }
703 
704  public:
705   using APFSObject::APFSObject;
706   APFSSpacemanCAB(const APFSPool &pool, const apfs_block_num block_num);
707 
708   inline uint32_t index() const noexcept { return cab()->index; }
709 
710   inline uint32_t cib_count() const noexcept { return cab()->cib_count; }
711 
712   const std::vector<apfs_block_num> cib_blocks() const;
713 };
714 
715 class APFSSpaceman : public APFSObject {
716   mutable std::vector<APFSSpacemanCIB::bm_entry> _bm_entries{};
717 
718 #ifdef TSK_MULTITHREAD_LIB
719   mutable std::mutex _bm_entries_init_lock;
720 #endif
721 
722  protected:
723   inline const apfs_spaceman *sm() const noexcept {
724     return reinterpret_cast<const apfs_spaceman *>(_storage.data());
725   }
726 
727   inline const apfs_block_num *entries() const noexcept {
728     return reinterpret_cast<const apfs_block_num *>(
729         (uintptr_t)sm() + sm()->devs[APFS_SD_MAIN].addr_offset);
730   }
731 
732  public:
733   using APFSObject::APFSObject;
734   APFSSpaceman(const APFSPool &pool, const apfs_block_num block_num);
735 
736   const std::vector<APFSSpacemanCIB::bm_entry> &bm_entries() const;
737 
738   using range = APFSPool::range;
739 
740   inline uint64_t num_free_blocks() const noexcept {
741     return sm()->devs[APFS_SD_MAIN].free_count;
742   }
743 
744   const std::vector<range> unallocated_ranges() const;
745 };
746 
747 class APFSBitmapBlock : public APFSBlock {
748   enum class mode {
749     unset,
750     set,
751   };
752 
753   // A special return value for next that is returned when there are no more
754   // bits to scan.
755   static constexpr auto no_bits_left = std::numeric_limits<uint32_t>::max();
756 
757   // Number of bits in cache
758   static constexpr uint32_t cached_bits = sizeof(uintptr_t) * 8;
759 
760   const APFSSpacemanCIB::bm_entry _entry;
761   uint32_t _hint{};
762   mode _mode{mode::unset};
763   uintptr_t _cache{};
764 
765   inline bool done() const noexcept { return (_hint >= _entry.total_blocks); }
766 
767   inline void reset() noexcept { _hint = 0; }
768 
769   // Find the index of the next scanned bit.  If the scan mode is
770   // set to "set" then this will be a 1 bit and if the mode is
771   // "unset" then it will be a zero bit.  If no more bits are found
772   // then no_bits_left is returned.
773   //
774   // Returns the index of the next scanned bit or no_bits_left
775   //
776   uint32_t next() noexcept;
777 
778   // Cache the next set of bits from the buffer.
779   inline void cache_next() noexcept {
780     //
781     // Interpret the buffer as an array of 32-bit ints.
782     //
783     const auto array = reinterpret_cast<uintptr_t *>(_storage.data());
784 
785     //
786     // Fetch the next integer to the cache.
787     //
788     _cache = array[_hint / cached_bits];
789 
790     //
791     // If we're scanning for unset bits then we need to invert the cached
792     // bits, since we only actually have logic for searching for set bits.
793     //
794     if (_mode == mode::unset) {
795       _cache = ~_cache;
796     }
797   }
798 
799   //
800   // Toggles the scan mode from set to unset or vice-versa.
801   //
802   // Returns the new scan mode
803   //
804   inline void toggle_mode() noexcept {
805     // Toggle the scan mode based on the current mode.
806     if (_mode == mode::set) {
807       _mode = mode::unset;
808     } else {
809       _mode = mode::set;
810     }
811 
812     // Invert the cached bits
813     _cache = ~_cache;
814   }
815 
816  public:
817   using APFSBlock::APFSBlock;
818 
819   APFSBitmapBlock(const APFSPool &pool, const APFSSpacemanCIB::bm_entry &entry);
820 
821   const std::vector<APFSSpaceman::range> unallocated_ranges();
822 };
823 
824 class APFSKeybag : public APFSObject {
825  protected:
826   inline const apfs_keybag *kb() const noexcept {
827     return reinterpret_cast<const apfs_keybag *>(_storage.data());
828   }
829 
830   using key = struct {
831     Guid uuid;
832     std::unique_ptr<uint8_t[]> data;
833     uint16_t type;
834   };
835 
836  public:
837   APFSKeybag(const APFSPool &pool, const apfs_block_num block_num,
838              const uint8_t *key, const uint8_t *key2 = nullptr);
839 
840   std::unique_ptr<uint8_t[]> get_key(const Guid &uuid, uint16_t type) const;
841 
842   std::vector<key> get_keys() const;
843 };
844 
845 class APFSSuperblock : public APFSObject {
846   mutable std::unique_ptr<APFSSpaceman> _spaceman{};
847 
848 #ifdef TSK_MULTITHREAD_LIB
849   mutable std::mutex _spaceman_init_lock;
850 #endif
851 
852  protected:
853   inline const apfs_nx_superblock *sb() const noexcept {
854     return reinterpret_cast<const apfs_nx_superblock *>(_storage.data());
855   }
856 
857   inline APFSOmap omap() const { return {_pool, sb()->omap_oid}; };
858 
859   const APFSSpaceman &spaceman() const;
860 
861   class Keybag : public APFSKeybag {
862    public:
863     Keybag(const APFSSuperblock &sb);
864   };
865 
866  public:
867   using APFSObject::APFSObject;
868 
869   APFSSuperblock(const APFSPool &pool, const apfs_block_num block_num);
870 
871   inline uint32_t block_size() const noexcept { return sb()->block_size; }
872 
873   inline uint64_t num_blocks() const noexcept { return sb()->block_count; }
874 
875   inline uint64_t num_free_blocks() const {
876     return spaceman().num_free_blocks();
877   }
878 
879   inline Guid uuid() const { return {sb()->uuid}; }
880 
881   const std::vector<apfs_block_num> volume_blocks() const;
882   const std::vector<apfs_block_num> sm_bitmap_blocks() const;
883   inline const std::vector<APFSSpaceman::range> unallocated_ranges() const {
884     return spaceman().unallocated_ranges();
885   }
886 
887   const std::vector<uint64_t> volume_oids() const;
888 
889   apfs_block_num checkpoint_desc_block() const;
890 
891   Keybag keybag() const;
892 
893   friend APFSPool;
894 };
895 
896 class APFSCheckpointMap : public APFSObject {
897  protected:
898   inline const apfs_checkpoint_map *map() const noexcept {
899     return reinterpret_cast<const apfs_checkpoint_map *>(_storage.data());
900   }
901 
902  public:
903   using APFSObject::APFSObject;
904   APFSCheckpointMap(const APFSPool &pool, const apfs_block_num block_num);
905 
906   apfs_block_num get_object_block(uint64_t oid, APFS_OBJ_TYPE_ENUM type) const;
907 };
908 
909 // Object representation of an APFS Physical Extent Reference
910 #pragma pack(push, 1)
911 struct APFSPhysicalExtentRef : apfs_phys_extent {
912   inline apfs_phys_extent_kind kind() const noexcept {
913     return static_cast<apfs_phys_extent_kind>(bitfield_value(
914         len_and_kind, APFS_PHYS_EXTENT_KIND_BITS, APFS_PHYS_EXTENT_KIND_SHIFT));
915   }
916 
917   inline uint64_t block_count() const noexcept {
918     return bitfield_value(len_and_kind, APFS_PHYS_EXTENT_LEN_BITS,
919                           APFS_PHYS_EXTENT_LEN_SHIFT);
920   }
921 
922   inline uint64_t owner_oid() const noexcept { return owning_obj_id; }
923 
924   inline uint32_t ref_count() const noexcept { return refcnt; }
925 };
926 static_assert(sizeof(APFSPhysicalExtentRef) == sizeof(apfs_phys_extent),
927               "No member fields can be added to APFSPhysicalExtentRef");
928 
929 struct APFSPhysicalExtentKey : apfs_phys_extent_key {
930   inline apfs_block_num start_block() const noexcept {
931     return bitfield_value(start_block_and_type,
932                           APFS_PHYS_EXTENT_START_BLOCK_BITS,
933                           APFS_PHYS_EXTENT_START_BLOCK_SHIFT);
934   }
935 };
936 static_assert(sizeof(APFSPhysicalExtentKey) == sizeof(apfs_phys_extent_key),
937               "No member fields can be added to APFSPhysicalExtentKey");
938 #pragma pack(pop)
939 
940 class APFSExtentRefBtreeNode : public APFSBtreeNode<> {
941  public:
942   APFSExtentRefBtreeNode(const APFSPool &pool, apfs_block_num block_num);
943 
944   iterator find(apfs_block_num) const;
945 };
946 
947 class APFSJObjTree;
948 class APFSFileSystem : public APFSObject {
949  public:
950   using unmount_log_t = struct {
951     uint64_t timestamp;
952     std::string logstr;
953     uint64_t last_xid;
954   };
955 
956   using snapshot_t = struct {
957     std::string name;
958     uint64_t timestamp;
959     uint64_t snap_xid;
960     bool dataless;
961   };
962 
963   struct wrapped_kek {
964     Guid uuid;
965     uint8_t data[0x28];
966     uint64_t iterations;
967     uint64_t flags;
968     uint8_t salt[0x10];
969     wrapped_kek(Guid &&uuid, const std::unique_ptr<uint8_t[]> &);
970 
971     inline bool hw_crypt() const noexcept {
972       // If this bit is set, some sort of hardware encryption is used.
973       return bit_is_set(flags, 1ULL << 56);
974     }
975 
976     inline bool cs() const noexcept {
977       // If this bit is set the KEK is 0x10 bytes instead of 0x20
978       return bit_is_set(flags, 1ULL << 57);
979     }
980   };
981 
982   struct crypto_info_t {
983     apfs_block_num recs_block_num{};
984     std::string password_hint{};
985     std::string password{};
986     std::vector<wrapped_kek> wrapped_keks{};
987     uint64_t vek_flags{};
988     uint8_t wrapped_vek[0x28]{};
989     uint8_t vek_uuid[0x10]{};
990     uint8_t vek[0x20]{};
991     bool unlocked{};
992 
993     inline uint64_t unk16() const noexcept {
994       // If this byte is not zero (1) then some other sort of decryption is used
995       return bitfield_value(vek_flags, 8, 16);
996     }
997 
998     inline bool hw_crypt() const noexcept {
999       // If this bit is set, some sort of hardware encryption is used.
1000       return bit_is_set(vek_flags, 1ULL << 56);
1001     }
1002 
1003     inline bool cs() const noexcept {
1004       // If this bit is set the VEK is 0x10 bytes instead of 0x20
1005       return bit_is_set(vek_flags, 1ULL << 57);
1006     }
1007   };
1008 
1009  protected:
1010   class Keybag : public APFSKeybag {
1011    public:
1012     Keybag(const APFSFileSystem &, apfs_block_num);
1013   };
1014 
1015   inline const apfs_superblock *fs() const noexcept {
1016     return reinterpret_cast<const apfs_superblock *>(_storage.data());
1017   }
1018 
1019   inline uint64_t rdo() const noexcept { return fs()->root_tree_oid; }
1020 
1021   void init_crypto_info();
1022 
1023   crypto_info_t _crypto{};
1024 
1025  public:
1026   using APFSObject::APFSObject;
1027   APFSFileSystem(const APFSPool &pool, const apfs_block_num block_num);
1028   APFSFileSystem(const APFSPool &pool, const apfs_block_num block_num,
1029                  const std::string &password);
1030 
1031   const std::vector<snapshot_t> snapshots() const;
1032 
1033   bool unlock(const std::string &password) noexcept;
1034 
1035   inline Guid uuid() const noexcept { return {fs()->uuid}; }
1036 
1037   inline std::string name() const { return {fs()->name}; }
1038 
1039   inline std::string formatted_by() const { return {fs()->formatted_by}; }
1040 
1041   inline const std::string &password_hint() const noexcept {
1042     return _crypto.password_hint;
1043   }
1044 
1045   inline const auto &crypto_info() const noexcept { return _crypto; }
1046 
1047   inline const uint8_t *decryption_key() const noexcept {
1048     if (_crypto.unlocked) {
1049       return _crypto.vek;
1050     }
1051 
1052     return nullptr;
1053   }
1054 
1055   inline APFS_VOLUME_ROLE role() const noexcept {
1056     return APFS_VOLUME_ROLE(fs()->role);
1057   }
1058 
1059   inline uint64_t reserved() const noexcept {
1060     return fs()->reserve_blocks * _pool.block_size();
1061   }
1062 
1063   inline uint64_t quota() const noexcept {
1064     return fs()->quota_blocks * _pool.block_size();
1065   }
1066 
1067   inline uint64_t used() const noexcept {
1068     return fs()->alloc_blocks * _pool.block_size();
1069   }
1070 
1071   inline uint64_t reserved_blocks() const noexcept {
1072     return fs()->reserve_blocks;
1073   }
1074 
1075   inline uint64_t quota_blocks() const noexcept { return fs()->quota_blocks; }
1076 
1077   inline uint64_t alloc_blocks() const noexcept { return fs()->alloc_blocks; }
1078 
1079   inline uint64_t last_inum() const noexcept { return fs()->next_inum - 1; }
1080 
1081   inline bool encrypted() const noexcept {
1082     return !bit_is_set(fs()->flags, APFS_SB_UNENCRYPTED);
1083   }
1084 
1085   inline bool case_sensitive() const noexcept {
1086     return !bit_is_set(fs()->incompatible_features,
1087                        APFS_SB_INCOMPAT_CASE_INSENSITIVE);
1088   }
1089 
1090   inline uint64_t created() const noexcept { return fs()->created_timestamp; }
1091 
1092   inline uint64_t changed() const noexcept { return fs()->last_mod_time; }
1093 
1094   const std::vector<unmount_log_t> unmount_log() const;
1095 
1096   apfs_block_num omap_root() const;
1097 
1098   APFSJObjTree root_jobj_tree() const;
1099 
1100   APFSExtentRefBtreeNode extent_ref_tree() const {
1101     return {pool(), fs()->extentref_tree_oid};
1102   }
1103 
1104   APFSSnapshotMetaBtreeNode snap_meta_tree() const {
1105     return {pool(), fs()->snap_meta_tree_oid};
1106   }
1107 
1108   friend APFSJObjTree;
1109 };
1110 
1111 struct APFSJObjKey {
1112   uint64_t oid_and_type;
1113 
1114   inline uint64_t oid() const noexcept {
1115     return bitfield_value(oid_and_type, 60, 0);
1116   }
1117 
1118   inline uint64_t type() const noexcept {
1119     return bitfield_value(oid_and_type, 4, 60);
1120   }
1121 };
1122 static_assert(sizeof(APFSJObjKey) == 0x08, "invalid struct padding");
1123 
1124 // Template Specializations
1125 
1126 // Initializes the value for variable-sized key/values
1127 
1128 template <>
1129 inline lw_shared_ptr<APFSJObjBtreeNode>
1130 APFSBtreeNodeIterator<APFSJObjBtreeNode>::own_node(
1131     const APFSJObjBtreeNode *node, apfs_block_num block_num) {
1132   return node->_pool.template get_block<APFSJObjBtreeNode>(
1133       block_num, node->_obj_root, block_num, node->_decryption_key);
1134 }
1135 
1136 template <>
1137 template <>
1138 inline void APFSBtreeNodeIterator<APFSJObjBtreeNode>::init_value<void>() {
1139   const auto &t = _node->_table_data.toc.variable[_index];
1140   const auto key_data = _node->_table_data.koff + t.key_offset;
1141   const auto val_data = _node->_table_data.voff - t.val_offset;
1142 
1143   memory_view key{key_data, t.key_length};
1144 
1145   if (_node->is_leaf()) {
1146     memory_view value{val_data, t.val_length};
1147 
1148     _val = {key, value};
1149   } else {
1150     const auto obj_num = *((uint64_t *)val_data);
1151 
1152     const auto it = _node->_obj_root->find(obj_num);
1153 
1154     if (it == _node->_obj_root->end()) {
1155       throw std::runtime_error("can not find jobj");
1156     }
1157 
1158     _child_it = std::make_unique<typename APFSJObjBtreeNode::iterator>(
1159         own_node(_node.get(), it->value->paddr), 0);
1160   }
1161 }
1162 
1163 template <typename Node>
1164 APFSBtreeNodeIterator<Node>::APFSBtreeNodeIterator(const Node *node,
1165                                                    uint32_t index)
1166     : _node{own_node(node)}, _index{index} {
1167   // If we're the end, then there's nothing to do
1168   if (index >= _node->key_count()) {
1169     return;
1170   }
1171 
1172   init_value();
1173 }
1174 
1175 template <typename Node>
1176 APFSBtreeNodeIterator<Node>::APFSBtreeNodeIterator(lw_shared_ptr<Node> &&node,
1177                                                    uint32_t index)
1178     : _node{std::forward<lw_shared_ptr<Node>>(node)}, _index{index} {
1179   // If we're the end, then there's nothing to do
1180   if (index >= _node->key_count()) {
1181     return;
1182   }
1183 
1184   init_value();
1185 }
1186 
1187 template <typename Node>
1188 APFSBtreeNodeIterator<Node>::APFSBtreeNodeIterator(
1189     const Node *node, uint32_t index, typename Node::iterator &&child)
1190     : _node{own_node(node)}, _index{index} {
1191   _child_it = std::make_unique<typename Node::iterator>(
1192       std::forward<typename Node::iterator>(child));
1193 }
1194