Coverage Report

Created: 2026-10-22 07:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libvshadow/libvshadow/libvshadow_io_handle.c
Line
Count
Source
1
/*
2
 * Input/Output (IO) handle functions
3
 *
4
 * Copyright (C) 2011-2026, 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 "libvshadow_block_descriptor.h"
28
#include "libvshadow_block_tree.h"
29
#include "libvshadow_block_tree_node.h"
30
#include "libvshadow_debug.h"
31
#include "libvshadow_definitions.h"
32
#include "libvshadow_io_handle.h"
33
#include "libvshadow_libbfio.h"
34
#include "libvshadow_libcdata.h"
35
#include "libvshadow_libcerror.h"
36
#include "libvshadow_libcnotify.h"
37
#include "libvshadow_libfdatetime.h"
38
#include "libvshadow_libfguid.h"
39
#include "libvshadow_store_descriptor.h"
40
41
#include "vshadow_catalog.h"
42
#include "vshadow_volume.h"
43
44
const uint8_t vshadow_vss_identifier[ 16 ] = {
45
  0x6b, 0x87, 0x08, 0x38, 0x76, 0xc1, 0x48, 0x4e, 0xb7, 0xae, 0x04, 0x04, 0x6e, 0x6c, 0xc7, 0x52 };
46
47
/* Creates an IO handle
48
 * Make sure the value io_handle is referencing, is set to NULL
49
 * Returns 1 if successful or -1 on error
50
 */
51
int libvshadow_io_handle_initialize(
52
     libvshadow_io_handle_t **io_handle,
53
     libcerror_error_t **error )
54
4.15k
{
55
4.15k
  static char *function = "libvshadow_io_handle_initialize";
56
57
4.15k
  if( io_handle == NULL )
58
0
  {
59
0
    libcerror_error_set(
60
0
     error,
61
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
62
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
63
0
     "%s: invalid IO handle.",
64
0
     function );
65
66
0
    return( -1 );
67
0
  }
68
4.15k
  if( *io_handle != NULL )
69
0
  {
70
0
    libcerror_error_set(
71
0
     error,
72
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
73
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
74
0
     "%s: invalid IO handle value already set.",
75
0
     function );
76
77
0
    return( -1 );
78
0
  }
79
4.15k
  *io_handle = memory_allocate_structure(
80
4.15k
                libvshadow_io_handle_t );
81
82
4.15k
  if( *io_handle == NULL )
83
0
  {
84
0
    libcerror_error_set(
85
0
     error,
86
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
87
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
88
0
     "%s: unable to create IO handle.",
89
0
     function );
90
91
0
    goto on_error;
92
0
  }
93
4.15k
  if( memory_set(
94
4.15k
       *io_handle,
95
4.15k
       0,
96
4.15k
       sizeof( libvshadow_io_handle_t ) ) == NULL )
97
0
  {
98
0
    libcerror_error_set(
99
0
     error,
100
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
101
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
102
0
     "%s: unable to clear IO handle.",
103
0
     function );
104
105
0
    goto on_error;
106
0
  }
107
4.15k
  ( *io_handle )->block_size = 0x4000;
108
109
4.15k
  return( 1 );
110
111
0
on_error:
112
0
  if( *io_handle != NULL )
113
0
  {
114
0
    memory_free(
115
0
     *io_handle );
116
117
0
    *io_handle = NULL;
118
0
  }
119
0
  return( -1 );
120
4.15k
}
121
122
/* Frees an IO handle
123
 * Returns 1 if successful or -1 on error
124
 */
125
int libvshadow_io_handle_free(
126
     libvshadow_io_handle_t **io_handle,
127
     libcerror_error_t **error )
128
4.15k
{
129
4.15k
  static char *function = "libvshadow_io_handle_free";
130
131
4.15k
  if( io_handle == NULL )
132
0
  {
133
0
    libcerror_error_set(
134
0
     error,
135
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
136
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
137
0
     "%s: invalid IO handle.",
138
0
     function );
139
140
0
    return( -1 );
141
0
  }
142
4.15k
  if( *io_handle != NULL )
143
4.15k
  {
144
4.15k
    memory_free(
145
4.15k
     *io_handle );
146
147
4.15k
    *io_handle = NULL;
148
4.15k
  }
149
4.15k
  return( 1 );
150
4.15k
}
151
152
/* Clears the IO handle
153
 * Returns 1 if successful or -1 on error
154
 */
155
int libvshadow_io_handle_clear(
156
     libvshadow_io_handle_t *io_handle,
157
     libcerror_error_t **error )
