Coverage Report

Created: 2026-05-30 07:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libfsext/libfsext/libfsext_extents.c
Line
Count
Source
1
/*
2
 * Extents functions
3
 *
4
 * Copyright (C) 2010-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 <memory.h>
24
#include <types.h>
25
26
#include "libfsext_definitions.h"
27
#include "libfsext_extent.h"
28
#include "libfsext_extent_index.h"
29
#include "libfsext_extents.h"
30
#include "libfsext_extents_footer.h"
31
#include "libfsext_extents_header.h"
32
#include "libfsext_io_handle.h"
33
#include "libfsext_libbfio.h"
34
#include "libfsext_libcdata.h"
35
#include "libfsext_libcerror.h"
36
#include "libfsext_libcnotify.h"
37
38
/* Retrieves the last extent
39
 * Returns 1 if successful or -1 on error
40
 */
41
int libfsext_extents_get_last_extent(
42
     libcdata_array_t *extents_array,
43
     libfsext_extent_t **last_extent,
44
     libcerror_error_t **error )
45
10.3k
{
46
10.3k
  static char *function = "libfsext_extents_get_last_extent";
47
10.3k
  int number_of_extents = 0;
48
49
10.3k
  if( last_extent == NULL )
50
0
  {
51
0
    libcerror_error_set(
52
0
     error,
53
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
54
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
55
0
     "%s: invalid last extent.",
56
0
     function );
57
58
0
    return( -1 );
59
0
  }
60
10.3k
  if( libcdata_array_get_number_of_entries(
61
10.3k
       extents_array,
62
10.3k
       &number_of_extents,
63
10.3k
       error ) != 1 )
64
0
  {
65
0
    libcerror_error_set(
66
0
     error,
67
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
68
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
69
0
     "%s: unable to retrieve number of extents.",
70
0
     function );
71
72
0
    return( -1 );
73
0
  }
74
10.3k
  if( number_of_extents == 0 )
75
2.05k
  {
76
2.05k
    *last_extent = NULL;
77
2.05k
  }
78
8.34k
  else if( libcdata_array_get_entry_by_index(
79
8.34k
            extents_array,
80
8.34k
            number_of_extents - 1,
81
8.34k
            (intptr_t **) last_extent,
82
8.34k
            error ) != 1 )
83
0
  {
84
0
    libcerror_error_set(
85
0
     error,
86
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
87
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
88
0
     "%s: unable to retrieve extent: %d.",
89
0
     function,
90
0
     number_of_extents - 1 );
91
92
0
    return( -1 );
93
0
  }
94
10.3k
  return( 1 );
95
10.3k
}
96
97
/* Reads the inode data reference
98
 * Returns 1 if successful or -1 on error
99
 */
100
int libfsext_extents_read_inode_data_reference(
101
     libcdata_array_t *extents_array,
102
     libfsext_io_handle_t *io_handle,
103
     libbfio_handle_t *file_io_handle,
104
     uint64_t number_of_blocks,
105
     const uint8_t *data,
106
     size_t data_size,
107
     libcerror_error_t **error )
