/src/libcreg/libcreg/libcreg_key_navigation.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Key navigation functions |
3 | | * |
4 | | * Copyright (C) 2013-2024, 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 "libcreg_data_block.h" |
28 | | #include "libcreg_definitions.h" |
29 | | #include "libcreg_io_handle.h" |
30 | | #include "libcreg_key_name_entry.h" |
31 | | #include "libcreg_key_navigation.h" |
32 | | #include "libcreg_libbfio.h" |
33 | | #include "libcreg_libcerror.h" |
34 | | #include "libcreg_libcnotify.h" |
35 | | #include "libcreg_libfcache.h" |
36 | | #include "libcreg_libfdata.h" |
37 | | #include "libcreg_unused.h" |
38 | | |
39 | | #include "creg_file_header.h" |
40 | | #include "creg_key_navigation.h" |
41 | | |
42 | | const char *creg_key_navigation_signature = "RGKN"; |
43 | | |
44 | | /* Creates a key navigation |
45 | | * Make sure the value key_navigation is referencing, is set to NULL |
46 | | * Returns 1 if successful or -1 on error |
47 | | */ |
48 | | int libcreg_key_navigation_initialize( |
49 | | libcreg_key_navigation_t **key_navigation, |
50 | | libcreg_io_handle_t *io_handle, |
51 | | libcerror_error_t **error ) |
52 | 2.62k | { |
53 | 2.62k | static char *function = "libcreg_key_navigation_initialize"; |
54 | | |
55 | 2.62k | if( key_navigation == NULL ) |
56 | 0 | { |
57 | 0 | libcerror_error_set( |
58 | 0 | error, |
59 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
60 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
61 | 0 | "%s: invalid key navigation.", |
62 | 0 | function ); |
63 | |
|
64 | 0 | return( -1 ); |
65 | 0 | } |
66 | 2.62k | if( *key_navigation != NULL ) |
67 | 0 | { |
68 | 0 | libcerror_error_set( |
69 | 0 | error, |
70 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
71 | 0 | LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET, |
72 | 0 | "%s: invalid key navigation value already set.", |
73 | 0 | function ); |
74 | |
|
75 | 0 | return( -1 ); |
76 | 0 | } |
77 | 2.62k | *key_navigation = memory_allocate_structure( |
78 | 2.62k | libcreg_key_navigation_t ); |
79 | | |
80 | 2.62k | if( *key_navigation == NULL ) |
81 | 0 | { |
82 | 0 | libcerror_error_set( |
83 | 0 | error, |
84 | 0 | LIBCERROR_ERROR_DOMAIN_MEMORY, |
85 | 0 | LIBCERROR_MEMORY_ERROR_INSUFFICIENT, |
86 | 0 | "%s: unable to create key navigation.", |
87 | 0 | function ); |
88 | |
|
89 | 0 | goto on_error; |
90 | 0 | } |
91 | 2.62k | if( memory_set( |
92 | 2.62k | *key_navigation, |
93 | 2.62k | 0, |
94 | 2.62k | sizeof( libcreg_key_navigation_t ) ) == NULL ) |
95 | 0 | { |
96 | 0 | libcerror_error_set( |
97 | 0 | error, |
98 | 0 | LIBCERROR_ERROR_DOMAIN_MEMORY, |
99 | 0 | LIBCERROR_MEMORY_ERROR_SET_FAILED, |
100 | 0 | "%s: unable to clear key navigation.", |
101 | 0 | function ); |
102 | |
|
103 | 0 | goto on_error; |
104 | 0 | } |
105 | 2.62k | ( *key_navigation )->io_handle = io_handle; |
106 | | |
107 | 2.62k | return( 1 ); |
108 | | |
109 | 0 | on_error: |
110 | 0 | if( *key_navigation != NULL ) |
111 | 0 | { |
112 | 0 | memory_free( |
113 | 0 | *key_navigation ); |
114 | |
|
115 | 0 | *key_navigation = NULL; |
116 | 0 | } |
117 | 0 | return( -1 ); |
118 | 2.62k | } |
119 | | |
120 | | /* Frees a key navigation |
121 | | * Returns 1 if successful or -1 on error |
122 | | */ |
123 | | int libcreg_key_navigation_free( |
124 | | libcreg_key_navigation_t **key_navigation, |
125 | | libcerror_error_t **error ) |
126 | 2.62k | { |
127 | 2.62k | static char *function = "libcreg_key_navigation_free"; |
128 | 2.62k | int result = 1; |
129 | | |
130 | 2.62k | if( key_navigation == NULL ) |
131 | 0 | { |
132 | 0 | libcerror_error_set( |
133 | 0 | error, |
134 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
135 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
136 | 0 | "%s: invalid key navigation.", |
137 | 0 | function ); |
138 | |
|
139 | 0 | return( -1 ); |
140 | 0 | } |
141 | 2.62k | if( *key_navigation != NULL ) |
142 | 2.62k | { |
143 | | /* The io_handle reference is freed elsewhere |
144 | | */ |
145 | 2.62k | if( ( *key_navigation )->key_hierarchy_area != NULL ) |
146 | 2.04k | { |
147 | 2.04k | if( libfdata_area_free( |
148 | 2.04k | &( ( *key_navigation )->key_hierarchy_area ), |
149 | 2.04k | error ) != 1 ) |
150 | 0 | { |
151 | 0 | libcerror_error_set( |
152 | 0 | error, |
153 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
154 | 0 | LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED, |
155 | 0 | "%s: unable to free key hierarchy area.", |
156 | 0 | function ); |
157 | |
|
158 | 0 | result = -1; |
159 | 0 | } |
160 | 2.04k | } |
161 | 2.62k | if( ( *key_navigation )->key_hierarchy_cache != NULL ) |
162 | 2.04k | { |
163 | 2.04k | if( libfcache_cache_free( |
164 | 2.04k | &( ( *key_navigation )->key_hierarchy_cache ), |
165 | 2.04k | error ) != 1 ) |
166 | 0 | { |
167 | 0 | libcerror_error_set( |
168 | 0 | error, |
169 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
170 | 0 | LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED, |
171 | 0 | "%s: unable to free key hierarchy cache.", |
172 | 0 | function ); |
173 | |
|
174 | 0 | result = -1; |
175 | 0 | } |
176 | 2.04k | } |
177 | 2.62k | if( ( *key_navigation )->data_blocks_list != NULL ) |
178 | 2.26k | { |
179 | 2.26k | if( libfdata_list_free( |
180 | 2.26k | &( ( *key_navigation )->data_blocks_list ), |
181 | 2.26k | error ) != 1 ) |
182 | 0 | { |
183 | 0 | libcerror_error_set( |
184 | 0 | error, |
185 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
186 | 0 | LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED, |
187 | 0 | "%s: unable to free data blocks list.", |
188 | 0 | function ); |
189 | |
|
190 | 0 | result = -1; |
191 | 0 | } |
192 | 2.26k | } |
193 | 2.62k | if( ( *key_navigation )->data_blocks_cache != NULL ) |
194 | 2.26k | { |
195 | 2.26k | if( libfcache_cache_free( |
196 | 2.26k | &( ( *key_navigation )->data_blocks_cache ), |
197 | 2.26k | error ) != 1 ) |
198 | 0 | { |
199 | 0 | libcerror_error_set( |
200 | 0 | error, |
201 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
202 | 0 | LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED, |
203 | 0 | "%s: unable to free data blocks cache.", |
204 | 0 | function ); |
205 | |
|
206 | 0 | result = -1; |
207 | 0 | } |
208 | 2.26k | } |
209 | 2.62k | memory_free( |
210 | 2.62k | *key_navigation ); |
211 | | |
212 | 2.62k | *key_navigation = NULL; |
213 | 2.62k | } |
214 | 2.62k | return( result ); |
215 | 2.62k | } |
216 | | |
217 | | /* Reads a key navigation record |
218 | | * Returns 1 if successful, 0 if no key navigation signature was found or -1 on error |
219 | | */ |
220 | | int libcreg_key_navigation_read_file_io_handle( |
221 | | libcreg_key_navigation_t *key_navigation, |
222 | | libbfio_handle_t *file_io_handle, |
223 | | libcerror_error_t **error ) |
224 | 2.62k | { |
225 | 2.62k | creg_key_navigation_header_t key_navigation_header; |
226 | | |
227 | 2.62k | static char *function = "libcreg_key_navigation_read_file_io_handle"; |
228 | 2.62k | ssize_t read_count = 0; |
229 | 2.62k | uint32_t data_size = 0; |
230 | 2.62k | uint32_t key_hierarchy_entries_data_offset = 0; |
231 | 2.62k | int entry_index = 0; |
232 | | |
233 | | #if defined( HAVE_DEBUG_OUTPUT ) |
234 | | uint32_t value_32bit = 0; |
235 | | #endif |
236 | | |
237 | 2.62k | if( key_navigation == NULL ) |
238 | 0 | { |
239 | 0 | libcerror_error_set( |
240 | 0 | error, |
241 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
242 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
243 | 0 | "%s: invalid key navigation.", |
244 | 0 | function ); |
245 | |
|
246 | 0 | return( -1 ); |
247 | 0 | } |
248 | 2.62k | if( key_navigation->key_hierarchy_area != NULL ) |
249 | 0 | { |
250 | 0 | libcerror_error_set( |
251 | 0 | error, |
252 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
253 | 0 | LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET, |
254 | 0 | "%s: invalid key navigation - key hierarchy area already set.", |
255 | 0 | function ); |
256 | |
|
257 | 0 | return( -1 ); |
258 | 0 | } |
259 | 2.62k | if( key_navigation->key_hierarchy_cache != NULL ) |
260 | 0 | { |
261 | 0 | libcerror_error_set( |
262 | 0 | error, |
263 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
264 | 0 | LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET, |
265 | 0 | "%s: invalid key navigation - key hierarchy cache already set.", |
266 | 0 | function ); |
267 | |
|
268 | 0 | return( -1 ); |
269 | 0 | } |
270 | | #if defined( HAVE_DEBUG_OUTPUT ) |
271 | | if( libcnotify_verbose != 0 ) |
272 | | { |
273 | | libcnotify_printf( |
274 | | "%s: reading key navigation at offset: %" PRIzd " (0x%08" PRIzx ")\n", |
275 | | function, |
276 | | sizeof( creg_file_header_t ), |
277 | | sizeof( creg_file_header_t ) ); |
278 | | } |
279 | | #endif |
280 | 2.62k | read_count = libbfio_handle_read_buffer( |
281 | 2.62k | file_io_handle, |
282 | 2.62k | (uint8_t *) &key_navigation_header, |
283 | 2.62k | sizeof( creg_key_navigation_header_t ), |
284 | 2.62k | error ); |
285 | | |
286 | 2.62k | if( read_count != (ssize_t) sizeof( creg_key_navigation_header_t ) ) |
287 | 29 | { |
288 | 29 | libcerror_error_set( |
289 | 29 | error, |
290 | 29 | LIBCERROR_ERROR_DOMAIN_IO, |
291 | 29 | LIBCERROR_IO_ERROR_READ_FAILED, |
292 | 29 | "%s: unable to read key navigation header data.", |
293 | 29 | function ); |
294 | | |
295 | 29 | goto on_error; |
296 | 29 | } |
297 | | #if defined( HAVE_DEBUG_OUTPUT ) |
298 | | if( libcnotify_verbose != 0 ) |
299 | | { |
300 | | libcnotify_printf( |
301 | | "%s: key navigation header:\n", |
302 | | function ); |
303 | | libcnotify_print_data( |
304 | | (uint8_t *) &key_navigation_header, |
305 | | sizeof( creg_key_navigation_header_t ), |
306 | | 0 ); |
307 | | } |
308 | | #endif |
309 | 2.59k | if( memory_compare( |
310 | 2.59k | key_navigation_header.signature, |
311 | 2.59k | creg_key_navigation_signature, |
312 | 2.59k | 4 ) != 0 ) |
313 | 535 | { |
314 | 535 | return( 0 ); |
315 | 535 | } |
316 | 2.06k | byte_stream_copy_to_uint32_little_endian( |
317 | 2.06k | key_navigation_header.size, |
318 | 2.06k | data_size ); |
319 | | |
320 | 2.06k | byte_stream_copy_to_uint32_little_endian( |
321 | 2.06k | key_navigation_header.key_hierarchy_entries_data_offset, |
322 | 2.06k | key_hierarchy_entries_data_offset ); |
323 | | |
324 | | #if defined( HAVE_DEBUG_OUTPUT ) |
325 | | if( libcnotify_verbose != 0 ) |
326 | | { |
327 | | libcnotify_printf( |
328 | | "%s: signature\t\t\t\t: %c%c%c%c\n", |
329 | | function, |
330 | | key_navigation_header.signature[ 0 ], |
331 | | key_navigation_header.signature[ 1 ], |
332 | | key_navigation_header.signature[ 2 ], |
333 | | key_navigation_header.signature[ 3 ] ); |
334 | | |
335 | | libcnotify_printf( |
336 | | "%s: size\t\t\t\t: %" PRIu32 "\n", |
337 | | function, |
338 | | data_size ); |
339 | | |
340 | | libcnotify_printf( |
341 | | "%s: key hierarchy entries data offset\t: 0x%08" PRIx32 "\n", |
342 | | function, |
343 | | key_hierarchy_entries_data_offset ); |
344 | | |
345 | | byte_stream_copy_to_uint32_little_endian( |
346 | | key_navigation_header.unknown2, |
347 | | value_32bit ); |
348 | | libcnotify_printf( |
349 | | "%s: unknown2\t\t\t\t: 0x%08" PRIx32 "\n", |
350 | | function, |
351 | | value_32bit ); |
352 | | |
353 | | byte_stream_copy_to_uint32_little_endian( |
354 | | key_navigation_header.unknown3, |
355 | | value_32bit ); |
356 | | libcnotify_printf( |
357 | | "%s: unknown3\t\t\t\t: 0x%08" PRIx32 "\n", |
358 | | function, |
359 | | value_32bit ); |
360 | | |
361 | | byte_stream_copy_to_uint32_little_endian( |
362 | | key_navigation_header.unknown4, |
363 | | value_32bit ); |
364 | | libcnotify_printf( |
365 | | "%s: unknown4\t\t\t\t: 0x%08" PRIx32 "\n", |
366 | | function, |
367 | | value_32bit ); |
368 | | |
369 | | libcnotify_printf( |
370 | | "%s: unknown5:\n", |
371 | | function ); |
372 | | libcnotify_print_data( |
373 | | key_navigation_header.unknown5, |
374 | | 8, |
375 | | 0 ); |
376 | | } |
377 | | #endif /* defined( HAVE_DEBUG_OUTPUT ) */ |
378 | | |
379 | 2.06k | if( data_size < sizeof( creg_key_navigation_header_t ) ) |
380 | 16 | { |
381 | 16 | libcerror_error_set( |
382 | 16 | error, |
383 | 16 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
384 | 16 | LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS, |
385 | 16 | "%s: invalid data size value out of bounds.", |
386 | 16 | function ); |
387 | | |
388 | 16 | goto on_error; |
389 | 16 | } |
390 | | #if SIZEOF_SIZE_T <= 4 |
391 | | if( data_size > (size_t) SSIZE_MAX ) |
392 | | #else |
393 | 2.04k | if( data_size > (uint32_t) SSIZE_MAX ) |
394 | 0 | #endif |
395 | 0 | { |
396 | 0 | libcerror_error_set( |
397 | 0 | error, |
398 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
399 | 0 | LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM, |
400 | 0 | "%s: invalid data size value exceeds maximum.", |
401 | 0 | function ); |
402 | |
|
403 | 0 | goto on_error; |
404 | 0 | } |
405 | 2.04k | data_size -= sizeof( creg_key_navigation_header_t ); |
406 | | |
407 | | /* TODO clone function ? */ |
408 | 2.04k | if( libfdata_area_initialize( |
409 | 2.04k | &( key_navigation->key_hierarchy_area ), |
410 | 2.04k | (size64_t) sizeof( creg_key_hierarchy_entry_t ), |
411 | 2.04k | NULL, |
412 | 2.04k | NULL, |
413 | 2.04k | NULL, |
414 | 2.04k | (int (*)(intptr_t *, intptr_t *, libfdata_area_t *, libfdata_cache_t *, off64_t, int, off64_t, size64_t, uint32_t, uint8_t, libcerror_error_t **)) &libcreg_io_handle_read_key_hierarchy_entry, |
415 | 2.04k | NULL, |
416 | 2.04k | LIBFDATA_DATA_HANDLE_FLAG_NON_MANAGED, |
417 | 2.04k | error ) != 1 ) |
418 | 0 | { |
419 | 0 | libcerror_error_set( |
420 | 0 | error, |
421 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
422 | 0 | LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, |
423 | 0 | "%s: unable to create key hierarchy area.", |
424 | 0 | function ); |
425 | |
|
426 | 0 | goto on_error; |
427 | 0 | } |
428 | 2.04k | if( libfdata_area_append_segment( |
429 | 2.04k | key_navigation->key_hierarchy_area, |
430 | 2.04k | &entry_index, |
431 | 2.04k | 0, |
432 | 2.04k | (off64_t) key_hierarchy_entries_data_offset, |
433 | 2.04k | (size64_t) data_size, |
434 | 2.04k | 0, |
435 | 2.04k | error ) != 1 ) |
436 | 0 | { |
437 | 0 | libcerror_error_set( |
438 | 0 | error, |
439 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
440 | 0 | LIBCERROR_RUNTIME_ERROR_APPEND_FAILED, |
441 | 0 | "%s: unable to append segment to key hierarchy area.", |
442 | 0 | function ); |
443 | |
|
444 | 0 | goto on_error; |
445 | 0 | } |
446 | 2.04k | if( libfcache_cache_initialize( |
447 | 2.04k | &( key_navigation->key_hierarchy_cache ), |
448 | 2.04k | LIBCREG_MAXIMUM_CACHE_ENTRIES_KEYS, |
449 | 2.04k | error ) != 1 ) |
450 | 0 | { |
451 | 0 | libcerror_error_set( |
452 | 0 | error, |
453 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
454 | 0 | LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, |
455 | 0 | "%s: unable to create key hierarchy cache.", |
456 | 0 | function ); |
457 | |
|
458 | 0 | goto on_error; |
459 | 0 | } |
460 | 2.04k | return( 1 ); |
461 | | |
462 | 45 | on_error: |
463 | 45 | if( key_navigation->key_hierarchy_cache != NULL ) |
464 | 0 | { |
465 | 0 | libfcache_cache_free( |
466 | 0 | &( key_navigation->key_hierarchy_cache ), |
467 | 0 | NULL ); |
468 | 0 | } |
469 | 45 | if( key_navigation->key_hierarchy_area != NULL ) |
470 | 0 | { |
471 | 0 | libfdata_area_free( |
472 | 0 | &( key_navigation->key_hierarchy_area ), |
473 | 0 | NULL ); |
474 | 0 | } |
475 | 45 | return( -1 ); |
476 | 2.04k | } |
477 | | |
478 | | /* Reads the data block |
479 | | * Returns 1 if successful, 0 if no data block signature was found or -1 on error |
480 | | */ |
481 | | int libcreg_key_navigation_read_data_blocks( |
482 | | libcreg_key_navigation_t *key_navigation, |
483 | | libbfio_handle_t *file_io_handle, |
484 | | off64_t file_offset, |
485 | | size64_t file_size, |
486 | | libcerror_error_t **error ) |
487 | 2.58k | { |
488 | 2.58k | libcreg_data_block_t *data_block = NULL; |
489 | 2.58k | static char *function = "libcreg_key_navigation_read_data_blocks"; |
490 | 2.58k | int data_block_index = 0; |
491 | 2.58k | int result = 0; |
492 | | |
493 | 2.58k | if( key_navigation == NULL ) |
494 | 0 | { |
495 | 0 | libcerror_error_set( |
496 | 0 | error, |
497 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
498 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
499 | 0 | "%s: invalid key navigation.", |
500 | 0 | function ); |
501 | |
|
502 | 0 | return( -1 ); |
503 | 0 | } |
504 | 2.58k | if( key_navigation->data_blocks_list != NULL ) |
505 | 0 | { |
506 | 0 | libcerror_error_set( |
507 | 0 | error, |
508 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
509 | 0 | LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET, |
510 | 0 | "%s: invalid key navigation - data blocks list already set.", |
511 | 0 | function ); |
512 | |
|
513 | 0 | return( -1 ); |
514 | 0 | } |
515 | 2.58k | if( key_navigation->data_blocks_cache != NULL ) |
516 | 0 | { |
517 | 0 | libcerror_error_set( |
518 | 0 | error, |
519 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
520 | 0 | LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET, |
521 | 0 | "%s: invalid key navigation - data blocks list already set.", |
522 | 0 | function ); |
523 | |
|
524 | 0 | return( -1 ); |
525 | 0 | } |
526 | 2.58k | if( key_navigation->io_handle == NULL ) |
527 | 0 | { |
528 | 0 | libcerror_error_set( |
529 | 0 | error, |
530 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
531 | 0 | LIBCERROR_RUNTIME_ERROR_VALUE_MISSING, |
532 | 0 | "%s: invalid key navigation - missing IO handle.", |
533 | 0 | function ); |
534 | |
|
535 | 0 | return( -1 ); |
536 | 0 | } |
537 | 2.58k | if( file_offset < 0 ) |
538 | 0 | { |
539 | 0 | libcerror_error_set( |
540 | 0 | error, |
541 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
542 | 0 | LIBCERROR_ARGUMENT_ERROR_VALUE_LESS_THAN_ZERO, |
543 | 0 | "%s: invalid file offset value less than zero.", |
544 | 0 | function ); |
545 | |
|
546 | 0 | return( -1 ); |
547 | 0 | } |
548 | 2.58k | if( libfdata_list_initialize( |
549 | 2.58k | &( key_navigation->data_blocks_list ), |
550 | 2.58k | (intptr_t *) key_navigation->io_handle, |
551 | 2.58k | NULL, |
552 | 2.58k | NULL, |
553 | 2.58k | (int (*)(intptr_t *, intptr_t *, libfdata_list_element_t *, libfdata_cache_t *, int, off64_t, size64_t, uint32_t, uint8_t, libcerror_error_t **)) &libcreg_key_navigation_read_data_block_element_data, |
554 | 2.58k | NULL, |
555 | 2.58k | 0, |
556 | 2.58k | error ) != 1 ) |
557 | 0 | { |
558 | 0 | libcerror_error_set( |
559 | 0 | error, |
560 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
561 | 0 | LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, |
562 | 0 | "%s: unable to create data blocks list.", |
563 | 0 | function ); |
564 | |
|
565 | 0 | goto on_error; |
566 | 0 | } |
567 | 2.67M | while( (size64_t) file_offset < file_size ) |
568 | 2.67M | { |
569 | 2.67M | if( libcreg_data_block_initialize( |
570 | 2.67M | &data_block, |
571 | 2.67M | error ) != 1 ) |
572 | 0 | { |
573 | 0 | libcerror_error_set( |
574 | 0 | error, |
575 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
576 | 0 | LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, |
577 | 0 | "%s: unable to create data block.", |
578 | 0 | function ); |
579 | |
|
580 | 0 | goto on_error; |
581 | 0 | } |
582 | | #if defined( HAVE_DEBUG_OUTPUT ) |
583 | | if( libcnotify_verbose != 0 ) |
584 | | { |
585 | | libcnotify_printf( |
586 | | "%s: reading data block: %d at offset: %" PRIi64 " (0x%08" PRIx64 ")\n", |
587 | | function, |
588 | | data_block_index, |
589 | | file_offset, |
590 | | file_offset ); |
591 | | } |
592 | | #endif |
593 | 2.67M | result = libcreg_data_block_read_header( |
594 | 2.67M | data_block, |
595 | 2.67M | file_io_handle, |
596 | 2.67M | file_offset, |
597 | 2.67M | error ); |
598 | | |
599 | 2.67M | if( result == -1 ) |
600 | 241 | { |
601 | 241 | libcerror_error_set( |
602 | 241 | error, |
603 | 241 | LIBCERROR_ERROR_DOMAIN_IO, |
604 | 241 | LIBCERROR_IO_ERROR_READ_FAILED, |
605 | 241 | "%s: unable to read data block header.", |
606 | 241 | function ); |
607 | | |
608 | 241 | goto on_error; |
609 | 241 | } |
610 | 2.67M | else if( result == 0 ) |
611 | 226 | { |
612 | | /* TODO mark file as corrupted */ |
613 | 226 | if( data_block_index != 0 ) |
614 | 71 | { |
615 | 71 | libcerror_error_set( |
616 | 71 | error, |
617 | 71 | LIBCERROR_ERROR_DOMAIN_IO, |
618 | 71 | LIBCERROR_IO_ERROR_READ_FAILED, |
619 | 71 | "%s: missing data block at offset: %" PRIi64 ".", |
620 | 71 | function, |
621 | 71 | file_offset ); |
622 | | |
623 | 71 | goto on_error; |
624 | 71 | } |
625 | 226 | } |
626 | 2.67M | else |
627 | 2.67M | { |
628 | 2.67M | if( data_block->size == 0 ) |
629 | 3 | { |
630 | 3 | libcerror_error_set( |
631 | 3 | error, |
632 | 3 | LIBCERROR_ERROR_DOMAIN_IO, |
633 | 3 | LIBCERROR_IO_ERROR_READ_FAILED, |
634 | 3 | "%s: invalid data block: %d size.", |
635 | 3 | function, |
636 | 3 | data_block_index ); |
637 | | |
638 | 3 | goto on_error; |
639 | 3 | } |
640 | 2.67M | if( libfdata_list_append_element( |
641 | 2.67M | key_navigation->data_blocks_list, |
642 | 2.67M | &data_block_index, |
643 | 2.67M | 0, |
644 | 2.67M | (off64_t) data_block->offset, |
645 | 2.67M | (size64_t) data_block->size, |
646 | 2.67M | 0, |
647 | 2.67M | error ) != 1 ) |
648 | 0 | { |
649 | 0 | libcerror_error_set( |
650 | 0 | error, |
651 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
652 | 0 | LIBCERROR_RUNTIME_ERROR_APPEND_FAILED, |
653 | 0 | "%s: unable to append data block: %d to data list.", |
654 | 0 | function, |
655 | 0 | data_block_index ); |
656 | |
|
657 | 0 | goto on_error; |
658 | 0 | } |
659 | 2.67M | file_offset += data_block->size; |
660 | 2.67M | } |
661 | 2.67M | if( libcreg_data_block_free( |
662 | 2.67M | &data_block, |
663 | 2.67M | error ) != 1 ) |
664 | 0 | { |
665 | 0 | libcerror_error_set( |
666 | 0 | error, |
667 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
668 | 0 | LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED, |
669 | 0 | "%s: unable to free data block.", |
670 | 0 | function ); |
671 | |
|
672 | 0 | goto on_error; |
673 | 0 | } |
674 | 2.67M | if( result == 0 ) |
675 | 155 | { |
676 | 155 | break; |
677 | 155 | } |
678 | 2.67M | data_block_index++; |
679 | 2.67M | } |
680 | 2.26k | if( libfcache_cache_initialize( |
681 | 2.26k | &( key_navigation->data_blocks_cache ), |
682 | 2.26k | LIBCREG_MAXIMUM_CACHE_ENTRIES_DATA_BLOCKS, |
683 | 2.26k | error ) != 1 ) |
684 | 0 | { |
685 | 0 | libcerror_error_set( |
686 | 0 | error, |
687 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
688 | 0 | LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, |
689 | 0 | "%s: unable to create data blocks cache.", |
690 | 0 | function ); |
691 | |
|
692 | 0 | goto on_error; |
693 | 0 | } |
694 | 2.26k | if( ( data_block_index == 0 ) |
695 | 2.26k | && ( result == 0 ) ) |
696 | 1.06k | { |
697 | 1.06k | return( 0 ); |
698 | 1.06k | } |
699 | 1.20k | return( 1 ); |
700 | | |
701 | 315 | on_error: |
702 | 315 | if( data_block != NULL ) |
703 | 315 | { |
704 | 315 | libcreg_data_block_free( |
705 | 315 | &data_block, |
706 | 315 | NULL ); |
707 | 315 | } |
708 | 315 | if( key_navigation->data_blocks_list != NULL ) |
709 | 315 | { |
710 | 315 | libfdata_list_free( |
711 | 315 | &( key_navigation->data_blocks_list ), |
712 | 315 | NULL ); |
713 | 315 | } |
714 | 315 | return( -1 ); |
715 | 2.26k | } |
716 | | |
717 | | /* Retrieves the key hierarchy entry at a specific offset |
718 | | * Returns 1 if successful or -1 on error |
719 | | */ |
720 | | int libcreg_key_navigation_get_key_hierarchy_entry_at_offset( |
721 | | libcreg_key_navigation_t *key_navigation, |
722 | | libbfio_handle_t *file_io_handle, |
723 | | off64_t key_hierarchy_entry_offset, |
724 | | libcreg_key_hierarchy_entry_t **key_hierarchy_entry, |
725 | | libcerror_error_t **error ) |
726 | 22.5k | { |
727 | 22.5k | static char *function = "libcreg_key_navigation_get_key_hierarchy_entry_at_offset"; |
728 | | |
729 | 22.5k | if( key_navigation == NULL ) |
730 | 0 | { |
731 | 0 | libcerror_error_set( |
732 | 0 | error, |
733 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
734 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
735 | 0 | "%s: invalid key navigation.", |
736 | 0 | function ); |
737 | |
|
738 | 0 | return( -1 ); |
739 | 0 | } |
740 | 22.5k | if( libfdata_area_get_element_value_at_offset( |
741 | 22.5k | key_navigation->key_hierarchy_area, |
742 | 22.5k | (intptr_t *) file_io_handle, |
743 | 22.5k | (libfdata_cache_t *) key_navigation->key_hierarchy_cache, |
744 | 22.5k | key_hierarchy_entry_offset, |
745 | 22.5k | (intptr_t **) key_hierarchy_entry, |
746 | 22.5k | 0, |
747 | 22.5k | error ) != 1 ) |
748 | 596 | { |
749 | 596 | libcerror_error_set( |
750 | 596 | error, |
751 | 596 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
752 | 596 | LIBCERROR_RUNTIME_ERROR_GET_FAILED, |
753 | 596 | "%s: unable to retrieve key hierarchy entry at offset: 0x%08" PRIx64 ".", |
754 | 596 | function, |
755 | 596 | key_hierarchy_entry_offset ); |
756 | | |
757 | 596 | return( -1 ); |
758 | 596 | } |
759 | 21.9k | return( 1 ); |
760 | 22.5k | } |
761 | | |
762 | | /* Retrieves the number of data blocks |
763 | | * Returns 1 if successful or -1 on error |
764 | | */ |
765 | | int libcreg_key_navigation_get_number_of_data_blocks( |
766 | | libcreg_key_navigation_t *key_navigation, |
767 | | int *number_of_data_blocks, |
768 | | libcerror_error_t **error ) |
769 | 1.20k | { |
770 | 1.20k | static char *function = "libcreg_key_navigation_get_number_of_data_blocks"; |
771 | | |
772 | 1.20k | if( key_navigation == NULL ) |
773 | 0 | { |
774 | 0 | libcerror_error_set( |
775 | 0 | error, |
776 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
777 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
778 | 0 | "%s: invalid key navigation.", |
779 | 0 | function ); |
780 | |
|
781 | 0 | return( -1 ); |
782 | 0 | } |
783 | 1.20k | if( libfdata_list_get_number_of_elements( |
784 | 1.20k | key_navigation->data_blocks_list, |
785 | 1.20k | number_of_data_blocks, |
786 | 1.20k | error ) != 1 ) |
787 | 0 | { |
788 | 0 | libcerror_error_set( |
789 | 0 | error, |
790 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
791 | 0 | LIBCERROR_RUNTIME_ERROR_GET_FAILED, |
792 | 0 | "%s: unable to retrieve number of data blocks list elements.", |
793 | 0 | function ); |
794 | |
|
795 | 0 | return( -1 ); |
796 | 0 | } |
797 | 1.20k | return( 1 ); |
798 | 1.20k | } |
799 | | |
800 | | /* Retrieves a specific data block |
801 | | * Returns 1 if successful or -1 on error |
802 | | */ |
803 | | int libcreg_key_navigation_get_data_block_at_index( |
804 | | libcreg_key_navigation_t *key_navigation, |
805 | | libbfio_handle_t *file_io_handle, |
806 | | int data_block_index, |
807 | | libcreg_data_block_t **data_block, |
808 | | libcerror_error_t **error ) |
809 | 1.04k | { |
810 | 1.04k | static char *function = "libcreg_key_navigation_get_data_block_at_index"; |
811 | | |
812 | 1.04k | if( key_navigation == NULL ) |
813 | 0 | { |
814 | 0 | libcerror_error_set( |
815 | 0 | error, |
816 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
817 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
818 | 0 | "%s: invalid key navigation.", |
819 | 0 | function ); |
820 | |
|
821 | 0 | return( -1 ); |
822 | 0 | } |
823 | 1.04k | if( libfdata_list_get_element_value_by_index( |
824 | 1.04k | key_navigation->data_blocks_list, |
825 | 1.04k | (intptr_t *) file_io_handle, |
826 | 1.04k | (libfdata_cache_t *) key_navigation->data_blocks_cache, |
827 | 1.04k | data_block_index, |
828 | 1.04k | (intptr_t **) data_block, |
829 | 1.04k | 0, |
830 | 1.04k | error ) != 1 ) |
831 | 907 | { |
832 | 907 | libcerror_error_set( |
833 | 907 | error, |
834 | 907 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
835 | 907 | LIBCERROR_RUNTIME_ERROR_GET_FAILED, |
836 | 907 | "%s: unable to retrieve data block: %d.", |
837 | 907 | function, |
838 | 907 | data_block_index ); |
839 | | |
840 | 907 | return( -1 ); |
841 | 907 | } |
842 | 139 | return( 1 ); |
843 | 1.04k | } |
844 | | |
845 | | /* Reads a data block |
846 | | * Callback function for the data blocks list |
847 | | * Returns 1 if successful or -1 on error |
848 | | */ |
849 | | int libcreg_key_navigation_read_data_block_element_data( |
850 | | libcreg_io_handle_t *io_handle, |
851 | | libbfio_handle_t *file_io_handle, |
852 | | libfdata_list_element_t *list_element, |
853 | | libfdata_cache_t *cache, |
854 | | int data_range_file_index LIBCREG_ATTRIBUTE_UNUSED, |
855 | | off64_t data_range_offset, |
856 | | size64_t data_range_size, |
857 | | uint32_t data_range_flags LIBCREG_ATTRIBUTE_UNUSED, |
858 | | uint8_t read_flags LIBCREG_ATTRIBUTE_UNUSED, |
859 | | libcerror_error_t **error ) |
860 | 973 | { |
861 | 973 | libcreg_data_block_t *data_block = NULL; |
862 | 973 | static char *function = "libcreg_key_navigation_read_data_block_element_data"; |
863 | | |
864 | 973 | LIBCREG_UNREFERENCED_PARAMETER( data_range_file_index ) |
865 | 973 | LIBCREG_UNREFERENCED_PARAMETER( data_range_flags ) |
866 | 973 | LIBCREG_UNREFERENCED_PARAMETER( read_flags ) |
867 | | |
868 | 973 | if( io_handle == NULL ) |
869 | 0 | { |
870 | 0 | libcerror_error_set( |
871 | 0 | error, |
872 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
873 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
874 | 0 | "%s: invalid IO handle.", |
875 | 0 | function ); |
876 | |
|
877 | 0 | return( -1 ); |
878 | 0 | } |
879 | 973 | if( libcreg_data_block_initialize( |
880 | 973 | &data_block, |
881 | 973 | error ) != 1 ) |
882 | 0 | { |
883 | 0 | libcerror_error_set( |
884 | 0 | error, |
885 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
886 | 0 | LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, |
887 | 0 | "%s: unable to create data block.", |
888 | 0 | function ); |
889 | |
|
890 | 0 | goto on_error; |
891 | 0 | } |
892 | | #if defined( HAVE_DEBUG_OUTPUT ) |
893 | | if( libcnotify_verbose != 0 ) |
894 | | { |
895 | | libcnotify_printf( |
896 | | "%s: reading data block at offset: %" PRIi64 " (0x%08" PRIx64 ")\n", |
897 | | function, |
898 | | data_range_offset, |
899 | | data_range_offset ); |
900 | | } |
901 | | #endif |
902 | 973 | if( libcreg_data_block_read_header( |
903 | 973 | data_block, |
904 | 973 | file_io_handle, |
905 | 973 | data_range_offset, |
906 | 973 | error ) != 1 ) |
907 | 0 | { |
908 | 0 | libcerror_error_set( |
909 | 0 | error, |
910 | 0 | LIBCERROR_ERROR_DOMAIN_IO, |
911 | 0 | LIBCERROR_IO_ERROR_READ_FAILED, |
912 | 0 | "%s: unable to read data block header.", |
913 | 0 | function ); |
914 | |
|
915 | 0 | goto on_error; |
916 | 0 | } |
917 | 973 | if( (size64_t) data_block->size != data_range_size ) |
918 | 0 | { |
919 | 0 | libcerror_error_set( |
920 | 0 | error, |
921 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
922 | 0 | LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE, |
923 | 0 | "%s: mismatch in data block size (stored: %" PRIu32 " != calculated: %" PRIu64 ").", |
924 | 0 | function, |
925 | 0 | data_block->size, |
926 | 0 | data_range_size ); |
927 | |
|
928 | 0 | goto on_error; |
929 | 0 | } |
930 | 973 | if( libcreg_data_block_read_entries( |
931 | 973 | data_block, |
932 | 973 | file_io_handle, |
933 | 973 | io_handle->ascii_codepage, |
934 | 973 | error ) != 1 ) |
935 | 852 | { |
936 | 852 | libcerror_error_set( |
937 | 852 | error, |
938 | 852 | LIBCERROR_ERROR_DOMAIN_IO, |
939 | 852 | LIBCERROR_IO_ERROR_READ_FAILED, |
940 | 852 | "%s: unable to read key name entries.", |
941 | 852 | function ); |
942 | | |
943 | 852 | goto on_error; |
944 | 852 | } |
945 | 121 | if( libfdata_list_element_set_element_value( |
946 | 121 | list_element, |
947 | 121 | (intptr_t *) file_io_handle, |
948 | 121 | cache, |
949 | 121 | (intptr_t *) data_block, |
950 | 121 | (int (*)(intptr_t **, libcerror_error_t **)) &libcreg_data_block_free, |
951 | 121 | LIBFDATA_LIST_ELEMENT_VALUE_FLAG_MANAGED, |
952 | 121 | error ) != 1 ) |
953 | 0 | { |
954 | 0 | libcerror_error_set( |
955 | 0 | error, |
956 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
957 | 0 | LIBCERROR_RUNTIME_ERROR_SET_FAILED, |
958 | 0 | "%s: unable to set data block as list element value.", |
959 | 0 | function ); |
960 | |
|
961 | 0 | goto on_error; |
962 | 0 | } |
963 | 121 | return( 1 ); |
964 | | |
965 | 852 | on_error: |
966 | 852 | if( data_block != NULL ) |
967 | 852 | { |
968 | 852 | libcreg_data_block_free( |
969 | 852 | &data_block, |
970 | 852 | NULL ); |
971 | 852 | } |
972 | 852 | return( -1 ); |
973 | 121 | } |
974 | | |
975 | | |