1 /*
2 * Grain data 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 "libvmdk_compression.h"
28 #include "libvmdk_definitions.h"
29 #include "libvmdk_grain_data.h"
30 #include "libvmdk_handle.h"
31 #include "libvmdk_io_handle.h"
32 #include "libvmdk_libcerror.h"
33 #include "libvmdk_libcnotify.h"
34 #include "libvmdk_libfdata.h"
35 #include "libvmdk_unused.h"
36
37 /* Creates grain data
38 * Make sure the value grain_data is referencing, is set to NULL
39 * Returns 1 if successful or -1 on error
40 */
libvmdk_grain_data_initialize(libvmdk_grain_data_t ** grain_data,size_t data_size,libcerror_error_t ** error)41 int libvmdk_grain_data_initialize(
42 libvmdk_grain_data_t **grain_data,
43 size_t data_size,
44 libcerror_error_t **error )
45 {
46 static char *function = "libvmdk_grain_data_initialize";
47
48 if( grain_data == NULL )
49 {
50 libcerror_error_set(
51 error,
52 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
53 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
54 "%s: invalid grain data.",
55 function );
56
57 return( -1 );
58 }
59 if( *grain_data != NULL )
60 {
61 libcerror_error_set(
62 error,
63 LIBCERROR_ERROR_DOMAIN_RUNTIME,
64 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
65 "%s: invalid grain data 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 *grain_data = memory_allocate_structure(
83 libvmdk_grain_data_t );
84
85 if( *grain_data == NULL )
86 {
87 libcerror_error_set(
88 error,
89 LIBCERROR_ERROR_DOMAIN_MEMORY,
90 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
91 "%s: unable to create grain data.",
92 function );
93
94 goto on_error;
95 }
96 if( memory_set(
97 *grain_data,
98 0,
99 sizeof( libvmdk_grain_data_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 grain data.",
106 function );
107
108 goto on_error;
109 }
110 ( *grain_data )->data = (uint8_t *) memory_allocate(
111 sizeof( uint8_t ) * data_size );
112
113 if( ( *grain_data )->data == NULL )
114 {
115 libcerror_error_set(
116 error,
117 LIBCERROR_ERROR_DOMAIN_MEMORY,
118 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
119 "%s: unable to create data.",
120 function );
121
122 goto on_error;
123 }
124 ( *grain_data )->data_size = data_size;
125
126 return( 1 );
127
128 on_error:
129 if( *grain_data != NULL )
130 {
131 memory_free(
132 *grain_data );
133
134 *grain_data = NULL;
135 }
136 return( -1 );
137 }
138
139 /* Frees grain data
140 * Returns 1 if successful or -1 on error
141 */
libvmdk_grain_data_free(libvmdk_grain_data_t ** grain_data,libcerror_error_t ** error)142 int libvmdk_grain_data_free(
143 libvmdk_grain_data_t **grain_data,
144 libcerror_error_t **error )
145 {
146 static char *function = "libvmdk_grain_data_free";
147
148 if( grain_data == NULL )
149 {
150 libcerror_error_set(
151 error,
152 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
153 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
154 "%s: invalid grain data.",
155 function );
156
157 return( -1 );
158 }
159 if( *grain_data != NULL )
160 {
161 if( ( *grain_data )->data != NULL )
162 {
163 memory_free(
164 ( *grain_data )->data );
165 }
166 memory_free(
167 *grain_data );
168
169 *grain_data = NULL;
170 }
171 return( 1 );
172 }
173
174 /* Reads a compressed grain data header
175 * The number of bytes read or -1 on error
176 */
libvmdk_grain_data_read_compressed_header(libvmdk_grain_data_t * grain_data,libvmdk_io_handle_t * io_handle,libbfio_pool_t * file_io_pool,int file_io_pool_entry,libcerror_error_t ** error)177 ssize_t libvmdk_grain_data_read_compressed_header(
178 libvmdk_grain_data_t *grain_data,
179 libvmdk_io_handle_t *io_handle,
180 libbfio_pool_t *file_io_pool,
181 int file_io_pool_entry,
182 libcerror_error_t **error )
183 {
184 uint8_t compressed_data_header[ 12 ];
185
186 static char *function = "libvmdk_grain_data_read_compressed_header";
187 ssize_t read_count = 0;
188
189 if( grain_data == NULL )
190 {
191 libcerror_error_set(
192 error,
193 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
194 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
195 "%s: invalid grain data.",
196 function );
197
198 return( -1 );
199 }
200 if( io_handle == NULL )
201 {
202 libcerror_error_set(
203 error,
204 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
205 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
206 "%s: invalid IO handle.",
207 function );
208
209 return( -1 );
210 }
211 read_count = libbfio_pool_read_buffer(
212 file_io_pool,
213 file_io_pool_entry,
214 compressed_data_header,
215 12,
216 error );
217
218 if( read_count != (ssize_t) 12 )
219 {
220 libcerror_error_set(
221 error,
222 LIBCERROR_ERROR_DOMAIN_IO,
223 LIBCERROR_IO_ERROR_READ_FAILED,
224 "%s: unable to read compressed grain data header.",
225 function );
226
227 return( -1 );
228 }
229 #if defined( HAVE_DEBUG_OUTPUT )
230 if( libcnotify_verbose != 0 )
231 {
232 libcnotify_printf(
233 "%s: compressed grain data header:\n",
234 function );
235 libcnotify_print_data(
236 compressed_data_header,
237 12,
238 0 );
239 }
240 #endif
241 byte_stream_copy_to_uint64_little_endian(
242 compressed_data_header,
243 grain_data->uncompressed_data_offset );
244
245 byte_stream_copy_to_uint32_little_endian(
246 &( compressed_data_header[ 8 ] ),
247 grain_data->compressed_data_size );
248
249 #if defined( HAVE_DEBUG_OUTPUT )
250 if( libcnotify_verbose != 0 )
251 {
252 libcnotify_printf(
253 "%s: uncompressed data offset\t: %" PRIu64 " grains (0x%08" PRIx64 ")\n",
254 function,
255 grain_data->uncompressed_data_offset,
256 grain_data->uncompressed_data_offset * io_handle->grain_size );
257
258 libcnotify_printf(
259 "%s: compressed data size\t\t: %" PRIu32 "\n",
260 function,
261 grain_data->compressed_data_size );
262
263 libcnotify_printf(
264 "\n" );
265 }
266 #endif
267 grain_data->uncompressed_data_offset *= io_handle->grain_size;
268
269 return( read_count );
270 }
271
272 /* Reads a grain
273 * Callback function for the grains list
274 * Returns 1 if successful or -1 on error
275 */
libvmdk_grain_data_read_element_data(libvmdk_io_handle_t * io_handle,libbfio_pool_t * file_io_pool,libfdata_list_element_t * element,libfdata_cache_t * cache,int file_io_pool_entry,off64_t grain_data_offset,size64_t grain_data_size,uint32_t grain_data_flags,uint8_t read_flags LIBVMDK_ATTRIBUTE_UNUSED,libcerror_error_t ** error)276 int libvmdk_grain_data_read_element_data(
277 libvmdk_io_handle_t *io_handle,
278 libbfio_pool_t *file_io_pool,
279 libfdata_list_element_t *element,
280 libfdata_cache_t *cache,
281 int file_io_pool_entry,
282 off64_t grain_data_offset,
283 size64_t grain_data_size,
284 uint32_t grain_data_flags,
285 uint8_t read_flags LIBVMDK_ATTRIBUTE_UNUSED,
286 libcerror_error_t **error )
287 {
288 libvmdk_grain_data_t *grain_data = NULL;
289 uint8_t *compressed_data = NULL;
290 static char *function = "libvmdk_grain_data_read_element_data";
291 ssize_t read_count = 0;
292
293 LIBVMDK_UNREFERENCED_PARAMETER( read_flags )
294
295 if( io_handle == NULL )
296 {
297 libcerror_error_set(
298 error,
299 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
300 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
301 "%s: invalid IO handle.",
302 function );
303
304 return( -1 );
305 }
306 if( ( grain_data_size == (size64_t) 0 )
307 || ( grain_data_size > (size64_t) SSIZE_MAX ) )
308 {
309 libcerror_error_set(
310 error,
311 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
312 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
313 "%s: invalid grain data size value out of bounds.",
314 function );
315
316 return( -1 );
317 }
318 if( ( grain_data_flags & LIBVMDK_RANGE_FLAG_IS_SPARSE ) != 0 )
319 {
320 libcerror_error_set(
321 error,
322 LIBCERROR_ERROR_DOMAIN_RUNTIME,
323 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
324 "%s: sparse grain not supported.",
325 function );
326
327 return( -1 );
328 }
329 if( libbfio_pool_seek_offset(
330 file_io_pool,
331 file_io_pool_entry,
332 grain_data_offset,
333 SEEK_SET,
334 error ) == -1 )
335 {
336 libcerror_error_set(
337 error,
338 LIBCERROR_ERROR_DOMAIN_IO,
339 LIBCERROR_IO_ERROR_SEEK_FAILED,
340 "%s: unable to seek grain offset: %" PRIi64 " in file IO pool entry: %d.",
341 function,
342 grain_data_offset,
343 file_io_pool_entry );
344
345 goto on_error;
346 }
347 if( ( grain_data_flags & LIBVMDK_RANGE_FLAG_IS_COMPRESSED ) != 0 )
348 {
349 if( io_handle->grain_size > (size64_t) SSIZE_MAX )
350 {
351 libcerror_error_set(
352 error,
353 LIBCERROR_ERROR_DOMAIN_RUNTIME,
354 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
355 "%s: invalid IO handle - grain size value exceeds maximum.",
356 function );
357
358 goto on_error;
359 }
360 if( libvmdk_grain_data_initialize(
361 &grain_data,
362 (size_t) io_handle->grain_size,
363 error ) != 1 )
364 {
365 libcerror_error_set(
366 error,
367 LIBCERROR_ERROR_DOMAIN_RUNTIME,
368 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
369 "%s: unable to create grain data.",
370 function );
371
372 goto on_error;
373 }
374 read_count = libvmdk_grain_data_read_compressed_header(
375 grain_data,
376 io_handle,
377 file_io_pool,
378 file_io_pool_entry,
379 error );
380
381 if( read_count == -1 )
382 {
383 libcerror_error_set(
384 error,
385 LIBCERROR_ERROR_DOMAIN_IO,
386 LIBCERROR_IO_ERROR_READ_FAILED,
387 "%s: unable to read compressed grain data header.",
388 function );
389
390 goto on_error;
391 }
392 if( ( grain_data->compressed_data_size == 0 )
393 || ( grain_data->compressed_data_size > (uint32_t) MEMORY_MAXIMUM_ALLOCATION_SIZE ) )
394 {
395 libcerror_error_set(
396 error,
397 LIBCERROR_ERROR_DOMAIN_RUNTIME,
398 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
399 "%s: invalid grain data - compressed data size value out of bounds.",
400 function );
401
402 goto on_error;
403 }
404 compressed_data = (uint8_t *) memory_allocate(
405 sizeof( uint8_t ) * (size_t) grain_data->compressed_data_size );
406
407 if( compressed_data == NULL )
408 {
409 libcerror_error_set(
410 error,
411 LIBCERROR_ERROR_DOMAIN_MEMORY,
412 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
413 "%s: unable to create compressed data.",
414 function );
415
416 goto on_error;
417 }
418 read_count = libbfio_pool_read_buffer(
419 file_io_pool,
420 file_io_pool_entry,
421 compressed_data,
422 (size_t) grain_data->compressed_data_size,
423 error );
424
425 if( read_count != (ssize_t) grain_data->compressed_data_size )
426 {
427 libcerror_error_set(
428 error,
429 LIBCERROR_ERROR_DOMAIN_IO,
430 LIBCERROR_IO_ERROR_READ_FAILED,
431 "%s: unable to read compressed grain data.",
432 function );
433
434 goto on_error;
435 }
436 if( libvmdk_decompress_data(
437 compressed_data,
438 (size_t) grain_data->compressed_data_size,
439 LIBVMDK_COMPRESSION_METHOD_DEFLATE,
440 grain_data->data,
441 &( grain_data->data_size ),
442 error ) != 1 )
443 {
444 libcerror_error_set(
445 error,
446 LIBCERROR_ERROR_DOMAIN_COMPRESSION,
447 LIBCERROR_COMPRESSION_ERROR_DECOMPRESS_FAILED,
448 "%s: unable to decompress grain data.",
449 function );
450
451 goto on_error;
452 }
453 memory_free(
454 compressed_data );
455
456 compressed_data = NULL;
457 }
458 else
459 {
460 if( libvmdk_grain_data_initialize(
461 &grain_data,
462 (size_t) grain_data_size,
463 error ) != 1 )
464 {
465 libcerror_error_set(
466 error,
467 LIBCERROR_ERROR_DOMAIN_RUNTIME,
468 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
469 "%s: unable to create grain data.",
470 function );
471
472 goto on_error;
473 }
474 if( grain_data == NULL )
475 {
476 libcerror_error_set(
477 error,
478 LIBCERROR_ERROR_DOMAIN_RUNTIME,
479 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
480 "%s: missing grain data.",
481 function );
482
483 goto on_error;
484 }
485 read_count = libbfio_pool_read_buffer(
486 file_io_pool,
487 file_io_pool_entry,
488 grain_data->data,
489 (size_t) grain_data_size,
490 error );
491
492 if( read_count != (ssize_t) grain_data_size )
493 {
494 libcerror_error_set(
495 error,
496 LIBCERROR_ERROR_DOMAIN_IO,
497 LIBCERROR_IO_ERROR_READ_FAILED,
498 "%s: unable to read grain data.",
499 function );
500
501 goto on_error;
502 }
503 }
504 if( libfdata_list_element_set_element_value(
505 element,
506 (intptr_t *) file_io_pool,
507 cache,
508 (intptr_t *) grain_data,
509 (int (*)(intptr_t **, libcerror_error_t **)) &libvmdk_grain_data_free,
510 LIBFDATA_LIST_ELEMENT_VALUE_FLAG_MANAGED,
511 error ) != 1 )
512 {
513 libcerror_error_set(
514 error,
515 LIBCERROR_ERROR_DOMAIN_RUNTIME,
516 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
517 "%s: unable to set grain data as element value.",
518 function );
519
520 goto on_error;
521 }
522 return( 1 );
523
524 on_error:
525 if( compressed_data != NULL )
526 {
527 memory_free(
528 compressed_data );
529 }
530 if( grain_data != NULL )
531 {
532 libvmdk_grain_data_free(
533 &grain_data,
534 NULL );
535 }
536 return( -1 );
537 }
538
539