Coverage Report

Created: 2025-09-05 06:58

/src/libvmdk/libvmdk/libvmdk_grain_data.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Grain data functions
3
 *
4
 * Copyright (C) 2009-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 "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
 */
41
int libvmdk_grain_data_initialize(
42
     libvmdk_grain_data_t **grain_data,
43
     size_t data_size,
44
     libcerror_error_t **error )
45
0
{
46
0
  static char *function = "libvmdk_grain_data_initialize";
47
48
0
  if( grain_data == NULL )
49
0
  {
50
0
    libcerror_error_set(
51
0
     error,
52
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
53
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
54
0
     "%s: invalid grain data.",
55
0
     function );
56
57
0
    return( -1 );
58
0
  }
59
0
  if( *grain_data != NULL )
60
0
  {
61
0
    libcerror_error_set(
62
0
     error,
63
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
64
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
65
0
     "%s: invalid grain data value already set.",
66
0
     function );
67
68
0
    return( -1 );
69
0
  }
70
0
  if( ( data_size == 0 )
71
0
   || ( data_size > (size_t) MEMORY_MAXIMUM_ALLOCATION_SIZE ) )
72
0
  {
73
0
    libcerror_error_set(
74
0
     error,
75
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
76
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
77
0
     "%s: invalid data size value out of bounds.",
78
0
     function );
79
80
0
    return( -1 );
81
0
  }
82
0
  *grain_data = memory_allocate_structure(
83
0
                 libvmdk_grain_data_t );
84
85
0
  if( *grain_data == NULL )
86
0
  {
87
0
    libcerror_error_set(
88
0
     error,
89
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
90
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
91
0
     "%s: unable to create grain data.",
92
0
     function );
93
94
0
    goto on_error;
95
0
  }
96
0
  if( memory_set(
97
0
       *grain_data,
98
0
       0,
99
0
       sizeof( libvmdk_grain_data_t ) ) == NULL )
100
0
  {
101
0
    libcerror_error_set(
102
0
     error,
103
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
104
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
105
0
     "%s: unable to clear grain data.",
106
0
     function );
107
108
0
    goto on_error;
109
0
  }
110
0
  ( *grain_data )->data = (uint8_t *) memory_allocate(
111
0
                                       sizeof( uint8_t ) * data_size );
112
113
0
  if( ( *grain_data )->data == NULL )
114
0
  {
115
0
    libcerror_error_set(
116
0
     error,
117
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
118
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
119
0
     "%s: unable to create data.",
120
0
     function );
121
122
0
    goto on_error;
123
0
  }
124
0
  ( *grain_data )->data_size = data_size;
125
126
0
  return( 1 );
127
128
0
on_error:
129
0
  if( *grain_data != NULL )
130
0
  {
131
0
    memory_free(
132
0
     *grain_data );
133
134
0
    *grain_data = NULL;
135
0
  }
136
0
  return( -1 );
137
0
}
138
139
/* Frees grain data
140
 * Returns 1 if successful or -1 on error
141
 */
142
int libvmdk_grain_data_free(
143
     libvmdk_grain_data_t **grain_data,
144
     libcerror_error_t **error )
