1 /*
2 * B-tree header functions
3 *
4 * Copyright (C) 2009-2021, Joachim Metz <joachim.metz@gmail.com>
5 *
6 * Refer to AUTHORS for acknowledgements.
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22 #include <common.h>
23 #include <byte_stream.h>
24 #include <memory.h>
25 #include <types.h>
26
27 #include "libfshfs_btree_header.h"
28 #include "libfshfs_debug.h"
29 #include "libfshfs_libcerror.h"
30 #include "libfshfs_libcnotify.h"
31
32 #include "fshfs_btree.h"
33
34 /* Creates a B-tree header
35 * Make sure the value btree_header is referencing, is set to NULL
36 * Returns 1 if successful or -1 on error
37 */
libfshfs_btree_header_initialize(libfshfs_btree_header_t ** btree_header,libcerror_error_t ** error)38 int libfshfs_btree_header_initialize(
39 libfshfs_btree_header_t **btree_header,
40 libcerror_error_t **error )
41 {
42 static char *function = "libfshfs_btree_header_initialize";
43
44 if( btree_header == NULL )
45 {
46 libcerror_error_set(
47 error,
48 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
49 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
50 "%s: invalid B-tree header.",
51 function );
52
53 return( -1 );
54 }
55 if( *btree_header != NULL )
56 {
57 libcerror_error_set(
58 error,
59 LIBCERROR_ERROR_DOMAIN_RUNTIME,
60 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
61 "%s: invalid B-tree header value already set.",
62 function );
63
64 return( -1 );
65 }
66 *btree_header = memory_allocate_structure(
67 libfshfs_btree_header_t );
68
69 if( *btree_header == NULL )
70 {
71 libcerror_error_set(
72 error,
73 LIBCERROR_ERROR_DOMAIN_MEMORY,
74 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
75 "%s: unable to create B-tree header.",
76 function );
77
78 goto on_error;
79 }
80 if( memory_set(
81 *btree_header,
82 0,
83 sizeof( libfshfs_btree_header_t ) ) == NULL )
84 {
85 libcerror_error_set(
86 error,
87 LIBCERROR_ERROR_DOMAIN_MEMORY,
88 LIBCERROR_MEMORY_ERROR_SET_FAILED,
89 "%s: unable to clear B-tree header.",
90 function );
91
92 goto on_error;
93 }
94 return( 1 );
95
96 on_error:
97 if( *btree_header != NULL )
98 {
99 memory_free(
100 *btree_header );
101
102 *btree_header = NULL;
103 }
104 return( -1 );
105 }
106
107 /* Frees a B-tree header
108 * Returns 1 if successful or -1 on error
109 */
libfshfs_btree_header_free(libfshfs_btree_header_t ** btree_header,libcerror_error_t ** error)110 int libfshfs_btree_header_free(
111 libfshfs_btree_header_t **btree_header,
112 libcerror_error_t **error )
113 {
114 static char *function = "libfshfs_btree_header_free";
115
116 if( btree_header == NULL )
117 {
118 libcerror_error_set(
119 error,
120 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
121 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
122 "%s: invalid B-tree header.",
123 function );
124
125 return( -1 );
126 }
127 if( *btree_header != NULL )
128 {
129 memory_free(
130 *btree_header );
131
132 *btree_header = NULL;
133 }
134 return( 1 );
135 }
136
137 /* Reads a B-tree header
138 * Returns 1 if successful or -1 on error
139 */
libfshfs_btree_header_read_data(libfshfs_btree_header_t * btree_header,const uint8_t * data,size_t data_size,libcerror_error_t ** error)140 int libfshfs_btree_header_read_data(
141 libfshfs_btree_header_t *btree_header,
142 const uint8_t *data,
143 size_t data_size,
144 libcerror_error_t **error )
145 {
146 static char *function = "libfshfs_btree_header_read_data";
147
148 #if defined( HAVE_DEBUG_OUTPUT )
149 uint32_t value_32bit = 0;
150 uint16_t value_16bit = 0;
151 #endif
152
153 if( btree_header == NULL )
154 {
155 libcerror_error_set(
156 error,
157 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
158 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
159 "%s: invalid B-tree header.",
160 function );
161
162 return( -1 );
163 }
164 if( data == NULL )
165 {
166 libcerror_error_set(
167 error,
168 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
169 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
170 "%s: invalid data.",
171 function );
172
173 return( -1 );
174 }
175 if( ( data_size < sizeof( fshfs_btree_header_record_t ) )
176 || ( data_size > (size_t) SSIZE_MAX ) )
177 {
178 libcerror_error_set(
179 error,
180 LIBCERROR_ERROR_DOMAIN_RUNTIME,
181 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
182 "%s: invalid data size value out of bounds.",
183 function );
184
185 return( -1 );
186 }
187 #if defined( HAVE_DEBUG_OUTPUT )
188 if( libcnotify_verbose != 0 )
189 {
190 libcnotify_printf(
191 "%s: B-tree header record data:\n",
192 function );
193 libcnotify_print_data(
194 (uint8_t *) data,
195 sizeof( fshfs_btree_header_record_t ),
196 LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
197 }
198 #endif
199 byte_stream_copy_to_uint32_big_endian(
200 ( (fshfs_btree_header_record_t *) data )->root_node_number,
201 btree_header->root_node_number );
202
203 byte_stream_copy_to_uint32_big_endian(
204 ( (fshfs_btree_header_record_t *) data )->first_leaf_node_number,
205 btree_header->first_leaf_node_number );
206
207 byte_stream_copy_to_uint32_big_endian(
208 ( (fshfs_btree_header_record_t *) data )->last_leaf_node_number,
209 btree_header->last_leaf_node_number );
210
211 byte_stream_copy_to_uint16_big_endian(
212 ( (fshfs_btree_header_record_t *) data )->node_size,
213 btree_header->node_size );
214
215 #if defined( HAVE_DEBUG_OUTPUT )
216 if( libcnotify_verbose != 0 )
217 {
218 byte_stream_copy_to_uint16_big_endian(
219 ( (fshfs_btree_header_record_t *) data )->depth,
220 value_16bit );
221 libcnotify_printf(
222 "%s: depth\t\t\t\t\t: %" PRIu16 "\n",
223 function,
224 value_16bit );
225
226 libcnotify_printf(
227 "%s: root node number\t\t\t: %" PRIu16 "\n",
228 function,
229 btree_header->root_node_number );
230
231 byte_stream_copy_to_uint32_big_endian(
232 ( (fshfs_btree_header_record_t *) data )->number_of_data_records,
233 value_32bit );
234 libcnotify_printf(
235 "%s: number of data records\t\t\t: %" PRIu32 "\n",
236 function,
237 value_32bit );
238
239 libcnotify_printf(
240 "%s: first leaf node number\t\t\t: %" PRIu32 "\n",
241 function,
242 btree_header->first_leaf_node_number );
243
244 libcnotify_printf(
245 "%s: last leaf node number\t\t\t: %" PRIu32 "\n",
246 function,
247 btree_header->last_leaf_node_number );
248
249 libcnotify_printf(
250 "%s: node size\t\t\t\t: %" PRIu16 "\n",
251 function,
252 btree_header->node_size );
253
254 byte_stream_copy_to_uint16_big_endian(
255 ( (fshfs_btree_header_record_t *) data )->maximum_key_size,
256 value_16bit );
257 libcnotify_printf(
258 "%s: maximum key size\t\t\t: %" PRIu16 "\n",
259 function,
260 value_16bit );
261
262 byte_stream_copy_to_uint32_big_endian(
263 ( (fshfs_btree_header_record_t *) data )->number_of_nodes,
264 value_32bit );
265 libcnotify_printf(
266 "%s: number of nodes\t\t\t: %" PRIu32 "\n",
267 function,
268 value_32bit );
269
270 byte_stream_copy_to_uint32_big_endian(
271 ( (fshfs_btree_header_record_t *) data )->number_of_free_nodes,
272 value_32bit );
273 libcnotify_printf(
274 "%s: number of free nodes\t\t\t: %" PRIu32 "\n",
275 function,
276 value_32bit );
277
278 /* TODO show different debug info for HFS */
279
280 byte_stream_copy_to_uint16_big_endian(
281 ( (fshfs_btree_header_record_t *) data )->unknown1,
282 value_16bit );
283 libcnotify_printf(
284 "%s: unknown1\t\t\t\t: %" PRIu16 "\n",
285 function,
286 value_16bit );
287
288 byte_stream_copy_to_uint32_big_endian(
289 ( (fshfs_btree_header_record_t *) data )->clump_size,
290 value_32bit );
291 libcnotify_printf(
292 "%s: clump size\t\t\t\t: %" PRIu32 "\n",
293 function,
294 value_32bit );
295
296 libcnotify_printf(
297 "%s: file type\t\t\t\t: 0x%02" PRIx8 "\n",
298 function,
299 ( (fshfs_btree_header_record_t *) data )->file_type );
300
301 libcnotify_printf(
302 "%s: key compare type\t\t\t: 0x%02" PRIx8 "\n",
303 function,
304 ( (fshfs_btree_header_record_t *) data )->key_compare_type );
305
306 byte_stream_copy_to_uint32_big_endian(
307 ( (fshfs_btree_header_record_t *) data )->attributes,
308 value_32bit );
309 libcnotify_printf(
310 "%s: attributes\t\t\t\t: 0x%08" PRIx32 "\n",
311 function,
312 value_32bit );
313 libfshfs_debug_print_btree_attribute_flags(
314 value_32bit );
315 libcnotify_printf(
316 "\n" );
317
318 libcnotify_printf(
319 "%s: unknown:\n",
320 function );
321 libcnotify_print_data(
322 ( (fshfs_btree_header_record_t *) data )->unknown2,
323 64,
324 LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
325 }
326 #endif /* defined( HAVE_DEBUG_OUTPUT ) */
327
328 /* TODO check if node side is supported: 512 or 4096
329 */
330 return( 1 );
331 }
332
333