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