108
1.10k
{
109
1.10k
  libfsext_extent_t *last_extent   = NULL;
110
1.10k
  libfsext_extent_t *sparse_extent = NULL;
111
1.10k
  static char *function            = "libfsext_extents_read_inode_data_reference";
112
1.10k
  uint32_t logical_block_number    = 0;
113
1.10k
  int entry_index                  = 0;
114
115
1.10k
  if( libfsext_extents_read_data(
116
1.10k
       extents_array,
117
1.10k
       io_handle,
118
1.10k
       file_io_handle,
119
1.10k
       number_of_blocks,
120
1.10k
       data,
121
1.10k
       data_size,
122
1.10k
       6,
123
1.10k
       error ) == -1 )
124
400
  {
125
400
    libcerror_error_set(
126
400
     error,
127
400
     LIBCERROR_ERROR_DOMAIN_IO,
128
400
     LIBCERROR_IO_ERROR_READ_FAILED,
129
400
     "%s: unable to read extents data.",
130
400
     function );
131
132
400
    goto on_error;
133
400
  }
134
709
  if( libfsext_extents_get_last_extent(
135
709
       extents_array,
136
709
       &last_extent,
137
709
       error ) != 1 )
138
0
  {
139
0
    libcerror_error_set(
140
0
     error,
141
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
142
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
143
0
     "%s: unable to retrieve last extent.",
144
0
     function );
145
146
0
    goto on_error;
147
0
  }
148
709
  if( last_extent != NULL )
149
678
  {
150
678
    logical_block_number = last_extent->logical_block_number + last_extent->number_of_blocks;
151
678
  }
152
709
  if( logical_block_number < number_of_blocks )
153
397
  {
154
397
    if( ( last_extent == NULL )
155
366
     || ( ( last_extent->range_flags & LIBFSEXT_EXTENT_FLAG_IS_SPARSE ) == 0 ) )
156
210
    {
157
210
      if( libfsext_extent_initialize(
158
210
           &sparse_extent,
159
210
           error ) != 1 )
160
0
      {
161
0
        libcerror_error_set(
162
0
         error,
163
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
164
0
         LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
165
0
         "%s: unable to create sparse extent.",
166
0
         function );
167
168
0
        goto on_error;
169
0
      }
170
210
      sparse_extent->logical_block_number = logical_block_number;
171
210
      sparse_extent->range_flags          = LIBFSEXT_EXTENT_FLAG_IS_SPARSE;
172
173
210
      if( libcdata_array_append_entry(
174
210
           extents_array,
175
210
           &entry_index,
176
210
           (intptr_t *) sparse_extent,
177
210
           error ) != 1 )
178
0
      {
179
0
        libcerror_error_set(
180
0
         error,
181
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
182
0
         LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
183
0
         "%s: unable to append sparse extent to array.",
184
0
         function );
185
186
0
        goto on_error;
187
0
      }
188
210
      last_extent   = sparse_extent;
189
210
      sparse_extent = NULL;
190
210
    }
191
397
    last_extent->number_of_blocks += number_of_blocks - logical_block_number;
192
193
#if defined( HAVE_DEBUG_OUTPUT )
194
    if( libcnotify_verbose != 0 )
195
    {
196
      libcnotify_printf(
197
       "%s: logical block number\t: %" PRIu64 "\n",
198
       function,
199
       last_extent->logical_block_number );
200
201
      libcnotify_printf(
202
       "%s: physical block number\t: %" PRIu64 "\n",
203
       function,
204
       last_extent->physical_block_number );
205
206
      libcnotify_printf(
207
       "%s: number of blocks\t\t: %" PRIu64 "\n",
208
       function,
209
       last_extent->number_of_blocks );
210
211
      libcnotify_printf(
212
       "\n" );
213
    }
214
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
215
397
  }
216
709
  return( 1 );
217
218
400
on_error:
219
400
  if( sparse_extent != NULL )
220
0
  {
221
0
    libfsext_extent_free(
222
0
     &sparse_extent,
223
0
     NULL );
224
0
  }
225
400
  libcdata_array_empty(
226
400
   extents_array,
227
400
   (int (*)(intptr_t **, libcerror_error_t **)) &libfsext_extent_free,
228
400
   NULL );
229
230
400
  return( -1 );
231
709
}
232
233
/* Reads the extents data
234
 * Returns 1 if successful or -1 on error
235
 */
236
int libfsext_extents_read_data(
237
     libcdata_array_t *extents_array,
238
     libfsext_io_handle_t *io_handle,
239
     libbfio_handle_t *file_io_handle,
240
     uint64_t number_of_blocks,
241
     const uint8_t *data,
242
     size_t data_size,
243
     uint16_t parent_depth,
244
     libcerror_error_t **error )