145
0
{
146
0
  static char *function = "libvmdk_grain_data_free";
147
148
0
  if( grain_data == NULL )
149
0
  {
150
0
    libcerror_error_set(
151
0
     error,
152
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
153
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
154
0
     "%s: invalid grain data.",
155
0
     function );
156
157
0
    return( -1 );
158
0
  }
159
0
  if( *grain_data != NULL )
160
0
  {
161
0
    if( ( *grain_data )->data != NULL )
162
0
    {
163
0
      memory_free(
164
0
       ( *grain_data )->data );
165
0
    }
166
0
    memory_free(
167
0
     *grain_data );
168
169
0
    *grain_data = NULL;
170
0
  }
171
0
  return( 1 );
172
0
}
173
174
/* Reads a compressed grain data header
175
 * The number of bytes read or -1 on error
176
 */
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
0
{
184
0
  uint8_t compressed_data_header[ 12 ];
185
186
0
  static char *function = "libvmdk_grain_data_read_compressed_header";
187
0
  ssize_t read_count    = 0;
188
189
0
  if( grain_data == NULL )
190
0
  {
191
0
    libcerror_error_set(
192
0
     error,
193
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
194
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
195
0
     "%s: invalid grain data.",
196
0
     function );
197
198
0
    return( -1 );
199
0
  }
200
0
  if( io_handle == NULL )
201
0
  {
202
0
    libcerror_error_set(
203
0
     error,
204
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
205
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
206
0
     "%s: invalid IO handle.",
207
0
     function );
208
209
0
    return( -1 );
210
0
  }
211
0
  read_count = libbfio_pool_read_buffer(
212
0
          file_io_pool,
213
0
          file_io_pool_entry,
214
0
          compressed_data_header,
215
0
          12,
216
0
          error );
217
218
0
  if( read_count != (ssize_t) 12 )
219
0
  {
220
0
    libcerror_error_set(
221
0
     error,
222
0
     LIBCERROR_ERROR_DOMAIN_IO,
223
0
     LIBCERROR_IO_ERROR_READ_FAILED,
224
0
     "%s: unable to read compressed grain data header.",
225
0
     function );
226
227
0
    return( -1 );
228
0
  }
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
0
  byte_stream_copy_to_uint64_little_endian(
242
0
   compressed_data_header,
243
0
   grain_data->uncompressed_data_offset );
244
245
0
  byte_stream_copy_to_uint32_little_endian(
246
0
   &( compressed_data_header[ 8 ] ),
247
0
   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
0
  grain_data->uncompressed_data_offset *= io_handle->grain_size;
268
269
0
  return( read_count );
270
0
}
271
272
/* Reads a grain
273
 * Callback function for the grains list
274
 * Returns 1 if successful or -1 on error
275
 */
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
0
{
288
0
  libvmdk_grain_data_t *grain_data = NULL;
289
0
  uint8_t *compressed_data         = NULL;
290
0
  static char *function            = "libvmdk_grain_data_read_element_data";
291
0
  ssize_t read_count               = 0;
292
293
0
  LIBVMDK_UNREFERENCED_PARAMETER( read_flags )
294
295
0
  if( io_handle == NULL )
296
0
  {
297
0
    libcerror_error_set(
298
0
     error,
299
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
300
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
301
0
     "%s: invalid IO handle.",
302
0
     function );
303
304
0
    return( -1 );
305
0
  }
306
0
  if( ( grain_data_size == (size64_t) 0 )
307
0
   || ( grain_data_size > (size64_t) SSIZE_MAX ) )
308
0
  {
309
0
    libcerror_error_set(
310
0
     error,
311
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
312
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
313
0
     "%s: invalid grain data size value out of bounds.",
314
0
     function );
315
316
0
    return( -1 );
317
0
  }
318
0
  if( ( grain_data_flags & LIBVMDK_RANGE_FLAG_IS_SPARSE ) != 0 )
319
0
  {
320
0
    libcerror_error_set(
321
0
     error,
322
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
323
0
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
324
0
     "%s: sparse grain not supported.",
325
0
     function );
326
327
0
    return( -1 );
328
0
  }
329
0
  if( libbfio_pool_seek_offset(
330
0
       file_io_pool,
331
0
       file_io_pool_entry,
332
0
       grain_data_offset,
333
0
       SEEK_SET,
334
0
       error ) == -1 )
335
0
  {
336
0
    libcerror_error_set(
337
0
     error,
338
0
     LIBCERROR_ERROR_DOMAIN_IO,
339
0
     LIBCERROR_IO_ERROR_SEEK_FAILED,
340
0
     "%s: unable to seek grain offset: %" PRIi64 " in file IO pool entry: %d.",
341
0
     function,
342
0
     grain_data_offset,
343
0
     file_io_pool_entry );
344
345
0
    goto on_error;
346
0
  }
347
0
  if( ( grain_data_flags & LIBVMDK_RANGE_FLAG_IS_COMPRESSED ) != 0 )
348
0
  {
349
0
    if( io_handle->grain_size > (size64_t) SSIZE_MAX )
350
0
    {
351
0
      libcerror_error_set(
352
0
       error,
353
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
354
0
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
355
0
       "%s: invalid IO handle - grain size value exceeds maximum.",
356
0
       function );
357
358
0
      goto on_error;
359
0
    }
360
0
    if( libvmdk_grain_data_initialize(
361
0
         &grain_data,
362
0
         (size_t) io_handle->grain_size,
363
0
         error ) != 1 )
364
0
    {
365
0
      libcerror_error_set(
366
0
       error,
367
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
368
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
369
0
       "%s: unable to create grain data.",
370
0
       function );
371
372
0
      goto on_error;
373
0
    }
374
0
    read_count = libvmdk_grain_data_read_compressed_header(
375
0
                  grain_data,
376
0
                  io_handle,
377
0
                  file_io_pool,
378
0
                  file_io_pool_entry,
379
0
                  error );
380
381
0
    if( read_count == -1 )
382
0
    {
383
0
      libcerror_error_set(
384
0
       error,
385
0
       LIBCERROR_ERROR_DOMAIN_IO,
386
0
       LIBCERROR_IO_ERROR_READ_FAILED,
387
0
       "%s: unable to read compressed grain data header.",
388
0
       function );
389
390
0
      goto on_error;
391
0
    }
392
0
    if( ( grain_data->compressed_data_size == 0 )
393
0
     || ( grain_data->compressed_data_size > (uint32_t) MEMORY_MAXIMUM_ALLOCATION_SIZE ) )
394
0
    {
395
0
      libcerror_error_set(
396
0
       error,
397
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
398
0
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
399
0
       "%s: invalid grain data - compressed data size value out of bounds.",
400
0
       function );
401
402
0
      goto on_error;
403
0
    }
404
0
    compressed_data = (uint8_t *) memory_allocate(
405
0
                                   sizeof( uint8_t ) * (size_t) grain_data->compressed_data_size );
406
407
0
    if( compressed_data == NULL )
408
0
    {
409
0
      libcerror_error_set(
410
0
       error,
411
0
       LIBCERROR_ERROR_DOMAIN_MEMORY,
412
0
       LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
413
0
       "%s: unable to create compressed data.",
414
0
       function );
415
416
0
      goto on_error;
417
0
    }
418
0
    read_count = libbfio_pool_read_buffer(
419
0
            file_io_pool,
420
0
            file_io_pool_entry,
421
0
            compressed_data,
422
0
            (size_t) grain_data->compressed_data_size,
423
0
            error );
424
425
0
    if( read_count != (ssize_t) grain_data->compressed_data_size )
426
0
    {
427
0
      libcerror_error_set(
428
0
       error,
429
0
       LIBCERROR_ERROR_DOMAIN_IO,
430
0
       LIBCERROR_IO_ERROR_READ_FAILED,
431
0
       "%s: unable to read compressed grain data.",
432
0
       function );
433
434
0
      goto on_error;
435
0
    }
436
0
    if( libvmdk_decompress_data(
437
0
         compressed_data,
438
0
         (size_t) grain_data->compressed_data_size,
439
0
         LIBVMDK_COMPRESSION_METHOD_DEFLATE,
440
0
         grain_data->data,
441
0
         &( grain_data->data_size ),
442
0
         error ) != 1 )
443
0
    {
444
0
      libcerror_error_set(
445
0
       error,
446
0
       LIBCERROR_ERROR_DOMAIN_COMPRESSION,
447
0
       LIBCERROR_COMPRESSION_ERROR_DECOMPRESS_FAILED,
448
0
       "%s: unable to decompress grain data.",
449
0
       function );
450
451
0
      goto on_error;
452
0
    }
453
0
    memory_free(
454
0
     compressed_data );
455
456
0
    compressed_data = NULL;
457
0
  }
458
0
  else
459
0
  {
460
0
    if( libvmdk_grain_data_initialize(
461
0
         &grain_data,
462
0
         (size_t) grain_data_size,
463
0
         error ) != 1 )
464
0
    {
465
0
      libcerror_error_set(
466
0
       error,
467
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
468
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
469
0
       "%s: unable to create grain data.",
470
0
       function );
471
472
0
      goto on_error;
473
0
    }
474
0
    if( grain_data == NULL )
475
0
    {
476
0
      libcerror_error_set(
477
0
       error,
478
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
479
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
480
0
       "%s: missing grain data.",
481
0
       function );
482
483
0
      goto on_error;
484
0
    }
485
0
    read_count = libbfio_pool_read_buffer(
486
0
            file_io_pool,
487
0
            file_io_pool_entry,
488
0
            grain_data->data,
489
0
            (size_t) grain_data_size,
490
0
            error );
491
492
0
    if( read_count != (ssize_t) grain_data_size )
493
0
    {
494
0
      libcerror_error_set(
495
0
       error,
496
0
       LIBCERROR_ERROR_DOMAIN_IO,
497
0
       LIBCERROR_IO_ERROR_READ_FAILED,
498
0
       "%s: unable to read grain data.",
499
0
       function );
500
501
0
      goto on_error;
502
0
    }
503
0
  }
504
0
  if( libfdata_list_element_set_element_value(
505
0
       element,
506
0
       (intptr_t *) file_io_pool,
507
0
       cache,
508
0
       (intptr_t *) grain_data,
509
0
       (int (*)(intptr_t **, libcerror_error_t **)) &libvmdk_grain_data_free,
510
0
       LIBFDATA_LIST_ELEMENT_VALUE_FLAG_MANAGED,
511
0
       error ) != 1 )
512
0
  {
513
0
    libcerror_error_set(
514
0
     error,
515
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
516
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
517
0
     "%s: unable to set grain data as element value.",
518
0
     function );
519
520
0
    goto on_error;
521
0
  }
522
0
  return( 1 );
523
524
0
on_error:
525
0
  if( compressed_data != NULL )
526
0
  {
527
0
    memory_free(
528
0
     compressed_data );
529
0
  }
530
0
  if( grain_data != NULL )
531
0
  {
532
0
    libvmdk_grain_data_free(
533
0
     &grain_data,
534
0
     NULL );
535
0
  }
536
0
  return( -1 );
537
0
}
538