/src/sleuthkit/tsk/pool/tsk_apfs.hpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * The Sleuth Kit |
3 | | * |
4 | | * Brian Carrier [carrier <at> sleuthkit [dot] org] |
5 | | * Copyright (c) 2019-2020 Brian Carrier. All Rights reserved |
6 | | * Copyright (c) 2018-2019 BlackBag Technologies. All Rights reserved |
7 | | * |
8 | | * This software is distributed under the Common Public License 1.0 |
9 | | */ |
10 | | /** \@file Public C++ API */ |
11 | | #pragma once |
12 | | |
13 | | #include "tsk_apfs.h" |
14 | | #include "tsk_pool.hpp" |
15 | | |
16 | | #include <array> |
17 | | #include <memory> |
18 | | #include <unordered_map> |
19 | | |
20 | | #include "tsk/fs/tsk_apfs.h" |
21 | | #include "tsk/util/lw_shared_ptr.hpp" |
22 | | |
23 | | class APFSSuperblock; |
24 | | class APFSFileSystem; |
25 | | class APFSPool; |
26 | | |
27 | | class APFSBlock { |
28 | | protected: |
29 | | using storage = std::array<char, APFS_BLOCK_SIZE>; |
30 | | |
31 | | storage _storage; |
32 | | const APFSPool &_pool; |
33 | | const apfs_block_num _block_num; |
34 | | |
35 | | // disable default construction |
36 | | APFSBlock() = delete; |
37 | | |
38 | | // Copies are expensive here, so let's disable them |
39 | | APFSBlock(const APFSBlock &) = delete; |
40 | | APFSBlock &operator=(const APFSBlock &) = delete; |
41 | | |
42 | | public: |
43 | | APFSBlock(const APFSPool &pool, const apfs_block_num block_num); |
44 | | |
45 | | // Move constructible |
46 | 0 | APFSBlock(APFSBlock &&) = default; |
47 | | |
48 | 5.59k | virtual ~APFSBlock() = default; |
49 | | |
50 | | void decrypt(const uint8_t *key, const uint8_t *key2 = nullptr) noexcept; |
51 | | |
52 | | void dump() const noexcept; |
53 | | |
54 | 228 | inline bool operator==(const APFSBlock &rhs) const noexcept { |
55 | 228 | if (this == &rhs) { |
56 | 228 | return true; |
57 | 228 | } |
58 | | |
59 | 0 | return (&_pool == &rhs._pool && _block_num == rhs._block_num); |
60 | 228 | } |
61 | | |
62 | 228 | inline bool operator!=(const APFSBlock &rhs) const noexcept { |
63 | 228 | return !this->operator==(rhs); |
64 | 228 | } |
65 | | |
66 | 17 | inline apfs_block_num block_num() const noexcept { return _block_num; } |
67 | 4 | inline const APFSPool &pool() const noexcept { return _pool; } |
68 | 0 | inline const char *data() const noexcept { return _storage.data(); } |
69 | | }; |
70 | | |
71 | | class APFSPool : public TSKPool { |
72 | | // This should give a worst case of caching ~64 MiB of blocks |
73 | | static constexpr auto block_cache_size = 1024 * 16; |
74 | | |
75 | | protected: |
76 | | TSK_IMG_INFO *_img; |
77 | | TSK_OFF_T _offset; |
78 | | |
79 | | apfs_block_num _nx_block_num; |
80 | | std::vector<apfs_block_num> _vol_blocks; |
81 | | |
82 | | // TODO(JTS): make thread safe if needed. The locking in the higher-level APIs should prevent issues. |
83 | | mutable std::unordered_map<apfs_block_num, lw_shared_ptr<APFSBlock>> |
84 | | _block_cache{}; |
85 | | |
86 | | bool _hw_crypto{}; |
87 | | |
88 | | using nx_version = struct { |
89 | | apfs_block_num nx_block_num; |
90 | | uint64_t xid; |
91 | | }; |
92 | | |
93 | | public: |
94 | | APFSPool(std::vector<img_t> &&imgs, |
95 | | apfs_block_num nx_block_num = APFS_POOL_NX_BLOCK_LAST_KNOWN_GOOD); |
96 | | |
97 | | // Moveable |
98 | | APFSPool(APFSPool &&) = default; |
99 | | APFSPool &operator=(APFSPool &&) = default; |
100 | | |
101 | | // Not copyable because of TSK_IMG_INFO pointer |
102 | | APFSPool(const APFSPool &) = delete; |
103 | | APFSPool &operator=(const APFSPool &) = delete; |
104 | | |
105 | | std::vector<APFSFileSystem> volumes() const; |
106 | | |
107 | | ssize_t read(uint64_t address, char *buf, size_t buf_size) const |
108 | | noexcept final; |
109 | | |
110 | | // This is not thread safe, but locking in the higher level APIs appears to prevent any issues. |
111 | | template <typename T, typename... Args> |
112 | | inline lw_shared_ptr<T> get_block(apfs_block_num block, |
113 | 18 | Args &&... args) const { |
114 | 18 | const auto it = _block_cache.find(block); |
115 | 18 | if (it == _block_cache.end()) { |
116 | 11 | if (_block_cache.size() > block_cache_size) { |
117 | 0 | _block_cache.clear(); |
118 | 0 | } |
119 | 11 | _block_cache[block] = make_lw_shared<T>(std::forward<Args>(args)...); |
120 | 11 | return lw_static_pointer_cast<T>(_block_cache[block]); |
121 | 11 | } |
122 | | |
123 | 7 | return lw_static_pointer_cast<T>(it->second); |
124 | 18 | } lw_shared_ptr<APFSJObjBtreeNode> APFSPool::get_block<APFSJObjBtreeNode, APFSObjectBtreeNode const* const&, unsigned long&, unsigned char const* const&>(unsigned long, APFSObjectBtreeNode const* const&, unsigned long&, unsigned char const* const&) const Line | Count | Source | 113 | 4 | Args &&... args) const { | 114 | 4 | const auto it = _block_cache.find(block); | 115 | 4 | if (it == _block_cache.end()) { | 116 | 1 | if (_block_cache.size() > block_cache_size) { | 117 | 0 | _block_cache.clear(); | 118 | 0 | } | 119 | 1 | _block_cache[block] = make_lw_shared<T>(std::forward<Args>(args)...); | 120 | 1 | return lw_static_pointer_cast<T>(_block_cache[block]); | 121 | 1 | } | 122 | | | 123 | 3 | return lw_static_pointer_cast<T>(it->second); | 124 | 4 | } |
lw_shared_ptr<APFSBtreeNode<apfs_omap_key, apfs_omap_value> > APFSPool::get_block<APFSBtreeNode<apfs_omap_key, apfs_omap_value>, APFSPool const&, unsigned long&, unsigned char const* const&>(unsigned long, APFSPool const&, unsigned long&, unsigned char const* const&) const Line | Count | Source | 113 | 14 | Args &&... args) const { | 114 | 14 | const auto it = _block_cache.find(block); | 115 | 14 | if (it == _block_cache.end()) { | 116 | 10 | if (_block_cache.size() > block_cache_size) { | 117 | 0 | _block_cache.clear(); | 118 | 0 | } | 119 | 10 | _block_cache[block] = make_lw_shared<T>(std::forward<Args>(args)...); | 120 | 10 | return lw_static_pointer_cast<T>(_block_cache[block]); | 121 | 10 | } | 122 | | | 123 | 4 | return lw_static_pointer_cast<T>(it->second); | 124 | 14 | } |
Unexecuted instantiation: lw_shared_ptr<APFSBtreeNode<memory_view, memory_view> > APFSPool::get_block<APFSBtreeNode<memory_view, memory_view>, APFSPool const&, unsigned long&, unsigned char const* const&>(unsigned long, APFSPool const&, unsigned long&, unsigned char const* const&) const |
125 | | |
126 | | const std::vector<nx_version> known_versions() const; |
127 | | |
128 | | const std::vector<range> unallocated_ranges() const final; |
129 | | |
130 | | std::unique_ptr<APFSSuperblock> nx(bool validate = false) const; |
131 | | |
132 | 0 | inline bool hardware_crypto() const noexcept { return _hw_crypto; } |
133 | | |
134 | | void clear_cache() noexcept; |
135 | | |
136 | | friend class APFSBlock; |
137 | | }; |