245
9.80k
{
246
9.80k
  libfsext_extent_t *extent                 = NULL;
247
9.80k
  libfsext_extent_t *last_extent            = NULL;
248
9.80k
  libfsext_extent_t *sparse_extent          = NULL;
249
9.80k
  libfsext_extent_index_t *extent_index     = NULL;
250
9.80k
  libfsext_extents_footer_t *extents_footer = NULL;
251
9.80k
  libfsext_extents_header_t *extents_header = NULL;
252
9.80k
  static char *function                     = "libfsext_extents_read_data";
253
9.80k
  size_t data_offset                        = 0;
254
9.80k
  off64_t extents_block_offset              = 0;
255
9.80k
  uint32_t extent_descriptor_index          = 0;
256
9.80k
  uint32_t logical_block_number             = 0;
257
9.80k
  int entry_index                           = 0;
258
259
9.80k
  if( io_handle == NULL )
260
0
  {
261
0
    libcerror_error_set(
262
0
     error,
263
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
264
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
265
0
     "%s: invalid IO handle.",
266
0
     function );
267
268
0
    return( -1 );
269
0
  }
270
9.80k
  if( io_handle->block_size == 0 )
271
0
  {
272
0
    libcerror_error_set(
273
0
     error,
274
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
275
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
276
0
     "%s: invalid IO handle - block size value out of bounds.",
277
0
     function );
278
279
0
    return( -1 );
280
0
  }
281
9.80k
  if( data == NULL )
282
0
  {
283
0
    libcerror_error_set(
284
0
     error,
285
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
286
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
287
0
     "%s: invalid data.",
288
0
     function );
289
290
0
    return( -1 );
291
0
  }
292
9.80k
  if( ( data_size < 12 )
293
9.80k
   || ( data_size > (size_t) SSIZE_MAX ) )
294
0
  {
295
0
    libcerror_error_set(
296
0
     error,
297
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
298
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
299
0
     "%s: invalid data size value out of bounds.",
300
0
     function );
301
302
0
    return( -1 );
303
0
  }
304
9.80k
  if( libfsext_extents_header_initialize(
305
9.80k
       &extents_header,
306
9.80k
       error ) != 1 )
307
0
  {
308
0
    libcerror_error_set(
309
0
     error,
310
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
311
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
312
0
     "%s: unable to create extents header.",
313
0
     function );
314
315
0
    goto on_error;
316
0
  }
317
9.80k
  if( libfsext_extents_header_read_data(
318
9.80k
       extents_header,
319
9.80k
       data,
320
9.80k
       12,
321
9.80k
       error ) == -1 )
322
90
  {
323
90
    libcerror_error_set(
324
90
     error,
325
90
     LIBCERROR_ERROR_DOMAIN_IO,
326
90
     LIBCERROR_IO_ERROR_READ_FAILED,
327
90
     "%s: unable to read extents header.",
328
90
     function );
329
330
90
    goto on_error;
331
90
  }
332
9.71k
  data_offset = 12;
333
334
9.71k
  if( extents_header->depth >= parent_depth )
335
8
  {
336
8
    libcerror_error_set(
337
8
     error,
338
8
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
339
8
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
340
8
     "%s: invalid depth value out of bounds.",
341
8
     function );
342
343
8
    goto on_error;
344
8
  }
345
9.70k
  if( extents_header->number_of_extents > ( ( data_size - data_offset ) / 12 ) )
346
20
  {
347
20
    libcerror_error_set(
348
20
     error,
349
20
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
350
20
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
351
20
     "%s: invalid number of extents value out of bounds.",
352
20
     function );
353
354
20
    goto on_error;
355
20
  }
356
9.68k
  if( libfsext_extents_get_last_extent(
357
9.68k
       extents_array,
358
9.68k
       &last_extent,
359
9.68k
       error ) != 1 )
360
0
  {
361
0
    libcerror_error_set(
362
0
     error,
363
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
364
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
365
0
     "%s: unable to retrieve last extent.",
366
0
     function );
367
368
0
    goto on_error;
369
0
  }
370
9.68k
  if( last_extent != NULL )
371
7.66k
  {
372
#if defined( HAVE_DEBUG_OUTPUT )
373
    if( libcnotify_verbose != 0 )
374
    {
375
      libcnotify_printf(
376
       "%s: logical block number\t\t\t: %" PRIu64 "\n",
377
       function,
378
       last_extent->logical_block_number );
379
380
      libcnotify_printf(
381
       "%s: physical block number\t\t\t: %" PRIu64 "\n",
382
       function,
383
       last_extent->physical_block_number );
384
385
      libcnotify_printf(
386
       "%s: number of blocks\t\t\t: %" PRIu64 "\n",
387
       function,
388
       last_extent->number_of_blocks );
389
390
      libcnotify_printf(
391
       "\n" );
392
    }
393
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
394
395
7.66k
    logical_block_number = last_extent->logical_block_number + last_extent->number_of_blocks;
396
7.66k
  }
397
9.68k
  for( extent_descriptor_index = 0;
398
2.56M
       extent_descriptor_index < extents_header->number_of_extents;
399
2.55M
       extent_descriptor_index++ )
400
2.55M
  {
401
2.55M
    if( data_offset > ( data_size - 12 ) )
402
0
    {
403
0
      libcerror_error_set(
404
0
       error,
405
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
406
0
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
407
0
       "%s: invalid data size value out of bounds.",
408
0
       function );
409
410
0
      goto on_error;
411
0
    }
412
2.55M
    if( extents_header->depth == 0 )
413
2.54M
    {
414
2.54M
      if( libfsext_extent_initialize(
415
2.54M
           &extent,
416
2.54M
           error ) != 1 )
417
0
      {
418
0
        libcerror_error_set(
419
0
         error,
420
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
421
0
         LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
422
0
         "%s: unable to create extent.",
423
0
         function );
424
425
0
        goto on_error;
426
0
      }
427
2.54M
      if( libfsext_extent_read_data(
428
2.54M
           extent,
429
2.54M
           &( data[ data_offset ] ),
430
2.54M
           12,
431
2.54M
           error ) == -1 )
432
0
      {
433
0
        libcerror_error_set(
434
0
         error,
435
0
         LIBCERROR_ERROR_DOMAIN_IO,
436
0
         LIBCERROR_IO_ERROR_READ_FAILED,
437
0
         "%s: unable to read extent.",
438
0
         function );
439
440
0
        goto on_error;
441
0
      }
442
2.54M
      data_offset += 12;
443
444
2.54M
      if( extent->number_of_blocks == 0 )
445
1.16M
      {
446
1.16M
        if( libfsext_extent_free(
447
1.16M
             &extent,
448
1.16M
             error ) != 1 )
449
0
        {
450
0
          libcerror_error_set(
451
0
           error,
452
0
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
453
0
           LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
454
0
           "%s: unable to free extent.",
455
0
           function );
456
457
0
          goto on_error;
458
0
        }
459
1.16M
        continue;
460
1.16M
      }
461
1.37M
      if( extent->logical_block_number > logical_block_number )
462
815k
      {
463
815k
        if( libfsext_extent_initialize(
464
815k
             &sparse_extent,
465
815k
             error ) != 1 )
466
0
        {
467
0
          libcerror_error_set(
468
0
           error,
469
0
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
470
0
           LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
471
0
           "%s: unable to create sparse extent.",
472
0
           function );
473
474
0
          goto on_error;
475
0
        }
476
815k
        sparse_extent->logical_block_number = logical_block_number;
477
815k
        sparse_extent->number_of_blocks     = extent->logical_block_number - logical_block_number;
478
815k
        sparse_extent->range_flags          = LIBFSEXT_EXTENT_FLAG_IS_SPARSE;
479
480
815k
        if( libcdata_array_append_entry(
481
815k
             extents_array,
482
815k
             &entry_index,
483
815k
             (intptr_t *) sparse_extent,
484
815k
             error ) != 1 )
485
0
        {
486
0
          libcerror_error_set(
487
0
           error,
488
0
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
489
0
           LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
490
0
           "%s: unable to append sparse extent to array.",
491
0
           function );
492
493
0
          goto on_error;
494
0
        }
495
815k
        sparse_extent = NULL;
496
815k
      }
497
1.37M
      logical_block_number = extent->logical_block_number + extent->number_of_blocks;
498
499
1.37M
      if( libcdata_array_append_entry(
500
1.37M
           extents_array,
501
1.37M
           &entry_index,
502
1.37M
           (intptr_t *) extent,
503
1.37M
           error ) != 1 )
504
0
      {
505
0
        libcerror_error_set(
506
0
         error,
507
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
508
0
         LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
509
0
         "%s: unable to append data extent to array.",
510
0
         function );
511
512
0
        goto on_error;
513
0
      }
514
1.37M
      extent = NULL;
515
1.37M
    }
516
8.97k
    else
517
8.97k
    {
518
8.97k
      if( libfsext_extent_index_initialize(
519
8.97k
           &extent_index,
520
8.97k
           error ) != 1 )
521
0
      {
522
0
        libcerror_error_set(
523
0
         error,
524
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
525
0
         LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
526
0
         "%s: unable to create extent index.",
527
0
         function );
528
529
0
        goto on_error;
530
0
      }
531
8.97k
      if( libfsext_extent_index_read_data(
532
8.97k
           extent_index,
533
8.97k
           &( data[ data_offset ] ),
534
8.97k
           12,
535
8.97k
           error ) == -1 )
536
0
      {
537
0
        libcerror_error_set(
538
0
         error,
539
0
         LIBCERROR_ERROR_DOMAIN_IO,
540
0
         LIBCERROR_IO_ERROR_READ_FAILED,
541
0
         "%s: unable to read extent index.",
542
0
         function );
543
544
0
        goto on_error;
545
0
      }
546
8.97k
      data_offset += 12;
547
548
8.97k
      if( extent_index->physical_block_number > ( (uint64_t) INT64_MAX / io_handle->block_size ) )
549
96
      {
550
96
        libcerror_error_set(
551
96
         error,
552
96
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
553
96
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
554
96
         "%s: invalid extent index - physical block number value out of bounds.",
555
96
         function );
556
557
96
        goto on_error;
558
96
      }
559
8.88k
      extents_block_offset = (off64_t) extent_index->physical_block_number * io_handle->block_size;
560
561
8.88k
      if( libfsext_extents_read_file_io_handle(
562
8.88k
           extents_array,
563
8.88k
           io_handle,
564
8.88k
           file_io_handle,
565
8.88k
           number_of_blocks,
566
8.88k
           extents_block_offset,
567
8.88k
           extents_header->depth,
568
8.88k
           error ) == -1 )
569
270
      {
570
270
        libcerror_error_set(
571
270
         error,
572
270
         LIBCERROR_ERROR_DOMAIN_IO,
573
270
         LIBCERROR_IO_ERROR_READ_FAILED,
574
270
         "%s: unable to read extents at depth: %" PRIu16 ".",
575
270
         function,
576
270
         extents_header->depth - 1 );
577
578
270
        goto on_error;
579
270
      }
580
8.61k
      if( libfsext_extent_index_free(
581
8.61k
           &extent_index,
582
8.61k
           error ) != 1 )
583
0
      {
584
0
        libcerror_error_set(
585
0
         error,
586
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
587
0
         LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
588
0
         "%s: unable to free extent index.",
589
0
         function );
590
591
0
        goto on_error;
592
0
      }
593
8.61k
    }
594
2.55M
  }
595
9.32k
  if( libfsext_extents_header_free(
596
9.32k
       &extents_header,
597
9.32k
       error ) != 1 )
598
0
  {
599
0
    libcerror_error_set(
600
0
     error,
601
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
602
0
     LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
603
0
     "%s: unable to free extents header.",
604
0
     function );
605
606
0
    goto on_error;
607
0
  }
608
9.32k
  if( data_offset <= ( data_size - 4 ) )
609
8.81k
  {
610
    /* Note that the extents in the inode->data_reference do not have an extents footer
611
     */
612
8.81k
    if( libfsext_extents_footer_initialize(
613
8.81k
         &extents_footer,
614
8.81k
         error ) != 1 )
615
0
    {
616
0
      libcerror_error_set(
617
0
       error,
618
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
619
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
620
0
       "%s: unable to create extents footer.",
621
0
       function );
622
623
0
      goto on_error;
624
0
    }
625
8.81k
    if( libfsext_extents_footer_read_data(
626
8.81k
         extents_footer,
627
8.81k
         &( data[ data_offset ] ),
628
8.81k
         4,
629
8.81k
         error ) == -1 )
630
0
    {
631
0
      libcerror_error_set(
632
0
       error,
633
0
       LIBCERROR_ERROR_DOMAIN_IO,
634
0
       LIBCERROR_IO_ERROR_READ_FAILED,
635
0
       "%s: unable to read extents footer.",
636
0
       function );
637
638
0
      goto on_error;
639
0
    }
640
8.81k
    if( libfsext_extents_footer_free(
641
8.81k
         &extents_footer,
642
8.81k
         error ) != 1 )
643
0
    {
644
0
      libcerror_error_set(
645
0
       error,
646
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
647
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
648
0
       "%s: unable to free extents footer.",
649
0
       function );
650
651
0
      goto on_error;
652
0
    }
653
8.81k
  }
654
9.32k
  return( 1 );
655
656
484
on_error:
657
484
  if( extents_footer != NULL )
658
0
  {
659
0
    libfsext_extents_footer_free(
660
0
     &extents_footer,
661
0
     NULL );
662
0
  }
663
484
  if( extent_index != NULL )
664
366
  {
665
366
    libfsext_extent_index_free(
666
366
     &extent_index,
667
366
     NULL );
668
366
  }
669
484
  if( sparse_extent != NULL )
670
0
  {
671
0
    libfsext_extent_free(
672
0
     &sparse_extent,
673
0
     NULL );
674
0
  }
675
484
  if( extent != NULL )
676
0
  {
677
0
    libfsext_extent_free(
678
0
     &extent,
679
0
     NULL );
680
0
  }
681
484
  if( extents_header != NULL )
682
484
  {
683
484
    libfsext_extents_header_free(
684
484
     &extents_header,
685
484
     NULL );
686
484
  }
687
484
  return( -1 );
688
9.32k
}
689
690
/* Reads the extents data
691
 * Returns 1 if successful or -1 on error
692
 */