158
618
{
159
618
  static char *function = "libvshadow_io_handle_clear";
160
161
618
  if( io_handle == NULL )
162
0
  {
163
0
    libcerror_error_set(
164
0
     error,
165
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
166
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
167
0
     "%s: invalid IO handle.",
168
0
     function );
169
170
0
    return( -1 );
171
0
  }
172
618
  if( memory_set(
173
618
       io_handle,
174
618
       0,
175
618
       sizeof( libvshadow_io_handle_t ) ) == NULL )
176
0
  {
177
0
    libcerror_error_set(
178
0
     error,
179
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
180
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
181
0
     "%s: unable to clear IO handle.",
182
0
     function );
183
184
0
    return( -1 );
185
0
  }
186
618
  io_handle->block_size = 0x4000;
187
188
618
  return( 1 );
189
618
}
190
191
/* Checks if this is the first time the block is being read
192
 * Returns 1 if successful or -1 on error
193
 */
194
int libvshadow_io_handle_check_if_block_first_read(
195
     libvshadow_io_handle_t *io_handle,
196
     libvshadow_block_tree_t *block_tree,
197
     off64_t block_offset,
198
     libcerror_error_t **error )
199
2.75k
{
200
2.75k
  libvshadow_block_descriptor_t *existing_block_descriptor = NULL;
201
2.75k
  libvshadow_block_descriptor_t *new_block_descriptor      = NULL;
202
2.75k
  libvshadow_block_tree_node_t *leaf_block_tree_node       = NULL;
203
2.75k
  static char *function                                    = "libvshadow_io_handle_check_if_block_first_read";
204
2.75k
  int leaf_value_index                                     = 0;
205
2.75k
  int result                                               = 0;
206
207
2.75k
  if( io_handle == NULL )
208
0
  {
209
0
    libcerror_error_set(
210
0
     error,
211
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
212
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
213
0
     "%s: invalid IO handle.",
214
0
     function );
215
216
0
    return( -1 );
217
0
  }
218
2.75k
  if( libvshadow_block_descriptor_initialize(
219
2.75k
       &new_block_descriptor,
220
2.75k
       error ) != 1 )
221
0
  {
222
0
    libcerror_error_set(
223
0
     error,
224
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
225
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
226
0
     "%s: unable to create block descriptor.",
227
0
     function );
228
229
0
    goto on_error;
230
0
  }
231
2.75k
  new_block_descriptor->offset = block_offset;
232
233
2.75k
  result = libvshadow_block_tree_insert_block_descriptor_by_offset(
234
2.75k
            block_tree,
235
2.75k
            block_offset,
236
2.75k
            new_block_descriptor,
237
2.75k
            &leaf_value_index,
238
2.75k
            &leaf_block_tree_node,
239
2.75k
            &existing_block_descriptor,
240
2.75k
            error );
241
242
2.75k
  if( result == -1 )
243
476
  {
244
476
    libcerror_error_set(
245
476
     error,
246
476
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
247
476
     LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
248
476
     "%s: unable to insert block descriptor in block tree.",
249
476
     function );
250
251
476
    goto on_error;
252
476
  }
253
2.28k
  else if( result == 0 )
254
5
  {
255
5
    libcerror_error_set(
256
5
     error,
257
5
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
258
5
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
259
5
     "%s: invalid block offset: %" PRIi64 " (0x%08" PRIx64 ") value already exists.",
260
5
     function,
261
5
     block_offset,
262
5
     block_offset );
263
264
5
    goto on_error;
265
5
  }
266
2.27k
  new_block_descriptor = NULL;
267
268
2.27k
  return( 1 );
269
270
481
on_error:
271
481
  if( new_block_descriptor != NULL )
272
481
  {
273
481
    libvshadow_block_descriptor_free(
274
481
     &new_block_descriptor,
275
481
     NULL );
276
481
  }
277
481
  return( -1 );
278
2.75k
}
279
280
/* Reads the volume header
281
 * Returns 1 if successful or -1 on error
282
 */
283
int libvshadow_io_handle_read_volume_header(
284
     libvshadow_io_handle_t *io_handle,
285
     libbfio_handle_t *file_io_handle,
286
     off64_t file_offset,
287
     off64_t *catalog_offset,
288
     libcerror_error_t **error )
