1 /*
2 * Data block functions
3 *
4 * Copyright (C) 2012-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 "libmodi_compression.h"
28 #include "libmodi_data_block.h"
29 #include "libmodi_definitions.h"
30 #include "libmodi_io_handle.h"
31 #include "libmodi_libbfio.h"
32 #include "libmodi_libcerror.h"
33 #include "libmodi_libcnotify.h"
34 #include "libmodi_libfdata.h"
35 #include "libmodi_unused.h"
36
37 /* Creates a data block
38 * Make sure the value data_block is referencing, is set to NULL
39 * Returns 1 if successful or -1 on error
40 */
libmodi_data_block_initialize(libmodi_data_block_t ** data_block,size_t data_size,libcerror_error_t ** error)41 int libmodi_data_block_initialize(
42 libmodi_data_block_t **data_block,
43 size_t data_size,
44 libcerror_error_t **error )
45 {
46 static char *function = "libmodi_data_block_initialize";
47
48 if( data_block == NULL )
49 {
50 libcerror_error_set(
51 error,
52 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
53 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
54 "%s: invalid data block.",
55 function );
56
57 return( -1 );
58 }
59 if( *data_block != NULL )
60 {
61 libcerror_error_set(
62 error,
63 LIBCERROR_ERROR_DOMAIN_RUNTIME,
64 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
65 "%s: invalid data block value already set.",
66 function );
67
68 return( -1 );
69 }
70 if( ( data_size == 0 )
71 || ( data_size > (size_t) MEMORY_MAXIMUM_ALLOCATION_SIZE ) )
72 {
73 libcerror_error_set(
74 error,
75 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
76 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
77 "%s: invalid data size value out of bounds.",
78 function );
79
80 return( -1 );
81 }
82 *data_block = memory_allocate_structure(
83 libmodi_data_block_t );
84
85 if( *data_block == NULL )
86 {
87 libcerror_error_set(
88 error,
89 LIBCERROR_ERROR_DOMAIN_MEMORY,
90 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
91 "%s: unable to create data block.",
92 function );
93
94 goto on_error;
95 }
96 if( memory_set(
97 *data_block,
98 0,
99 sizeof( libmodi_data_block_t ) ) == NULL )
100 {
101 libcerror_error_set(
102 error,
103 LIBCERROR_ERROR_DOMAIN_MEMORY,
104 LIBCERROR_MEMORY_ERROR_SET_FAILED,
105 "%s: unable to clear data block.",
106 function );
107
108 memory_free(
109 *data_block );
110
111 *data_block = NULL;
112
113 return( -1 );
114 }
115 ( *data_block )->data = (uint8_t *) memory_allocate(
116 sizeof( uint8_t ) * data_size );
117
118 if( ( *data_block )->data == NULL )
119 {
120 libcerror_error_set(
121 error,
122 LIBCERROR_ERROR_DOMAIN_MEMORY,
123 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
124 "%s: unable to create data.",
125 function );
126
127 goto on_error;
128 }
129 ( *data_block )->data_size = data_size;
130
131 return( 1 );
132
133 on_error:
134 if( *data_block != NULL )
135 {
136 memory_free(
137 *data_block );
138
139 *data_block = NULL;
140 }
141 return( -1 );
142 }
143
144 /* Frees a data block
145 * Returns 1 if successful or -1 on error
146 */
libmodi_data_block_free(libmodi_data_block_t ** data_block,libcerror_error_t ** error)147 int libmodi_data_block_free(
148 libmodi_data_block_t **data_block,
149 libcerror_error_t **error )
150 {
151 static char *function = "libmodi_data_block_free";
152 int result = 1;
153
154 if( data_block == NULL )
155 {
156 libcerror_error_set(
157 error,
158 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
159 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
160 "%s: invalid data block.",
161 function );
162
163 return( -1 );
164 }
165 if( *data_block != NULL )
166 {
167 memory_free(
168 ( *data_block )->data );
169
170 memory_free(
171 *data_block );
172
173 *data_block = NULL;
174 }
175 return( result );
176 }
177
178 /* Clears a data block
179 * Returns 1 if successful or -1 on error
180 */
libmodi_data_block_clear(libmodi_data_block_t * data_block,libcerror_error_t ** error)181 int libmodi_data_block_clear(
182 libmodi_data_block_t *data_block,
183 libcerror_error_t **error )
184 {
185 static char *function = "libmodi_data_block_clear";
186
187 if( data_block == NULL )
188 {
189 libcerror_error_set(
190 error,
191 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
192 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
193 "%s: invalid data block.",
194 function );
195
196 return( -1 );
197 }
198 if( data_block->data == NULL )
199 {
200 libcerror_error_set(
201 error,
202 LIBCERROR_ERROR_DOMAIN_RUNTIME,
203 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
204 "%s: invalid data block - missing data.",
205 function );
206
207 return( -1 );
208 }
209 if( memory_set(
210 data_block->data,
211 0,
212 data_block->data_size ) == NULL )
213 {
214 libcerror_error_set(
215 error,
216 LIBCERROR_ERROR_DOMAIN_MEMORY,
217 LIBCERROR_MEMORY_ERROR_SET_FAILED,
218 "%s: unable to clear data block data.",
219 function );
220
221 return( -1 );
222 }
223 return( 1 );
224 }
225
226 /* Reads data block
227 * Returns 1 if successful or -1 on error
228 */
libmodi_data_block_read_file_io_handle(libmodi_data_block_t * data_block,libbfio_handle_t * file_io_handle,off64_t data_block_offset,libcerror_error_t ** error)229 int libmodi_data_block_read_file_io_handle(
230 libmodi_data_block_t *data_block,
231 libbfio_handle_t *file_io_handle,
232 off64_t data_block_offset,
233 libcerror_error_t **error )
234 {
235 static char *function = "libmodi_data_block_read_file_io_handle";
236 ssize_t read_count = 0;
237
238 if( data_block == NULL )
239 {
240 libcerror_error_set(
241 error,
242 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
243 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
244 "%s: invalid data block.",
245 function );
246
247 return( -1 );
248 }
249 #if defined( HAVE_DEBUG_OUTPUT )
250 if( libcnotify_verbose != 0 )
251 {
252 libcnotify_printf(
253 "%s: reading data block at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
254 function,
255 data_block_offset,
256 data_block_offset );
257 }
258 #endif
259 read_count = libbfio_handle_read_buffer_at_offset(
260 file_io_handle,
261 data_block->data,
262 data_block->data_size,
263 data_block_offset,
264 error );
265
266 if( read_count != (ssize_t) data_block->data_size )
267 {
268 libcerror_error_set(
269 error,
270 LIBCERROR_ERROR_DOMAIN_IO,
271 LIBCERROR_IO_ERROR_READ_FAILED,
272 "%s: unable to read data block at offset: %" PRIi64 " (0x%08" PRIx64 ").",
273 function,
274 data_block_offset,
275 data_block_offset );
276
277 return( -1 );
278 }
279 #if defined( HAVE_DEBUG_OUTPUT )
280 if( libcnotify_verbose != 0 )
281 {
282 libcnotify_printf(
283 "%s: data block:\n",
284 function );
285 libcnotify_print_data(
286 data_block->data,
287 data_block->data_size,
288 LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
289 }
290 #endif
291 return( 1 );
292 }
293
294 /* Reads a data block
295 * Callback function for the block chunks list
296 * Returns 1 if successful or -1 on error
297 */
libmodi_data_block_read_list_element_data(libmodi_io_handle_t * io_handle,libbfio_handle_t * file_io_handle,libfdata_list_element_t * element,libfdata_cache_t * cache,int element_data_file_index LIBMODI_ATTRIBUTE_UNUSED,off64_t element_data_offset,size64_t element_data_size,uint32_t element_data_flags,uint8_t read_flags LIBMODI_ATTRIBUTE_UNUSED,libcerror_error_t ** error)298 int libmodi_data_block_read_list_element_data(
299 libmodi_io_handle_t *io_handle,
300 libbfio_handle_t *file_io_handle,
301 libfdata_list_element_t *element,
302 libfdata_cache_t *cache,
303 int element_data_file_index LIBMODI_ATTRIBUTE_UNUSED,
304 off64_t element_data_offset,
305 size64_t element_data_size,
306 uint32_t element_data_flags,
307 uint8_t read_flags LIBMODI_ATTRIBUTE_UNUSED,
308 libcerror_error_t **error )
309 {
310 libmodi_data_block_t *data_block = NULL;
311 static char *function = "libmodi_data_block_read_list_element_data";
312 uint8_t *compressed_data = NULL;
313 size64_t mapped_size = 0;
314 size_t uncompressed_data_size = 0;
315 ssize_t read_count = 0;
316
317 LIBMODI_UNREFERENCED_PARAMETER( element_data_file_index )
318 LIBMODI_UNREFERENCED_PARAMETER( read_flags )
319
320 if( io_handle == NULL )
321 {
322 libcerror_error_set(
323 error,
324 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
325 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
326 "%s: invalid IO handle.",
327 function );
328
329 return( -1 );
330 }
331 if( ( element_data_flags & LIBFDATA_RANGE_FLAG_IS_COMPRESSED ) != 0 )
332 {
333 if( ( element_data_size == 0 )
334 || ( element_data_size > (size64_t) SSIZE_MAX ) )
335 {
336 libcerror_error_set(
337 error,
338 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
339 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
340 "%s: invalid element data size value out of bounds.",
341 function );
342
343 return( -1 );
344 }
345 }
346 if( libfdata_list_element_get_mapped_size(
347 element,
348 &mapped_size,
349 error ) != 1 )
350 {
351 libcerror_error_set(
352 error,
353 LIBCERROR_ERROR_DOMAIN_RUNTIME,
354 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
355 "%s: unable to retrieve mapped size from element.",
356 function );
357
358 goto on_error;
359 }
360 if( ( mapped_size == 0 )
361 || ( mapped_size > (size64_t) SSIZE_MAX ) )
362 {
363 libcerror_error_set(
364 error,
365 LIBCERROR_ERROR_DOMAIN_RUNTIME,
366 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
367 "%s: invalid block chunk data size value out of bounds.",
368 function );
369
370 goto on_error;
371 }
372 if( libmodi_data_block_initialize(
373 &data_block,
374 (size_t) mapped_size,
375 error ) != 1 )
376 {
377 libcerror_error_set(
378 error,
379 LIBCERROR_ERROR_DOMAIN_RUNTIME,
380 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
381 "%s: unable to create data block.",
382 function );
383
384 goto on_error;
385 }
386 if( ( element_data_flags & LIBFDATA_RANGE_FLAG_IS_SPARSE ) != 0 )
387 {
388 if( memory_set(
389 data_block->data,
390 0,
391 data_block->data_size ) == NULL )
392 {
393 libcerror_error_set(
394 error,
395 LIBCERROR_ERROR_DOMAIN_MEMORY,
396 LIBCERROR_MEMORY_ERROR_SET_FAILED,
397 "%s: unable to clear data block.",
398 function );
399
400 goto on_error;
401 }
402 }
403 else if( ( element_data_flags & LIBFDATA_RANGE_FLAG_IS_COMPRESSED ) != 0 )
404 {
405 #if defined( HAVE_DEBUG_OUTPUT )
406 if( libcnotify_verbose != 0 )
407 {
408 libcnotify_printf(
409 "%s: reading compressed block chunk at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
410 function,
411 element_data_offset,
412 element_data_offset );
413 }
414 #endif
415 compressed_data = (uint8_t *) memory_allocate(
416 sizeof( uint8_t ) * element_data_size );
417
418 if( compressed_data == NULL )
419 {
420 libcerror_error_set(
421 error,
422 LIBCERROR_ERROR_DOMAIN_MEMORY,
423 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
424 "%s: unable to create compressed data.",
425 function );
426
427 goto on_error;
428 }
429 read_count = libbfio_handle_read_buffer_at_offset(
430 file_io_handle,
431 compressed_data,
432 element_data_size,
433 element_data_offset,
434 error );
435
436 if( read_count != (ssize_t) element_data_size )
437 {
438 libcerror_error_set(
439 error,
440 LIBCERROR_ERROR_DOMAIN_IO,
441 LIBCERROR_IO_ERROR_READ_FAILED,
442 "%s: unable to read compressed block chunk at offset: %" PRIi64 " (0x%08" PRIx64 ").",
443 function,
444 element_data_offset,
445 element_data_offset );
446
447 goto on_error;
448 }
449 uncompressed_data_size = data_block->data_size;
450
451 if( libmodi_decompress_data(
452 compressed_data,
453 (size_t) read_count,
454 io_handle->compression_method,
455 data_block->data,
456 &uncompressed_data_size,
457 error ) != 1 )
458 {
459 libcerror_error_set(
460 error,
461 LIBCERROR_ERROR_DOMAIN_ENCRYPTION,
462 LIBCERROR_ENCRYPTION_ERROR_GENERIC,
463 "%s: unable to decompress block chunk at offset: %" PRIi64 " (0x%08" PRIx64 ").",
464 function,
465 element_data_offset,
466 element_data_offset );
467
468 goto on_error;
469 }
470 memory_free(
471 compressed_data );
472
473 compressed_data = NULL;
474 }
475 else
476 {
477 if( libmodi_data_block_read_file_io_handle(
478 data_block,
479 file_io_handle,
480 element_data_offset,
481 error ) != 1 )
482 {
483 libcerror_error_set(
484 error,
485 LIBCERROR_ERROR_DOMAIN_IO,
486 LIBCERROR_IO_ERROR_READ_FAILED,
487 "%s: unable to read data block at offset: %" PRIi64 " (0x%08" PRIx64 ").",
488 function,
489 element_data_offset,
490 element_data_offset );
491
492 goto on_error;
493 }
494 }
495 if( libfdata_list_element_set_element_value(
496 element,
497 (intptr_t *) file_io_handle,
498 cache,
499 (intptr_t *) data_block,
500 (int (*)(intptr_t **, libcerror_error_t **)) &libmodi_data_block_free,
501 LIBFDATA_LIST_ELEMENT_VALUE_FLAG_MANAGED,
502 error ) != 1 )
503 {
504 libcerror_error_set(
505 error,
506 LIBCERROR_ERROR_DOMAIN_RUNTIME,
507 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
508 "%s: unable to set data block as element value.",
509 function );
510
511 goto on_error;
512 }
513 return( 1 );
514
515 on_error:
516 if( compressed_data != NULL )
517 {
518 memory_free(
519 compressed_data );
520 }
521 if( data_block != NULL )
522 {
523 libmodi_data_block_free(
524 &data_block,
525 NULL );
526 }
527 return( -1 );
528 }
529
530 /* Reads a data block
531 * Callback function for the data block vector
532 * Returns 1 if successful or -1 on error
533 */
libmodi_data_block_read_vector_element_data(libmodi_io_handle_t * io_handle,intptr_t * file_io_handle,libfdata_vector_t * vector,libfdata_cache_t * cache,int element_index,int element_data_file_index,off64_t element_data_offset,size64_t element_data_size,uint32_t element_data_flags,uint8_t read_flags LIBMODI_ATTRIBUTE_UNUSED,libcerror_error_t ** error)534 int libmodi_data_block_read_vector_element_data(
535 libmodi_io_handle_t *io_handle,
536 intptr_t *file_io_handle,
537 libfdata_vector_t *vector,
538 libfdata_cache_t *cache,
539 int element_index,
540 int element_data_file_index,
541 off64_t element_data_offset,
542 size64_t element_data_size,
543 uint32_t element_data_flags,
544 uint8_t read_flags LIBMODI_ATTRIBUTE_UNUSED,
545 libcerror_error_t **error )
546 {
547 libbfio_handle_t *bfio_handle = NULL;
548 libmodi_data_block_t *data_block = NULL;
549 static char *function = "libmodi_data_block_read_vector_element_data";
550
551 LIBMODI_UNREFERENCED_PARAMETER( read_flags );
552
553 if( io_handle == NULL )
554 {
555 libcerror_error_set(
556 error,
557 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
558 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
559 "%s: invalid IO handle.",
560 function );
561
562 return( -1 );
563 }
564 if( ( io_handle->image_type != LIBMODI_IMAGE_TYPE_SPARSE_BUNDLE )
565 && ( element_data_file_index != 0 ) )
566 {
567 libcerror_error_set(
568 error,
569 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
570 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
571 "%s: invalid element data file index value out of bounds.",
572 function );
573
574 return( -1 );
575 }
576 if( ( element_data_size == 0 )
577 || ( element_data_size > (size64_t) SSIZE_MAX ) )
578 {
579 libcerror_error_set(
580 error,
581 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
582 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
583 "%s: invalid element data size value out of bounds.",
584 function );
585
586 return( -1 );
587 }
588 if( libmodi_data_block_initialize(
589 &data_block,
590 (size_t) element_data_size,
591 error ) != 1 )
592 {
593 libcerror_error_set(
594 error,
595 LIBCERROR_ERROR_DOMAIN_RUNTIME,
596 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
597 "%s: unable to create data block.",
598 function );
599
600 goto on_error;
601 }
602 if( ( element_data_flags & LIBFDATA_RANGE_FLAG_IS_SPARSE ) != 0 )
603 {
604 if( memory_set(
605 data_block->data,
606 0,
607 data_block->data_size ) == NULL )
608 {
609 libcerror_error_set(
610 error,
611 LIBCERROR_ERROR_DOMAIN_MEMORY,
612 LIBCERROR_MEMORY_ERROR_SET_FAILED,
613 "%s: unable to clear data block.",
614 function );
615
616 goto on_error;
617 }
618 }
619 else
620 {
621 if( io_handle->image_type != LIBMODI_IMAGE_TYPE_SPARSE_BUNDLE )
622 {
623 bfio_handle = (libbfio_handle_t *) file_io_handle;
624 }
625 else if( libbfio_pool_get_handle(
626 (libbfio_pool_t *) file_io_handle,
627 element_data_file_index,
628 &bfio_handle,
629 error ) != 1 )
630 {
631 libcerror_error_set(
632 error,
633 LIBCERROR_ERROR_DOMAIN_RUNTIME,
634 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
635 "%s: unable to retrieve handle: %d from file IO pool.",
636 function,
637 element_data_file_index );
638
639 goto on_error;
640 }
641 if( libmodi_data_block_read_file_io_handle(
642 data_block,
643 bfio_handle,
644 element_data_offset,
645 error ) != 1 )
646 {
647 libcerror_error_set(
648 error,
649 LIBCERROR_ERROR_DOMAIN_IO,
650 LIBCERROR_IO_ERROR_READ_FAILED,
651 "%s: unable to read data block at offset: %" PRIi64 " (0x%08" PRIx64 ").",
652 function,
653 element_data_offset,
654 element_data_offset );
655
656 goto on_error;
657 }
658 }
659 if( libfdata_vector_set_element_value_by_index(
660 vector,
661 (intptr_t *) file_io_handle,
662 cache,
663 element_index,
664 (intptr_t *) data_block,
665 (int (*)(intptr_t **, libcerror_error_t **)) &libmodi_data_block_free,
666 LIBFDATA_LIST_ELEMENT_VALUE_FLAG_MANAGED,
667 error ) != 1 )
668 {
669 libcerror_error_set(
670 error,
671 LIBCERROR_ERROR_DOMAIN_RUNTIME,
672 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
673 "%s: unable to set data block as element value.",
674 function );
675
676 goto on_error;
677 }
678 return( 1 );
679
680 on_error:
681 if( data_block != NULL )
682 {
683 libmodi_data_block_free(
684 &data_block,
685 NULL );
686 }
687 return( -1 );
688 }
689
690