693
int libfsext_extents_read_file_io_handle(
694
     libcdata_array_t *extents_array,
695
     libfsext_io_handle_t *io_handle,
696
     libbfio_handle_t *file_io_handle,
697
     uint64_t number_of_blocks,
698
     off64_t file_offset,
699
     uint16_t parent_depth,
700
     libcerror_error_t **error )
701
8.88k
{
702
8.88k
  uint8_t *data         = NULL;
703
8.88k
  static char *function = "libfsext_extents_read_file_io_handle";
704
8.88k
  ssize_t read_count    = 0;
705
706
8.88k
  if( io_handle == NULL )
707
0
  {
708
0
    libcerror_error_set(
709
0
     error,
710
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
711
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
712
0
     "%s: invalid IO handle.",
713
0
     function );
714
715
0
    return( -1 );
716
0
  }
717
8.88k
  if( ( io_handle->block_size == 0 )
718
8.88k
   || ( io_handle->block_size > (size_t) MEMORY_MAXIMUM_ALLOCATION_SIZE ) )
719
0
  {
720
0
    libcerror_error_set(
721
0
     error,
722
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
723
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
724
0
     "%s: invalid IO handle - block size value out of bounds.",
725
0
     function );
726
727
0
    return( -1 );
728
0
  }
729
8.88k
  data = (uint8_t *) memory_allocate(
730
8.88k
                      sizeof( uint8_t ) * (size_t) io_handle->block_size );
731
732
8.88k
  if( data == NULL )
733
0
  {
734
0
    libcerror_error_set(
735
0
     error,
736
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
737
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
738
0
     "%s: unable to create extents data.",
739
0
     function );
740
741
0
    goto on_error;
742
0
  }
743
#if defined( HAVE_DEBUG_OUTPUT )
744
  if( libcnotify_verbose != 0 )
745
  {
746
    libcnotify_printf(
747
     "%s: reading extents data of size: %" PRIu32 " at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
748
     function,
749
     io_handle->block_size,
750
     file_offset,
751
     file_offset );
752
  }
753
#endif
754
8.88k
  read_count = libbfio_handle_read_buffer_at_offset(
755
8.88k
                file_io_handle,
756
8.88k
                data,
757
8.88k
                (size_t) io_handle->block_size,
758
8.88k
                file_offset,
759
8.88k
                error );
760
761
8.88k
  if( read_count != (ssize_t) io_handle->block_size )
762
186
  {
763
186
    libcerror_error_set(
764
186
     error,
765
186
     LIBCERROR_ERROR_DOMAIN_IO,
766
186
     LIBCERROR_IO_ERROR_READ_FAILED,
767
186
     "%s: unable to read extents data at offset: %" PRIi64 " (0x%08" PRIx64 ").",
768
186
     function,
769
186
     file_offset,
770
186
     file_offset );
771
772
186
    goto on_error;
773
186
  }
774
8.69k
  if( libfsext_extents_read_data(
775
8.69k
       extents_array,
776
8.69k
       io_handle,
777
8.69k
       file_io_handle,
778
8.69k
       number_of_blocks,
779
8.69k
       data,
780
8.69k
       (size_t) io_handle->block_size,
781
8.69k
       parent_depth,
782
8.69k
       error ) != 1 )
783
84
  {
784
84
    libcerror_error_set(
785
84
     error,
786
84
     LIBCERROR_ERROR_DOMAIN_IO,
787
84
     LIBCERROR_IO_ERROR_READ_FAILED,
788
84
     "%s: unable to read extents data at offset: %" PRIi64 " (0x%08" PRIx64 ").",
789
84
     function,
790
84
     file_offset,
791
84
     file_offset );
792
793
84
    goto on_error;
794
84
  }
795
8.61k
  memory_free(
796
8.61k
   data );
797
798
8.61k
  return( 1 );
799
800
270
on_error:
801
270
  if( data != NULL )
802
270
  {
803
270
    memory_free(
804
270
     data );
805
270
  }
806
270
  return( -1 );
807
8.69k
}
808