289
2.95k
{
290
2.95k
  vshadow_volume_header_t volume_header;
291
292
2.95k
  static char *function = "libvshadow_io_handle_read_volume_header";
293
2.95k
  ssize_t read_count    = 0;
294
295
2.95k
  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
#if defined( HAVE_DEBUG_OUTPUT )
307
  if( libcnotify_verbose != 0 )
308
  {
309
    libcnotify_printf(
310
     "%s: reading volume header at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
311
     function,
312
     file_offset,
313
     file_offset );
314
  }
315
#endif
316
2.95k
  read_count = libbfio_handle_read_buffer_at_offset(
317
2.95k
                file_io_handle,
318
2.95k
                (uint8_t *) &volume_header,
319
2.95k
                sizeof( vshadow_volume_header_t ),
320
2.95k
                file_offset,
321
2.95k
                error );
322
323
2.95k
  if( read_count != (ssize_t) sizeof( vshadow_volume_header_t ) )
324
67
  {
325
67
    libcerror_error_set(
326
67
     error,
327
67
     LIBCERROR_ERROR_DOMAIN_IO,
328
67
     LIBCERROR_IO_ERROR_READ_FAILED,
329
67
     "%s: unable to read volume header data at offset: %" PRIi64 " (0x%08" PRIx64 ").",
330
67
     function,
331
67
     file_offset,
332
67
     file_offset );
333
334
67
    return( -1 );
335
67
  }
336
2.88k
  if( libvshadow_io_handle_read_volume_header_data(
337
2.88k
       io_handle,
338
2.88k
       (uint8_t *) &volume_header,
339
2.88k
       sizeof( vshadow_volume_header_t ),
340
2.88k
       catalog_offset,
341
2.88k
       error ) != 1 )
342
325
  {
343
325
    libcerror_error_set(
344
325
     error,
345
325
     LIBCERROR_ERROR_DOMAIN_IO,
346
325
     LIBCERROR_IO_ERROR_READ_FAILED,
347
325
     "%s: unable to read volume header.",
348
325
     function );
349
350
325
    return( -1 );
351
325
  }
352
2.55k
  return( 1 );
353
2.88k
}
354
355
/* Reads the volume header
356
 * Returns 1 if successful or -1 on error
357
 */
358
int libvshadow_io_handle_read_volume_header_data(
359
     libvshadow_io_handle_t *io_handle,
360
     const uint8_t *data,
361
     size_t data_size,
362
     off64_t *catalog_offset,
363
     libcerror_error_t **error )
364
2.88k
{
365
2.88k
  static char *function        = "libvshadow_io_handle_read_volume_header_data";
366
2.88k
  uint64_t safe_catalog_offset = 0;
367
2.88k
  uint32_t record_type         = 0;
368
2.88k
  uint32_t version             = 0;
369
370
#if defined( HAVE_DEBUG_OUTPUT )
371
  uint64_t value_64bit         = 0;
372
  uint32_t value_32bit         = 0;
373
#endif
374
375
2.88k
  if( io_handle == NULL )
376
0
  {
377
0
    libcerror_error_set(
378
0
     error,
379
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
380
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
381
0
     "%s: invalid IO handle.",
382
0
     function );
383
384
0
    return( -1 );
385
0
  }
386
2.88k
  if( data == NULL )
387
0
  {
388
0
    libcerror_error_set(
389
0
     error,
390
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
391
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
392
0
     "%s: invalid data.",
393
0
     function );
394
395
0
    return( -1 );
396
0
  }
397
2.88k
  if( ( data_size < sizeof( vshadow_volume_header_t ) )
398
2.88k
   || ( data_size > (size_t) SSIZE_MAX ) )
399
0
  {
400
0
    libcerror_error_set(
401
0
     error,
402
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
403
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
404
0
     "%s: invalid data size value out of bounds.",
405
0
     function );
406
407
0
    return( -1 );
408
0
  }
409
2.88k
  if( catalog_offset == NULL )
410
0
  {
411
0
    libcerror_error_set(
412
0
     error,
413
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
414
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
415
0
     "%s: invalid catalog offset.",
416
0
     function );
417
418
0
    return( -1 );
419
0
  }
420
#if defined( HAVE_DEBUG_OUTPUT )
421
  if( libcnotify_verbose != 0 )
422
  {
423
    libcnotify_printf(
424
     "%s: volume header data:\n",
425
     function );
426
    libcnotify_print_data(
427
     data,
428
     data_size,
429
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
430
  }
431
#endif
432
2.88k
  if( memory_compare(
433
2.88k
       ( (vshadow_volume_header_t *) data )->identifier,
434
2.88k
       vshadow_vss_identifier,
435
2.88k
       16 ) != 0 )
436
139
  {
437
139
    libcerror_error_set(
438
139
     error,
439
139
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
440
139
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
441
139
     "%s: invalid volume identifier.",
442
139
     function );
443
444
139
    return( -1 );
445
139
  }
446
2.74k
  byte_stream_copy_to_uint32_little_endian(
447
2.74k
   ( (vshadow_volume_header_t *) data )->version,
448
2.74k
   version );
449
450
2.74k
  byte_stream_copy_to_uint32_little_endian(
451
2.74k
   ( (vshadow_volume_header_t *) data )->record_type,
452
2.74k
   record_type );
453
454
2.74k
  byte_stream_copy_to_uint64_little_endian(
455
2.74k
   ( (vshadow_volume_header_t *) data )->catalog_offset,
456
2.74k
   safe_catalog_offset );
457
458
#if defined( HAVE_DEBUG_OUTPUT )
459
  if( libcnotify_verbose != 0 )
460
  {
461
    if( libvshadow_debug_print_guid_value(
462
         function,
463
         "identifier\t\t",
464
         ( (vshadow_volume_header_t *) data )->identifier,
465
         16,
466
         LIBFGUID_ENDIAN_LITTLE,
467
         LIBFGUID_STRING_FORMAT_FLAG_USE_LOWER_CASE,
468
         error ) != 1 )
469
    {
470
      libcerror_error_set(
471
       error,
472
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
473
       LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
474
       "%s: unable to print GUID value.",
475
       function );
476
477
      return( -1 );
478
    }
479
    libcnotify_printf(
480
     "%s: version\t\t\t: %" PRIu32 "\n",
481
     function,
482
     version );
483
484
    libcnotify_printf(
485
     "%s: record type\t\t: %" PRIu32 "\n",
486
     function,
487
     record_type );
488
489
    byte_stream_copy_to_uint64_little_endian(
490
     ( (vshadow_volume_header_t *) data )->offset,
491
     value_64bit );
492
    libcnotify_printf(
493
     "%s: offset\t\t\t: 0x%08" PRIx64 "\n",
494
     function,
495
     value_64bit );
496
497
    byte_stream_copy_to_uint64_little_endian(
498
     ( (vshadow_volume_header_t *) data )->unknown1,
499
     value_64bit );
500
    libcnotify_printf(
501
     "%s: unknown1\t\t\t: 0x%08" PRIx64 "\n",
502
     function,
503
     value_64bit );
504
505
    byte_stream_copy_to_uint64_little_endian(
506
     ( (vshadow_volume_header_t *) data )->unknown2,
507
     value_64bit );
508
    libcnotify_printf(
509
     "%s: unknown2\t\t\t: 0x%08" PRIx64 "\n",
510
     function,
511
     value_64bit );
512
513
    libcnotify_printf(
514
     "%s: catalog offset\t\t: 0x%08" PRIx64 "\n",
515
     function,
516
     safe_catalog_offset );
517
518
    byte_stream_copy_to_uint64_little_endian(
519
     ( (vshadow_volume_header_t *) data )->maximum_size,
520
     value_64bit );
521
    libcnotify_printf(
522
     "%s: maximum size\t\t: %" PRIu64 "\n",
523
     function,
524
     value_64bit );
525
526
    if( libvshadow_debug_print_guid_value(
527
         function,
528
         "volume identifier\t\t",
529
         ( (vshadow_volume_header_t *) data )->volume_identifier,
530
         16,
531
         LIBFGUID_ENDIAN_LITTLE,
532
         LIBFGUID_STRING_FORMAT_FLAG_USE_LOWER_CASE,
533
         error ) != 1 )
534
    {
535
      libcerror_error_set(
536
       error,
537
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
538
       LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
539
       "%s: unable to print GUID value.",
540
       function );
541
542
      return( -1 );
543
    }
544
    if( libvshadow_debug_print_guid_value(
545
         function,
546
         "store volume identifier\t",
547
         ( (vshadow_volume_header_t *) data )->store_volume_identifier,
548
         16,
549
         LIBFGUID_ENDIAN_LITTLE,
550
         LIBFGUID_STRING_FORMAT_FLAG_USE_LOWER_CASE,
551
         error ) != 1 )
552
    {
553
      libcerror_error_set(
554
       error,
555
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
556
       LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
557
       "%s: unable to print GUID value.",
558
       function );
559
560
      return( -1 );
561
    }
562
    byte_stream_copy_to_uint32_little_endian(
563
     ( (vshadow_volume_header_t *) data )->unknown3,
564
     value_32bit );
565
    libcnotify_printf(
566
     "%s: unknown3\t\t\t: 0x%08" PRIx64 "\n",
567
     function,
568
     value_32bit );
569
570
    libcnotify_printf(
571
     "%s: unknown4:\n",
572
     function );
573
    libcnotify_print_data(
574
     ( (vshadow_volume_header_t *) data )->unknown4,
575
     412,
576
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
577
  }
578
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
579
580
2.74k
  if( ( version != 1 )
581
1.63k
   && ( version != 2 ) )
582
98
  {
583
98
    libcerror_error_set(
584
98
     error,
585
98
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
586
98
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
587
98
     "%s: unsupported version: %" PRIu32 ".",
588
98
     function,
589
98
     version );
590
591
98
    return( -1 );
592
98
  }
593
2.64k
  if( record_type != LIBVSHADOW_RECORD_TYPE_VOLUME_HEADER )
594
88
  {
595
88
    libcerror_error_set(
596
88
     error,
597
88
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
598
88
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
599
88
     "%s: unsupported record type: %" PRIu32 ".",
600
88
     function,
601
88
     version );
602
603
88
    return( -1 );
604
88
  }
605
2.55k
  *catalog_offset = (off64_t) safe_catalog_offset;
606
607
2.55k
  return( 1 );
608
2.64k
}
609
610
/* Reads the catalog
611
 * Returns 1 if successful or -1 on error
612
 */
613
int libvshadow_io_handle_read_catalog(
614
     libvshadow_io_handle_t *io_handle,
615
     libbfio_handle_t *file_io_handle,
616
     off64_t file_offset,
617
     size64_t *volume_size,
618
     libcdata_array_t *store_descriptors_array,
619
     libcerror_error_t **error )
620
2.44k
{
621
2.44k
  libvshadow_block_tree_t *catalog_block_tree          = NULL;
622
2.44k
  libvshadow_store_descriptor_t *last_store_descriptor = NULL;
623
2.44k
  libvshadow_store_descriptor_t *store_descriptor      = NULL;
624
2.44k
  uint8_t *catalog_block_data                          = NULL;
625
2.44k
  static char *function                                = "libvshadow_io_handle_read_catalog";
626
2.44k
  size64_t safe_volume_size                            = 0;
627
2.44k
  size_t catalog_block_offset                          = 0;
628
2.44k
  ssize_t read_count                                   = 0;
629
2.44k
  off64_t next_offset                                  = 0;
630
2.44k
  uint64_t catalog_entry_type                          = 0;
631
2.44k
  int result                                           = 0;
632
2.44k
  int store_descriptor_index                           = 0;
633
634
2.44k
  if( io_handle == NULL )
635
0
  {
636
0
    libcerror_error_set(
637
0
     error,
638
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
639
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
640
0
     "%s: invalid IO handle.",
641
0
     function );
642
643
0
    return( -1 );
644
0
  }
645
2.44k
  if( volume_size == NULL )
646
0
  {
647
0
    libcerror_error_set(
648
0
     error,
649
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
650
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
651
0
     "%s: invalid volume size.",
652
0
     function );
653
654
0
    return( -1 );
655
0
  }
656
2.44k
  catalog_block_data = (uint8_t *) memory_allocate(
657
2.44k
                                    sizeof( uint8_t ) * io_handle->block_size );
658
659
2.44k
  if( catalog_block_data == NULL )
660
0
  {
661
0
    libcerror_error_set(
662
0
     error,
663
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
664
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
665
0
     "%s: unable to catalog block data.",
666
0
     function );
667
668
0
    goto on_error;
669
0
  }
670
2.44k
  if( libvshadow_block_tree_initialize(
671
2.44k
       &catalog_block_tree,
672
2.44k
       io_handle->volume_size,
673
2.44k
       io_handle->block_size,
674
2.44k
       error ) != 1 )
675
0
  {
676
0
    libcerror_error_set(
677
0
     error,
678
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
679
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
680
0
     "%s: unable to create catalog block tree.",
681
0
     function );
682
683
0
    goto on_error;
684
0
  }
685
2.44k
  do
686
2.49k
  {
687
#if defined( HAVE_DEBUG_OUTPUT )
688
    if( libcnotify_verbose != 0 )
689
    {
690
      libcnotify_printf(
691
       "%s: reading catalog block at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
692
       function,
693
       file_offset,
694
       file_offset );
695
    }
696
#endif
697
2.49k
    if( libvshadow_io_handle_check_if_block_first_read(
698
2.49k
         io_handle,
699
2.49k
         catalog_block_tree,
700
2.49k
         file_offset,
701
2.49k
         error ) != 1 )
702
240
    {
703
240
      libcerror_error_set(
704
240
       error,
705
240
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
706
240
       LIBCERROR_RUNTIME_ERROR_GENERIC,
707
240
       "%s: unable to check if first read of catalog block at offset: %" PRIi64 " (0x%08" PRIx64 ").",
708
240
       function,
709
240
       file_offset,
710
240
       file_offset );
711
712
240
      goto on_error;
713
240
    }
714
2.25k
    read_count = libbfio_handle_read_buffer_at_offset(
715
2.25k
            file_io_handle,
716
2.25k
            catalog_block_data,
717
2.25k
            io_handle->block_size,
718
2.25k
            file_offset,
719
2.25k
            error );
720
721
2.25k
    if( read_count != (ssize_t) io_handle->block_size )
722
86
    {
723
86
      libcerror_error_set(
724
86
       error,
725
86
       LIBCERROR_ERROR_DOMAIN_IO,
726
86
       LIBCERROR_IO_ERROR_READ_FAILED,
727
86
       "%s: unable to read catalog block data at offset: %" PRIi64 " (0x%08" PRIx64 ").",
728
86
       function,
729
86
       file_offset,
730
86
       file_offset );
731
732
86
      goto on_error;
733
86
    }
734
2.16k
    if( libvshadow_io_handle_read_catalog_header_data(
735
2.16k
         io_handle,
736
2.16k
         catalog_block_data,
737
2.16k
         io_handle->block_size,
738
2.16k
         &next_offset,
739
2.16k
         error ) != 1 )
740
320
    {
741
320
      libcerror_error_set(
742
320
       error,
743
320
       LIBCERROR_ERROR_DOMAIN_IO,
744
320
       LIBCERROR_IO_ERROR_READ_FAILED,
745
320
       "%s: unable to read catalog block header.",
746
320
       function );
747
748
320
      goto on_error;
749
320
    }
750
1.84k
    catalog_block_offset = sizeof( vshadow_catalog_header_t );
751
752
149k
    while( catalog_block_offset < io_handle->block_size )
753
148k
    {
754
148k
      if( store_descriptor == NULL )
755
8.09k
      {
756
8.09k
        if( libvshadow_store_descriptor_initialize(
757
8.09k
             &store_descriptor,
758
8.09k
             error ) != 1 )
759
0
        {
760
0
          libcerror_error_set(
761
0
           error,
762
0
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
763
0
           LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
764
0
           "%s: unable to create store descriptor.",
765
0
           function );
766
767
0
          goto on_error;
768
0
        }
769
8.09k
      }
770
148k
      result = libvshadow_store_descriptor_read_catalog_entry(
771
148k
                store_descriptor,
772
148k
                &( catalog_block_data[ catalog_block_offset ] ),
773
148k
                io_handle->block_size - catalog_block_offset,
774
148k
                &catalog_entry_type,
775
148k
                error );
776
777
148k
      if( result == -1 )
778
1.05k
      {
779
1.05k
        libcerror_error_set(
780
1.05k
         error,
781
1.05k
         LIBCERROR_ERROR_DOMAIN_IO,
782
1.05k
         LIBCERROR_IO_ERROR_READ_FAILED,
783
1.05k
         "%s: unable to read catalog entry.",
784
1.05k
         function );
785
786
1.05k
        goto on_error;
787
1.05k
      }
788
147k
      if( catalog_entry_type == 2 )
789
6.29k
      {
790
6.29k
        if( libcdata_array_insert_entry(
791
6.29k
             store_descriptors_array,
792
6.29k
             &store_descriptor_index,
793
6.29k
             (intptr_t *) store_descriptor,
794
6.29k
             (int(*)(intptr_t *, intptr_t *, libcerror_error_t **)) &libvshadow_store_descriptor_compare_by_creation_time,
795
6.29k
             LIBCDATA_INSERT_FLAG_UNIQUE_ENTRIES,
796
6.29k
             error ) != 1 )
797
3
        {
798
3
          libcerror_error_set(
799
3
           error,
800
3
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
801
3
           LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
802
3
           "%s: unable to append store descriptor to array.",
803
3
           function );
804
805
3
          goto on_error;
806
3
        }
807
6.28k
        if( ( safe_volume_size == 0 )
808
2.44k
         && ( store_descriptor_index == 0 ) )
809
1.62k
        {
810
1.62k
          safe_volume_size = store_descriptor->volume_size;
811
1.62k
        }
812
#if defined( HAVE_DEBUG_OUTPUT )
813
        else if( libcnotify_verbose != 0 )
814
        {
815
          if( safe_volume_size != store_descriptor->volume_size )
816
          {
817
            libcnotify_printf(
818
             "%s: store descriptor: %d - mismatch in volume size: %" PRIu64 " (expected: %" PRIu64 ").",
819
             function,
820
             store_descriptor_index,
821
             store_descriptor->volume_size,
822
             safe_volume_size );
823
          }
824
        }
825
#endif
826
6.28k
        last_store_descriptor = store_descriptor;
827
6.28k
        store_descriptor      = NULL;
828
6.28k
      }
829
140k
      else if( catalog_entry_type == 3 )
830
5.48k
      {
831
5.48k
        if( ( last_store_descriptor != NULL )
832
4.51k
         && ( memory_compare(
833
4.51k
               store_descriptor->identifier,
834
4.51k
               last_store_descriptor->identifier,
835
4.51k
               16 ) != 0 ) )
836
2.92k
        {
837
2.92k
          result = libcdata_array_get_entry_by_value(
838
2.92k
                    store_descriptors_array,
839
2.92k
                    (intptr_t *) store_descriptor,
840
2.92k
                    (int (*)(intptr_t *, intptr_t *, libcerror_error_t **)) &libvshadow_store_descriptor_compare_by_identifier,
841
2.92k
                    (intptr_t **) &last_store_descriptor,
842
2.92k
                    error );
843
844
2.92k
          if( result == -1 )
845
0
          {
846
0
            libcerror_error_set(
847
0
             error,
848
0
             LIBCERROR_ERROR_DOMAIN_RUNTIME,
849
0
             LIBCERROR_RUNTIME_ERROR_GET_FAILED,
850
0
             "%s: unable to retrieve store descriptors by identifier.",
851
0
             function );
852
853
0
            goto on_error;
854
0
          }
855
2.92k
        }
856
/* TODO look for the last store descriptor ? */
857
5.48k
        if( last_store_descriptor != NULL )
858
4.51k
        {
859
4.51k
          last_store_descriptor->store_block_list_offset       = store_descriptor->store_block_list_offset;
860
4.51k
          last_store_descriptor->store_header_offset           = store_descriptor->store_header_offset;
861
4.51k
          last_store_descriptor->store_block_range_list_offset = store_descriptor->store_block_range_list_offset;
862
4.51k
          last_store_descriptor->store_bitmap_offset           = store_descriptor->store_bitmap_offset;
863
4.51k
          last_store_descriptor->store_previous_bitmap_offset  = store_descriptor->store_previous_bitmap_offset;
864
4.51k
          last_store_descriptor->has_in_volume_store_data      = 1;
865
4.51k
        }
866
#if defined( HAVE_DEBUG_OUTPUT )
867
        else
868
        {
869
          libcnotify_printf(
870
           "%s: missing last store descriptor.\n",
871
           function );
872
        }
873
#endif
874
5.48k
      }
875
147k
      catalog_block_offset += (size_t) 128;
876
147k
    }
877
791
    file_offset = next_offset;
878
791
  }
879
2.44k
  while( file_offset != 0 );
880
881
747
  if( store_descriptor != NULL )
882
731
  {
883
731
    if( libvshadow_store_descriptor_free(
884
731
         &store_descriptor,
885
731
         error ) != 1 )
886
0
    {
887
0
      libcerror_error_set(
888
0
       error,
889
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
890
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
891
0
       "%s: unable to free store descriptor.",
892
0
       function );
893
894
0
      goto on_error;
895
0
    }
896
731
  }
897
747
  if( libvshadow_block_tree_free(
898
747
       &catalog_block_tree,
899
747
       (int (*)(intptr_t **, libcerror_error_t **)) &libvshadow_block_descriptor_free,
900
747
       error ) != 1 )
901
0
  {
902
0
    libcerror_error_set(
903
0
     error,
904
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
905
0
     LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
906
0
     "%s: unable to free catalog block tree.",
907
0
     function );
908
909
0
    goto on_error;
910
0
  }
911
747
  memory_free(
912
747
   catalog_block_data );
913
914
747
  *volume_size = safe_volume_size;
915
916
747
  return( 1 );
917
918
1.70k
on_error:
919
1.70k
  if( store_descriptor != NULL )
920
1.07k
  {
921
1.07k
    libvshadow_store_descriptor_free(
922
1.07k
     &store_descriptor,
923
1.07k
     NULL );
924
1.07k
  }
925
1.70k
  if( catalog_block_tree != NULL )
926
1.70k
  {
927
1.70k
    libvshadow_block_tree_free(
928
1.70k
     &catalog_block_tree,
929
1.70k
     (int (*)(intptr_t **, libcerror_error_t **)) &libvshadow_block_descriptor_free,
930
1.70k
     NULL );
931
1.70k
  }
932
1.70k
  if( catalog_block_data != NULL )
933
1.70k
  {
934
1.70k
    memory_free(
935
1.70k
     catalog_block_data );
936
1.70k
  }
937
1.70k
  return( -1 );
938
747
}
939
940
/* Reads the catalog header
941
 * Returns 1 if successful or -1 on error
942
 */
943
int libvshadow_io_handle_read_catalog_header_data(
944
     libvshadow_io_handle_t *io_handle,
945
     const uint8_t *data,
946
     size_t data_size,
947
     off64_t *next_offset,
948
     libcerror_error_t **error )
949
2.16k
{
950
2.16k
  static char *function     = "libvshadow_io_handle_read_catalog_header_data";
951
2.16k
  uint64_t safe_next_offset = 0;
952
2.16k
  uint32_t record_type      = 0;
953
2.16k
  uint32_t version          = 0;
954
955
#if defined( HAVE_DEBUG_OUTPUT )
956
  uint64_t value_64bit      = 0;
957
#endif
958
959
2.16k
  if( io_handle == NULL )
960
0
  {
961
0
    libcerror_error_set(
962
0
     error,
963
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
964
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
965
0
     "%s: invalid IO handle.",
966
0
     function );
967
968
0
    return( -1 );
969
0
  }
970
2.16k
  if( data == NULL )
971
0
  {
972
0
    libcerror_error_set(
973
0
     error,
974
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
975
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
976
0
     "%s: invalid data.",
977
0
     function );
978
979
0
    return( -1 );
980
0
  }
981
2.16k
  if( data_size < sizeof( vshadow_catalog_header_t ) )
982
0
  {
983
0
    libcerror_error_set(
984
0
     error,
985
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
986
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
987
0
     "%s: invalid data size value too small.",
988
0
     function );
989
990
0
    return( -1 );
991
0
  }
992
2.16k
  if( data_size > (size_t) SSIZE_MAX )
993
0
  {
994
0
    libcerror_error_set(
995
0
     error,
996
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
997
0
     LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
998
0
     "%s: invalid data size value exceeds maximum.",
999
0
     function );
1000
1001
0
    return( -1 );
1002
0
  }
1003
2.16k
  if( next_offset == NULL )
1004
0
  {
1005
0
    libcerror_error_set(
1006
0
     error,
1007
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1008
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1009
0
     "%s: invalid next offset.",
1010
0
     function );
1011
1012
0
    return( -1 );
1013
0
  }
1014
#if defined( HAVE_DEBUG_OUTPUT )
1015
  if( libcnotify_verbose != 0 )
1016
  {
1017
    libcnotify_printf(
1018
     "%s: catalog header data:\n",
1019
     function );
1020
    libcnotify_print_data(
1021
     data,
1022
     data_size,
1023
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
1024
  }
1025
#endif
1026
2.16k
  if( memory_compare(
1027
2.16k
       ( (vshadow_catalog_header_t *) data )->identifier,
1028
2.16k
       vshadow_vss_identifier,
1029
2.16k
       8 ) != 0 )
1030
32
  {
1031
32
    libcerror_error_set(
1032
32
     error,
1033
32
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1034
32
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1035
32
     "%s: invalid catalog header identifier.",
1036
32
     function );
1037
1038
32
    return( -1 );
1039
32
  }
1040
2.13k
  byte_stream_copy_to_uint32_little_endian(
1041
2.13k
   ( (vshadow_catalog_header_t *) data )->version,
1042
2.13k
   version );
1043
1044
2.13k
  byte_stream_copy_to_uint32_little_endian(
1045
2.13k
   ( (vshadow_catalog_header_t *) data )->record_type,
1046
2.13k
   record_type );
1047
1048
2.13k
  byte_stream_copy_to_uint64_little_endian(
1049
2.13k
   ( (vshadow_catalog_header_t *) data )->next_offset,
1050
2.13k
   safe_next_offset );
1051
1052
#if defined( HAVE_DEBUG_OUTPUT )
1053
  if( libcnotify_verbose != 0 )
1054
  {
1055
    if( libvshadow_debug_print_guid_value(
1056
         function,
1057
         "identifier\t\t",
1058
         ( (vshadow_catalog_header_t *) data )->identifier,
1059
         16,
1060
         LIBFGUID_ENDIAN_LITTLE,
1061
         LIBFGUID_STRING_FORMAT_FLAG_USE_LOWER_CASE,
1062
         error ) != 1 )
1063
    {
1064
      libcerror_error_set(
1065
       error,
1066
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1067
       LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
1068
       "%s: unable to print GUID value.",
1069
       function );
1070
1071
      return( -1 );
1072
    }
1073
    libcnotify_printf(
1074
     "%s: version\t\t\t: %" PRIu32 "\n",
1075
     function,
1076
     version );
1077
1078
    libcnotify_printf(
1079
     "%s: record type\t\t: %" PRIu32 "\n",
1080
     function,
1081
     record_type );
1082
1083
    byte_stream_copy_to_uint64_little_endian(
1084
     ( (vshadow_catalog_header_t *) data )->relative_offset,
1085
     value_64bit );
1086
    libcnotify_printf(
1087
     "%s: relative offset\t\t: 0x%08" PRIx64 "\n",
1088
     function,
1089
     value_64bit );
1090
1091
    byte_stream_copy_to_uint64_little_endian(
1092
     ( (vshadow_catalog_header_t *) data )->offset,
1093
     value_64bit );
1094
    libcnotify_printf(
1095
     "%s: offset\t\t\t: 0x%08" PRIx64 "\n",
1096
     function,
1097
     value_64bit );
1098
1099
    libcnotify_printf(
1100
     "%s: next offset\t\t: 0x%08" PRIx64 "\n",
1101
     function,
1102
     safe_next_offset );
1103
1104
    libcnotify_printf(
1105
     "%s: unknown1:\n",
1106
     function );
1107
    libcnotify_print_data(
1108
     ( (vshadow_catalog_header_t *) data )->unknown1,
1109
     80,
1110
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
1111
  }
1112
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
1113
1114
2.13k
  if( version != 1 )
1115
85
  {
1116
85
    libcerror_error_set(
1117
85
     error,
1118
85
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1119
85
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1120
85
     "%s: unsupported version: %" PRIu32 ".",
1121
85
     function,
1122
85
     version );
1123
1124
85
    return( -1 );
1125
85
  }
1126
2.04k
  if( record_type != LIBVSHADOW_RECORD_TYPE_CATALOG )
1127
85
  {
1128
85
    libcerror_error_set(
1129
85
     error,
1130
85
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1131
85
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1132
85
     "%s: unsupported record type: %" PRIu32 ".",
1133
85
     function,
1134
85
     version );
1135
1136
85
    return( -1 );
1137
85
  }
1138
1.96k
  if( safe_next_offset > (uint64_t) INT64_MAX )
1139
118
  {
1140
118
    libcerror_error_set(
1141
118
     error,
1142
118
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1143
118
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1144
118
     "%s: invalid next offset value out of bounds.",
1145
118
     function,
1146
118
     version );
1147
1148
118
    return( -1 );
1149
118
  }
1150
1.84k
  *next_offset = (off64_t) safe_next_offset;
1151
1152
1.84k
  return( 1 );
1153
1.96k
}
1154