Coverage Report

Created: 2025-06-24 07:14

/src/libfsxfs/libfsxfs/libfsxfs_attributes.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * (Extended) attributes functions
3
 *
4
 * Copyright (C) 2020-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 <types.h>
24
25
#include "libfsxfs_attribute_values.h"
26
#include "libfsxfs_attributes.h"
27
#include "libfsxfs_attributes_leaf_block_header.h"
28
#include "libfsxfs_attributes_table.h"
29
#include "libfsxfs_block_data_handle.h"
30
#include "libfsxfs_data_stream.h"
31
#include "libfsxfs_debug.h"
32
#include "libfsxfs_definitions.h"
33
#include "libfsxfs_extent.h"
34
#include "libfsxfs_file_system_block.h"
35
#include "libfsxfs_inode.h"
36
#include "libfsxfs_io_handle.h"
37
#include "libfsxfs_libbfio.h"
38
#include "libfsxfs_libcdata.h"
39
#include "libfsxfs_libcerror.h"
40
#include "libfsxfs_libcnotify.h"
41
#include "libfsxfs_libfdata.h"
42
43
#include "fsxfs_attributes_block.h"
44
#include "fsxfs_file_system_block.h"
45
46
/* Reads the attributes branch values
47
 * Returns 1 if successful or -1 on error
48
 */
49
int libfsxfs_attributes_read_branch_values(
50
     libfsxfs_io_handle_t *io_handle,
51
     libbfio_handle_t *file_io_handle,
52
     libfsxfs_inode_t *inode,
53
     const uint8_t *data,
54
     size_t data_size,
55
     libcdata_array_t *extended_attributes_array,
56
     int recursion_depth,
57
     libcerror_error_t **error )
58
0
{
59
0
  static char *function          = "libfsxfs_attributes_read_branch_values";
60
0
  size_t branch_header_data_size = 0;
61
0
  size_t data_offset             = 0;
62
0
  size_t entries_data_size       = 0;
63
0
  uint32_t sub_block_number      = 0;
64
0
  uint16_t block_entry_index     = 0;
65
0
  uint16_t number_of_entries     = 0;
66
67
#if defined( HAVE_DEBUG_OUTPUT )
68
  uint32_t value_32bit           = 0;
69
  uint16_t value_16bit           = 0;
70
#endif
71
72
0
  if( io_handle == NULL )
73
0
  {
74
0
    libcerror_error_set(
75
0
     error,
76
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
77
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
78
0
     "%s: invalid IO handle.",
79
0
     function );
80
81
0
    return( -1 );
82
0
  }
83
0
  if( io_handle->format_version == 5 )
84
0
  {
85
0
    data_offset             = sizeof( fsxfs_file_system_block_header_v3_t );
86
0
    branch_header_data_size = sizeof( fsxfs_attributes_branch_block_header_v3_t );
87
0
  }
88
0
  else
89
0
  {
90
0
    data_offset             = sizeof( fsxfs_file_system_block_header_v2_t );
91
0
    branch_header_data_size = sizeof( fsxfs_attributes_branch_block_header_v2_t );
92
0
  }
93
0
  if( ( data_offset >= data_size )
94
0
   || ( branch_header_data_size > ( data_size - data_offset ) ) )
95
0
  {
96
0
    libcerror_error_set(
97
0
     error,
98
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
99
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
100
0
     "%s: invalid data size value out of bounds.",
101
0
     function );
102
103
0
    return( -1 );
104
0
  }
105
#if defined( HAVE_DEBUG_OUTPUT )
106
  if( libcnotify_verbose != 0 )
107
  {
108
    libcnotify_printf(
109
     "%s: branch header data:\n",
110
     function );
111
    libcnotify_print_data(
112
     &( data[ data_offset ] ),
113
     branch_header_data_size,
114
     0 );
115
  }
116
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
117
118
0
    byte_stream_copy_to_uint16_big_endian(
119
0
     ( (fsxfs_attributes_branch_block_header_v2_t *) &( data[ data_offset ] ) )->number_of_entries,
120
0
     number_of_entries );
121
122
#if defined( HAVE_DEBUG_OUTPUT )
123
    if( libcnotify_verbose != 0 )
124
    {
125
      libcnotify_printf(
126
       "%s: number of entries\t\t: %" PRIu16 "\n",
127
       function,
128
       number_of_entries );
129
130
      byte_stream_copy_to_uint16_big_endian(
131
       ( (fsxfs_attributes_branch_block_header_v2_t *) &( data[ data_offset ] ) )->node_level,
132
       value_16bit );
133
      libcnotify_printf(
134
       "%s: node level\t\t\t: %" PRIu16 "\n",
135
       function,
136
       value_16bit );
137
138
      if( io_handle->format_version == 5 )
139
      {
140
        byte_stream_copy_to_uint32_big_endian(
141
         ( (fsxfs_attributes_branch_block_header_v3_t *) &( data[ data_offset ] ) )->unknown1,
142
         value_32bit );
143
        libcnotify_printf(
144
         "%s: unknown1\t\t\t: 0x%08" PRIx32 "\n",
145
         function,
146
         value_32bit );
147
      }
148
      libcnotify_printf(
149
       "\n" );
150
    }
151
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
152
153
0
  data_offset += branch_header_data_size;
154
155
0
  entries_data_size = sizeof( fsxfs_attributes_branch_block_entry_t ) * number_of_entries;
156
157
0
  if( entries_data_size > ( data_size - data_offset ) )
158
0
  {
159
0
    libcerror_error_set(
160
0
     error,
161
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
162
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
163
0
     "%s: invalid number of entries value out of bounds.",
164
0
     function );
165
166
0
    return( -1 );
167
0
  }
168
#if defined( HAVE_DEBUG_OUTPUT )
169
  if( libcnotify_verbose != 0 )
170
  {
171
    libcnotify_printf(
172
     "%s: attribute branch entries data:\n",
173
     function );
174
    libcnotify_print_data(
175
     &( data[ data_offset ] ),
176
     entries_data_size,
177
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
178
  }
179
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
180
181
0
  for( block_entry_index = 0;
182
0
       block_entry_index < number_of_entries;
183
0
       block_entry_index++ )
184
0
  {
185
0
    byte_stream_copy_to_uint32_big_endian(
186
0
     ( (fsxfs_attributes_branch_block_entry_t *) &( data[ data_offset ] ) )->sub_block_number,
187
0
     sub_block_number );
188
189
#if defined( HAVE_DEBUG_OUTPUT )
190
    if( libcnotify_verbose != 0 )
191
    {
192
      byte_stream_copy_to_uint32_big_endian(
193
       ( (fsxfs_attributes_branch_block_entry_t *) &( data[ data_offset ] ) )->name_hash,
194
       value_32bit );
195
      libcnotify_printf(
196
       "%s: name hash\t\t\t: 0x%08" PRIx32 "\n",
197
       function,
198
       value_32bit );
199
200
      libcnotify_printf(
201
       "%s: sub block number\t\t: %" PRIu32 "\n",
202
       function,
203
       sub_block_number );
204
205
      libcnotify_printf(
206
       "\n" );
207
    }
208
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
209
210
0
    data_offset += sizeof( fsxfs_attributes_branch_block_entry_t );
211
212
0
    if( libfsxfs_attributes_get_from_block(
213
0
         io_handle,
214
0
         file_io_handle,
215
0
         inode,
216
0
         sub_block_number,
217
0
         extended_attributes_array,
218
0
         recursion_depth + 1,
219
0
         error ) != 1 )
220
0
    {
221
0
      libcerror_error_set(
222
0
       error,
223
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
224
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
225
0
       "%s: unable to retrieve extended attributes from attributes block: %" PRIu32 ".",
226
0
       function,
227
0
       sub_block_number );
228
229
0
      return( -1 );
230
0
    }
231
0
  }
232
0
  return( 1 );
233
0
}
234
235
/* Reads the attributes leaf values
236
 * Returns 1 if successful or -1 on error
237
 */
238
int libfsxfs_attributes_read_leaf_values(
239
     libfsxfs_io_handle_t *io_handle,
240
     const uint8_t *data,
241
     size_t data_size,
242
     libcdata_array_t *extended_attributes_array,
243
     libcerror_error_t **error )
244
0
{
245
0
  libfsxfs_attribute_values_t *attribute_values              = NULL;
246
0
  libfsxfs_attributes_leaf_block_header_t *leaf_block_header = NULL;
247
0
  static char *function                                      = "libfsxfs_attributes_read_leaf_values";
248
0
  size_t data_offset                                         = 0;
249
0
  size_t entries_data_end_offset                             = 0;
250
0
  size_t entries_data_size                                   = 0;
251
0
  size_t values_data_size                                    = 0;
252
0
  uint16_t block_entry_index                                 = 0;
253
0
  uint16_t values_offset                                     = 0;
254
0
  uint8_t flags                                              = 0;
255
0
  uint8_t name_size                                          = 0;
256
0
  int entry_index                                            = 0;
257
258
#if defined( HAVE_DEBUG_OUTPUT )
259
  uint32_t value_32bit                                       = 0;
260
#endif
261
262
0
  if( io_handle == NULL )
263
0
  {
264
0
    libcerror_error_set(
265
0
     error,
266
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
267
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
268
0
     "%s: invalid IO handle.",
269
0
     function );
270
271
0
    return( -1 );
272
0
  }
273
0
  if( io_handle->format_version == 5 )
274
0
  {
275
0
    data_offset = sizeof( fsxfs_file_system_block_header_v3_t );
276
0
  }
277
0
  else
278
0
  {
279
0
    data_offset = sizeof( fsxfs_file_system_block_header_v2_t );
280
0
  }
281
0
  if( data_offset >= data_size )
282
0
  {
283
0
    libcerror_error_set(
284
0
     error,
285
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
286
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
287
0
     "%s: invalid data size value out of bounds.",
288
0
     function );
289
290
0
    return( -1 );
291
0
  }
292
0
  if( libfsxfs_attributes_leaf_block_header_initialize(
293
0
       &leaf_block_header,
294
0
       error ) != 1 )
295
0
  {
296
0
    libcerror_error_set(
297
0
     error,
298
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
299
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
300
0
     "%s: unable to initialize attributes leaf block header.",
301
0
     function );
302
303
0
    goto on_error;
304
0
  }
305
0
  if( libfsxfs_attributes_leaf_block_header_read_data(
306
0
       leaf_block_header,
307
0
       io_handle,
308
0
       &( data[ data_offset ] ),
309
0
       data_size - data_offset,
310
0
       error ) != 1 )
311
0
  {
312
0
    libcerror_error_set(
313
0
     error,
314
0
     LIBCERROR_ERROR_DOMAIN_IO,
315
0
     LIBCERROR_IO_ERROR_READ_FAILED,
316
0
     "%s: unable to read attributes leaf block header.",
317
0
     function );
318
319
0
    goto on_error;
320
0
  }
321
0
  if( io_handle->format_version == 5 )
322
0
  {
323
0
    data_offset += sizeof( fsxfs_attributes_leaf_block_header_v3_t );
324
0
  }
325
0
  else
326
0
  {
327
0
    data_offset += sizeof( fsxfs_attributes_leaf_block_header_v2_t );
328
0
  }
329
0
  entries_data_size = sizeof( fsxfs_attributes_leaf_block_entry_t ) * leaf_block_header->number_of_entries;
330
331
0
  if( entries_data_size > ( data_size - data_offset ) )
332
0
  {
333
0
    libcerror_error_set(
334
0
     error,
335
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
336
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
337
0
     "%s: invalid number of entries value out of bounds.",
338
0
     function );
339
340
0
    goto on_error;
341
0
  }
342
#if defined( HAVE_DEBUG_OUTPUT )
343
  if( libcnotify_verbose != 0 )
344
  {
345
    libcnotify_printf(
346
     "%s: attribute leaf entries data:\n",
347
     function );
348
    libcnotify_print_data(
349
     &( data[ data_offset ] ),
350
     entries_data_size,
351
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
352
  }
353
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
354
355
0
  entries_data_end_offset = data_offset + entries_data_size;
356
357
0
  for( block_entry_index = 0;
358
0
       block_entry_index < leaf_block_header->number_of_entries;
359
0
       block_entry_index++ )
360
0
  {
361
0
    byte_stream_copy_to_uint16_big_endian(
362
0
     ( (fsxfs_attributes_leaf_block_entry_t *) &( data[ data_offset ] ) )->values_offset,
363
0
     values_offset );
364
365
0
    flags = ( (fsxfs_attributes_leaf_block_entry_t *) &( data[ data_offset ] ) )->flags;
366
367
#if defined( HAVE_DEBUG_OUTPUT )
368
    if( libcnotify_verbose != 0 )
369
    {
370
      byte_stream_copy_to_uint32_big_endian(
371
       ( (fsxfs_attributes_leaf_block_entry_t *) &( data[ data_offset ] ) )->name_hash,
372
       value_32bit );
373
      libcnotify_printf(
374
       "%s: name hash\t\t\t\t: 0x%08" PRIx32 "\n",
375
       function,
376
       value_32bit );
377
378
      libcnotify_printf(
379
       "%s: values offset\t\t\t: %" PRIu16 "\n",
380
       function,
381
       values_offset );
382
383
      libcnotify_printf(
384
       "%s: flags\t\t\t\t: 0x%02" PRIx8 "\n",
385
       function,
386
       flags );
387
388
      libcnotify_printf(
389
       "%s: unknown1\t\t\t\t: 0x%02" PRIx8 "\n",
390
       function,
391
       ( (fsxfs_attributes_leaf_block_entry_t *) &( data[ data_offset ] ) )->unknown1 );
392
    }
393
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
394
395
0
    data_offset += sizeof( fsxfs_attributes_leaf_block_entry_t );
396
397
0
    if( ( values_offset < entries_data_end_offset )
398
0
     || ( values_offset >= data_size ) )
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 values offset value out of bounds.",
405
0
       function );
406
407
0
      goto on_error;
408
0
    }
409
0
    if( ( flags & 0x01 ) != 0 )
410
0
    {
411
0
      values_data_size = sizeof( fsxfs_attributes_block_values_local_t );
412
0
    }
413
0
    else
414
0
    {
415
0
      values_data_size = sizeof( fsxfs_attributes_block_values_remote_t );
416
0
    }
417
0
    if( values_data_size > ( data_size - values_offset ) )
418
0
    {
419
0
      libcerror_error_set(
420
0
       error,
421
0
       LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
422
0
       LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
423
0
       "%s: invalid values data size value out of bounds.",
424
0
       function );
425
426
0
      goto on_error;
427
0
    }
428
0
    if( ( flags & 0x01 ) != 0 )
429
0
    {
430
0
      name_size = ( (fsxfs_attributes_block_values_local_t *) &( data[ values_offset ] ) )->name_size;
431
0
    }
432
0
    else
433
0
    {
434
0
      name_size = ( (fsxfs_attributes_block_values_remote_t *) &( data[ values_offset ] ) )->name_size;
435
0
    }
436
0
    if( name_size > ( data_size - values_offset - values_data_size ) )
437
0
    {
438
0
      libcerror_error_set(
439
0
       error,
440
0
       LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
441
0
       LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
442
0
       "%s: invalid name size value out of bounds.",
443
0
       function );
444
445
0
      goto on_error;
446
0
    }
447
#if defined( HAVE_DEBUG_OUTPUT )
448
    if( libcnotify_verbose != 0 )
449
    {
450
      libcnotify_printf(
451
       "%s: values data:\n",
452
       function );
453
      libcnotify_print_data(
454
       &( data[ values_offset ] ),
455
       values_data_size + name_size,
456
       LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
457
    }
458
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
459
460
0
    if( libfsxfs_attribute_values_initialize(
461
0
         &attribute_values,
462
0
         error ) != 1 )
463
0
    {
464
0
      libcerror_error_set(
465
0
       error,
466
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
467
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
468
0
       "%s: unable to create attribute: %d values.",
469
0
       function,
470
0
       block_entry_index );
471
472
0
      goto on_error;
473
0
    }
474
0
    if( ( flags & 0x01 ) != 0 )
475
0
    {
476
0
      byte_stream_copy_to_uint16_big_endian(
477
0
       ( (fsxfs_attributes_block_values_local_t *) &( data[ values_offset ] ) )->value_data_size,
478
0
       attribute_values->value_data_size );
479
0
    }
480
0
    else
481
0
    {
482
0
      byte_stream_copy_to_uint32_big_endian(
483
0
       ( (fsxfs_attributes_block_values_remote_t *) &( data[ values_offset ] ) )->value_data_block_number,
484
0
       attribute_values->value_data_block_number );
485
486
0
      byte_stream_copy_to_uint32_big_endian(
487
0
       ( (fsxfs_attributes_block_values_remote_t *) &( data[ values_offset ] ) )->value_data_size,
488
0
       attribute_values->value_data_size );
489
0
    }
490
#if defined( HAVE_DEBUG_OUTPUT )
491
    if( libcnotify_verbose != 0 )
492
    {
493
      if( ( flags & 0x01 ) == 0 )
494
      {
495
        libcnotify_printf(
496
         "%s: value data block number\t\t: %" PRIu32 "\n",
497
         function,
498
         attribute_values->value_data_block_number );
499
      }
500
      libcnotify_printf(
501
       "%s: value data size\t\t\t: %" PRIu32 "\n",
502
       function,
503
       attribute_values->value_data_size );
504
505
      libcnotify_printf(
506
       "%s: name size\t\t\t\t: %" PRIu8 "\n",
507
       function,
508
       name_size );
509
    }
510
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
511
512
0
    values_offset += values_data_size;
513
514
0
    if( name_size > 0 )
515
0
    {
516
0
      if( libfsxfs_attribute_values_set_name(
517
0
           attribute_values,
518
0
           &( data[ values_offset ] ),
519
0
           name_size,
520
0
           flags,
521
0
           error ) != 1 )
522
0
      {
523
0
        libcerror_error_set(
524
0
         error,
525
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
526
0
         LIBCERROR_RUNTIME_ERROR_SET_FAILED,
527
0
         "%s: unable to set name.",
528
0
         function );
529
530
0
        goto on_error;
531
0
      }
532
#if defined( HAVE_DEBUG_OUTPUT )
533
      if( libcnotify_verbose != 0 )
534
      {
535
        if( libfsxfs_debug_print_utf8_string_value(
536
             function,
537
             "name\t\t\t\t",
538
             attribute_values->name,
539
             attribute_values->name_size,
540
             error ) != 1 )
541
        {
542
          libcerror_error_set(
543
           error,
544
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
545
           LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
546
           "%s: unable to print UTF-8 string value.",
547
           function );
548
549
          goto on_error;
550
        }
551
      }
552
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
553
554
0
      values_offset += name_size;
555
0
    }
556
#if defined( HAVE_DEBUG_OUTPUT )
557
    if( libcnotify_verbose != 0 )
558
    {
559
      libcnotify_printf(
560
       "\n" );
561
    }
562
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
563
564
0
    if( ( flags & 0x01 ) != 0 )
565
0
    {
566
0
      if( attribute_values->value_data_size > ( data_size - values_offset ) )
567
0
      {
568
0
        libcerror_error_set(
569
0
         error,
570
0
         LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
571
0
         LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
572
0
         "%s: invalid value data size value out of bounds.",
573
0
         function );
574
575
0
        goto on_error;
576
0
      }
577
#if defined( HAVE_DEBUG_OUTPUT )
578
      if( libcnotify_verbose != 0 )
579
      {
580
        libcnotify_printf(
581
         "%s: value data:\n",
582
         function );
583
        libcnotify_print_data(
584
         &( data[ values_offset ] ),
585
         (size_t) attribute_values->value_data_size,
586
         LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
587
      }
588
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
589
590
0
      if( attribute_values->value_data_size > 0 )
591
0
      {
592
0
        if( libfsxfs_attribute_values_set_value_data(
593
0
             attribute_values,
594
0
             &( data[ values_offset ] ),
595
0
             (size_t) attribute_values->value_data_size,
596
0
             error ) != 1 )
597
0
        {
598
0
          libcerror_error_set(
599
0
           error,
600
0
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
601
0
           LIBCERROR_RUNTIME_ERROR_SET_FAILED,
602
0
           "%s: unable to set value data.",
603
0
           function );
604
605
0
          goto on_error;
606
0
        }
607
0
      }
608
0
    }
609
0
    if( libcdata_array_append_entry(
610
0
         extended_attributes_array,
611
0
         &entry_index,
612
0
         (intptr_t *) attribute_values,
613
0
         error ) != 1 )
614
0
    {
615
0
      libcerror_error_set(
616
0
       error,
617
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
618
0
       LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
619
0
       "%s: unable to append attribute values to extended attributes array.",
620
0
       function );
621
622
0
      goto on_error;
623
0
    }
624
0
    attribute_values = NULL;
625
0
  }
626
0
  if( libfsxfs_attributes_leaf_block_header_free(
627
0
       &leaf_block_header,
628
0
       error ) != 1 )
629
0
  {
630
0
    libcerror_error_set(
631
0
     error,
632
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
633
0
     LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
634
0
     "%s: unable to free attributes leaf block header.",
635
0
     function );
636
637
0
    goto on_error;
638
0
  }
639
0
  return( 1 );
640
641
0
on_error:
642
0
  if( attribute_values != NULL )
643
0
  {
644
0
    libfsxfs_attribute_values_free(
645
0
     &attribute_values,
646
0
     NULL );
647
0
  }
648
0
  if( leaf_block_header != NULL )
649
0
  {
650
0
    libfsxfs_attributes_leaf_block_header_free(
651
0
     &leaf_block_header,
652
0
     NULL );
653
0
  }
654
0
  libcdata_array_empty(
655
0
   extended_attributes_array,
656
0
   (int (*)(intptr_t **, libcerror_error_t **)) &libfsxfs_attribute_values_free,
657
0
   NULL );
658
659
0
  return( -1 );
660
0
}
661
662
/* Retrieves the extended attributes from an attributes block
663
 * Returns 1 if successful or -1 on error
664
 */
665
int libfsxfs_attributes_get_from_block(
666
     libfsxfs_io_handle_t *io_handle,
667
     libbfio_handle_t *file_io_handle,
668
     libfsxfs_inode_t *inode,
669
     uint32_t block_number,
670
     libcdata_array_t *extended_attributes_array,
671
     int recursion_depth,
672
     libcerror_error_t **error )
673
0
{
674
0
  libfsxfs_extent_t *extent                       = NULL;
675
0
  libfsxfs_file_system_block_t *file_system_block = NULL;
676
0
  static char *function                           = "libfsxfs_attributes_get_from_block";
677
0
  off64_t block_offset                            = 0;
678
0
  uint64_t relative_block_number                  = 0;
679
0
  int allocation_group_index                      = 0;
680
0
  int extent_index                                = 0;
681
0
  int number_of_extents                           = 0;
682
683
0
  if( io_handle == NULL )
684
0
  {
685
0
    libcerror_error_set(
686
0
     error,
687
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
688
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
689
0
     "%s: invalid IO handle.",
690
0
     function );
691
692
0
    return( -1 );
693
0
  }
694
0
  if( ( recursion_depth < 0 )
695
0
   || ( recursion_depth > LIBFSXFS_MAXIMUM_RECURSION_DEPTH ) )
696
0
  {
697
0
    libcerror_error_set(
698
0
     error,
699
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
700
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
701
0
     "%s: invalid recursion depth value out of bounds.",
702
0
     function );
703
704
0
    return( -1 );
705
0
  }
706
0
  if( libfsxfs_inode_get_number_of_attributes_extents(
707
0
       inode,
708
0
       &number_of_extents,
709
0
       error ) != 1 )
710
0
  {
711
0
    libcerror_error_set(
712
0
     error,
713
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
714
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
715
0
     "%s: unable to retrieve number of attributes extents.",
716
0
     function );
717
718
0
    goto on_error;
719
0
  }
720
/* TODO optimize this lookup */
721
722
0
  for( extent_index = 0;
723
0
       extent_index < number_of_extents;
724
0
       extent_index++ )
725
0
  {
726
0
    if( libfsxfs_inode_get_attributes_extent_by_index(
727
0
         inode,
728
0
         extent_index,
729
0
         &extent,
730
0
         error ) != 1 )
731
0
    {
732
0
      libcerror_error_set(
733
0
       error,
734
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
735
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
736
0
       "%s: unable to retrieve attributes extent: %d.",
737
0
       function,
738
0
       extent_index );
739
740
0
      goto on_error;
741
0
    }
742
0
    if( extent == NULL )
743
0
    {
744
0
      libcerror_error_set(
745
0
       error,
746
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
747
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
748
0
       "%s: missing extent: %d.",
749
0
       function,
750
0
       extent_index );
751
752
0
      goto on_error;
753
0
    }
754
0
    if( ( block_number >= extent->logical_block_number )
755
0
     && ( block_number < ( extent->logical_block_number + extent->number_of_blocks ) ) )
756
0
    {
757
0
      break;
758
0
    }
759
0
  }
760
0
  if( extent_index >= number_of_extents )
761
0
  {
762
0
    libcerror_error_set(
763
0
     error,
764
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
765
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
766
0
     "%s: invalid block number: %" PRIu32 " value out of bounds.",
767
0
     function,
768
0
     block_number );
769
770
0
    return( -1 );
771
0
  }
772
0
  allocation_group_index = (int) ( extent->physical_block_number >> io_handle->number_of_relative_block_number_bits );
773
0
  relative_block_number  = extent->physical_block_number & ( ( 1 << io_handle->number_of_relative_block_number_bits ) - 1 );
774
775
#if defined( HAVE_DEBUG_OUTPUT )
776
  if( libcnotify_verbose != 0 )
777
  {
778
    libcnotify_printf(
779
     "%s: extent: %d physical block number\t: %" PRIu64 "\n",
780
     function,
781
     extent_index,
782
     extent->physical_block_number );
783
784
    libcnotify_printf(
785
     "%s: extent: %d allocation group index\t: %d\n",
786
     function,
787
     extent_index,
788
     allocation_group_index );
789
790
    libcnotify_printf(
791
     "%s: extent: %d relative block number\t: %" PRIu64 "\n",
792
     function,
793
     extent_index,
794
     relative_block_number );
795
796
    libcnotify_printf(
797
     "\n" );
798
  }
799
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
800
801
0
  block_offset  = ( (off64_t) allocation_group_index * io_handle->allocation_group_size ) + relative_block_number;
802
0
  block_offset += block_number - extent->logical_block_number;
803
0
  block_offset *= io_handle->block_size;
804
805
0
  if( libfsxfs_file_system_block_initialize(
806
0
       &file_system_block,
807
0
       io_handle->block_size,
808
0
       error ) != 1 )
809
0
  {
810
0
    libcerror_error_set(
811
0
     error,
812
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
813
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
814
0
     "%s: unable to initialize file system block.",
815
0
     function );
816
817
0
    goto on_error;
818
0
  }
819
0
  if( libfsxfs_file_system_block_read_file_io_handle(
820
0
       file_system_block,
821
0
       io_handle,
822
0
       file_io_handle,
823
0
       block_offset,
824
0
       error ) != 1 )
825
0
  {
826
0
    libcerror_error_set(
827
0
     error,
828
0
     LIBCERROR_ERROR_DOMAIN_IO,
829
0
     LIBCERROR_IO_ERROR_READ_FAILED,
830
0
     "%s: unable to read block at offset: %" PRIi64 " (0x%08" PRIx64 ").",
831
0
     function,
832
0
     block_offset,
833
0
     block_offset );
834
835
0
    goto on_error;
836
0
  }
837
0
  if( ( file_system_block->header->signature == 0x3bee )
838
0
   || ( file_system_block->header->signature == 0xfbee ) )
839
0
  {
840
0
    if( libfsxfs_attributes_read_leaf_values(
841
0
         io_handle,
842
0
         file_system_block->data,
843
0
         file_system_block->data_size,
844
0
         extended_attributes_array,
845
0
         error ) != 1 )
846
0
    {
847
0
      libcerror_error_set(
848
0
       error,
849
0
       LIBCERROR_ERROR_DOMAIN_IO,
850
0
       LIBCERROR_IO_ERROR_READ_FAILED,
851
0
       "%s: unable to read attributes leaf values.",
852
0
       function );
853
854
0
      goto on_error;
855
0
    }
856
0
  }
857
0
  else if( ( file_system_block->header->signature == 0x3ebe )
858
0
        || ( file_system_block->header->signature == 0xfebe ) )
859
0
  {
860
0
    if( libfsxfs_attributes_read_branch_values(
861
0
         io_handle,
862
0
         file_io_handle,
863
0
         inode,
864
0
         file_system_block->data,
865
0
         file_system_block->data_size,
866
0
         extended_attributes_array,
867
0
         recursion_depth,
868
0
         error ) != 1 )
869
0
    {
870
0
      libcerror_error_set(
871
0
       error,
872
0
       LIBCERROR_ERROR_DOMAIN_IO,
873
0
       LIBCERROR_IO_ERROR_READ_FAILED,
874
0
       "%s: unable to read attributes branch values.",
875
0
       function );
876
877
0
      goto on_error;
878
0
    }
879
0
  }
880
0
  else
881
0
  {
882
0
    libcerror_error_set(
883
0
     error,
884
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
885
0
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
886
0
     "%s: unsupported block signature: 0x%04" PRIx16 ".",
887
0
     function,
888
0
     file_system_block->header->signature );
889
890
0
    goto on_error;
891
0
  }
892
0
  if( libfsxfs_file_system_block_free(
893
0
       &file_system_block,
894
0
       error ) != 1 )
895
0
  {
896
0
    libcerror_error_set(
897
0
     error,
898
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
899
0
     LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
900
0
     "%s: unable to free file system block.",
901
0
     function );
902
903
0
    goto on_error;
904
0
  }
905
0
  return( 1 );
906
907
0
on_error:
908
0
  if( file_system_block != NULL )
909
0
  {
910
0
    libfsxfs_file_system_block_free(
911
0
     &file_system_block,
912
0
     NULL );
913
0
  }
914
0
  libcdata_array_empty(
915
0
   extended_attributes_array,
916
0
   (int (*)(intptr_t **, libcerror_error_t **)) &libfsxfs_attribute_values_free,
917
0
   NULL );
918
919
0
  return( -1 );
920
0
}
921
922
/* Retrieves the extended attributes from the inode
923
 * Returns 1 if successful or -1 on error
924
 */
925
int libfsxfs_attributes_get_from_inode(
926
     libfsxfs_io_handle_t *io_handle,
927
     libbfio_handle_t *file_io_handle,
928
     libfsxfs_inode_t *inode,
929
     libcdata_array_t *extended_attributes_array,
930
     libcerror_error_t **error )
931
0
{
932
0
  libfsxfs_attributes_table_t *attributes_table = NULL;
933
0
  static char *function                         = "libfsxfs_attributes_get_from_inode";
934
935
0
  if( io_handle == NULL )
936
0
  {
937
0
    libcerror_error_set(
938
0
     error,
939
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
940
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
941
0
     "%s: invalid IO handle.",
942
0
     function );
943
944
0
    return( -1 );
945
0
  }
946
0
  if( inode == NULL )
947
0
  {
948
0
    libcerror_error_set(
949
0
     error,
950
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
951
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
952
0
     "%s: invalid inode.",
953
0
     function );
954
955
0
    return( -1 );
956
0
  }
957
0
  if( ( inode->attributes_fork_type != LIBFSXFS_FORK_TYPE_INLINE_DATA )
958
0
   && ( inode->attributes_fork_type != LIBFSXFS_FORK_TYPE_EXTENTS )
959
0
   && ( inode->attributes_fork_type != LIBFSXFS_FORK_TYPE_BTREE ) )
960
0
  {
961
0
    libcerror_error_set(
962
0
     error,
963
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
964
0
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
965
0
     "%s: invalid inode - unsupported attributes fork type.",
966
0
     function );
967
968
0
    goto on_error;
969
0
  }
970
0
  if( inode->attributes_fork_type == LIBFSXFS_FORK_TYPE_INLINE_DATA )
971
0
  {
972
#if defined( HAVE_DEBUG_OUTPUT )
973
    if( libcnotify_verbose != 0 )
974
    {
975
      libcnotify_printf(
976
       "%s: extended attributes data:\n",
977
       function );
978
      libcnotify_print_data(
979
       inode->inline_attributes_data,
980
       inode->attributes_fork_size,
981
       LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
982
    }
983
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
984
985
0
    if( libfsxfs_attributes_table_initialize(
986
0
         &attributes_table,
987
0
         error ) != 1 )
988
0
    {
989
0
      libcerror_error_set(
990
0
       error,
991
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
992
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
993
0
       "%s: unable to create attributes table.",
994
0
       function );
995
996
0
      goto on_error;
997
0
    }
998
0
    if( libfsxfs_attributes_table_read_data(
999
0
         attributes_table,
1000
0
         inode->inline_attributes_data,
1001
0
         inode->attributes_fork_size,
1002
0
         extended_attributes_array,
1003
0
         error ) != 1 )
1004
0
    {
1005
0
      libcerror_error_set(
1006
0
       error,
1007
0
       LIBCERROR_ERROR_DOMAIN_IO,
1008
0
       LIBCERROR_IO_ERROR_READ_FAILED,
1009
0
       "%s: unable to read attributes table.",
1010
0
       function );
1011
1012
0
      goto on_error;
1013
0
    }
1014
0
    if( libfsxfs_attributes_table_free(
1015
0
         &attributes_table,
1016
0
         error ) != 1 )
1017
0
    {
1018
0
      libcerror_error_set(
1019
0
       error,
1020
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1021
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
1022
0
       "%s: unable to free attributes table.",
1023
0
       function );
1024
1025
0
      goto on_error;
1026
0
    }
1027
0
  }
1028
0
  else if( inode->attributes_extents_array != NULL )
1029
0
  {
1030
0
    if( libfsxfs_attributes_get_from_block(
1031
0
         io_handle,
1032
0
         file_io_handle,
1033
0
         inode,
1034
0
         0,
1035
0
         extended_attributes_array,
1036
0
         0,
1037
0
         error ) != 1 )
1038
0
    {
1039
0
      libcerror_error_set(
1040
0
       error,
1041
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1042
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1043
0
       "%s: unable to retrieve extended attributes from attributes block: 0.",
1044
0
       function );
1045
1046
0
      goto on_error;
1047
0
    }
1048
0
  }
1049
0
  return( 1 );
1050
1051
0
on_error:
1052
0
  if( attributes_table != NULL )
1053
0
  {
1054
0
    libfsxfs_attributes_table_free(
1055
0
     &attributes_table,
1056
0
     NULL );
1057
0
  }
1058
0
  return( -1 );
1059
0
}
1060
1061
/* Creates a data stream of the attribute value data
1062
 * Make sure the value data_stream is referencing, is set to NULL
1063
 * Returns 1 if successful or -1 on error
1064
 */
1065
int libfsxfs_attributes_get_value_data_stream(
1066
     libfsxfs_io_handle_t *io_handle,
1067
     libfsxfs_inode_t *inode,
1068
     libfsxfs_attribute_values_t *attribute_values,
1069
     libfdata_stream_t **data_stream,
1070
     libcerror_error_t **error )
1071
0
{
1072
0
  libfdata_stream_t *safe_data_stream = NULL;
1073
0
  libfsxfs_extent_t *extent           = NULL;
1074
0
  static char *function               = "libfsxfs_attributes_get_value_data_stream";
1075
0
  size64_t data_segment_size          = 0;
1076
0
  off64_t data_segment_offset         = 0;
1077
0
  uint64_t relative_block_number      = 0;
1078
0
  uint32_t remaining_value_data_size  = 0;
1079
0
  int allocation_group_index          = 0;
1080
0
  int extent_index                    = 0;
1081
0
  int number_of_extents               = 0;
1082
0
  int segment_index                   = 0;
1083
1084
0
  if( io_handle == NULL )
1085
0
  {
1086
0
    libcerror_error_set(
1087
0
     error,
1088
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1089
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1090
0
     "%s: invalid IO handle.",
1091
0
     function );
1092
1093
0
    return( -1 );
1094
0
  }
1095
0
  if( attribute_values == NULL )
1096
0
  {
1097
0
    libcerror_error_set(
1098
0
     error,
1099
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1100
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1101
0
     "%s: invalid attribute values.",
1102
0
     function );
1103
1104
0
    return( -1 );
1105
0
  }
1106
0
  if( data_stream == NULL )
1107
0
  {
1108
0
    libcerror_error_set(
1109
0
     error,
1110
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1111
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1112
0
     "%s: invalid data stream.",
1113
0
     function );
1114
1115
0
    return( -1 );
1116
0
  }
1117
0
  if( attribute_values->value_data_block_number == 0 )
1118
0
  {
1119
0
    if( libfsxfs_data_stream_initialize_from_data(
1120
0
         data_stream,
1121
0
         attribute_values->value_data,
1122
0
         (size_t) attribute_values->value_data_size,
1123
0
         error ) != 1 )
1124
0
    {
1125
0
      libcerror_error_set(
1126
0
       error,
1127
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1128
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1129
0
       "%s: unable to create data stream.",
1130
0
       function );
1131
1132
0
      goto on_error;
1133
0
    }
1134
0
  }
1135
0
  else
1136
0
  {
1137
0
    if( libfsxfs_inode_get_number_of_attributes_extents(
1138
0
         inode,
1139
0
         &number_of_extents,
1140
0
         error ) != 1 )
1141
0
    {
1142
0
      libcerror_error_set(
1143
0
       error,
1144
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1145
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1146
0
       "%s: unable to retrieve number of attributes extents.",
1147
0
       function );
1148
1149
0
      goto on_error;
1150
0
    }
1151
0
    for( extent_index = 0;
1152
0
         extent_index < number_of_extents;
1153
0
         extent_index++ )
1154
0
    {
1155
0
      if( libfsxfs_inode_get_attributes_extent_by_index(
1156
0
           inode,
1157
0
           extent_index,
1158
0
           &extent,
1159
0
           error ) != 1 )
1160
0
      {
1161
0
        libcerror_error_set(
1162
0
         error,
1163
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
1164
0
         LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1165
0
         "%s: unable to retrieve attributes extent: %d.",
1166
0
         function,
1167
0
         extent_index );
1168
1169
0
        goto on_error;
1170
0
      }
1171
0
      if( extent == NULL )
1172
0
      {
1173
0
        libcerror_error_set(
1174
0
         error,
1175
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
1176
0
         LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1177
0
         "%s: missing extent: %d.",
1178
0
         function,
1179
0
         extent_index );
1180
1181
0
        goto on_error;
1182
0
      }
1183
0
      if( ( attribute_values->value_data_block_number >= extent->logical_block_number )
1184
0
       && ( attribute_values->value_data_block_number < ( extent->logical_block_number + extent->number_of_blocks ) ) )
1185
0
      {
1186
0
        break;
1187
0
      }
1188
0
    }
1189
0
    if( extent_index >= number_of_extents )
1190
0
    {
1191
0
      libcerror_error_set(
1192
0
       error,
1193
0
       LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1194
0
       LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
1195
0
       "%s: invalid block number: %" PRIu32 " value out of bounds.",
1196
0
       function,
1197
0
       attribute_values->value_data_block_number );
1198
1199
0
      return( -1 );
1200
0
    }
1201
/* TODO add v5 remote value data block header support */
1202
0
    if( io_handle->format_version == 5 )
1203
0
    {
1204
0
      libcerror_error_set(
1205
0
       error,
1206
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1207
0
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1208
0
       "%s: invalid IO handle - unsupported format version.",
1209
0
       function );
1210
1211
0
      return( -1 );
1212
0
    }
1213
0
    if( libfdata_stream_initialize(
1214
0
         &safe_data_stream,
1215
0
         NULL,
1216
0
         NULL,
1217
0
         NULL,
1218
0
         NULL,
1219
0
         (ssize_t (*)(intptr_t *, intptr_t *, int, int, uint8_t *, size_t, uint32_t, uint8_t, libcerror_error_t **)) &libfsxfs_block_data_handle_read_segment_data,
1220
0
         NULL,
1221
0
         (off64_t (*)(intptr_t *, intptr_t *, int, int, off64_t, libcerror_error_t **)) &libfsxfs_block_data_handle_seek_segment_offset,
1222
0
         0,
1223
0
         error ) != 1 )
1224
0
    {
1225
0
      libcerror_error_set(
1226
0
       error,
1227
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1228
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1229
0
       "%s: unable to create data stream.",
1230
0
       function );
1231
1232
0
      goto on_error;
1233
0
    }
1234
0
    remaining_value_data_size = attribute_values->value_data_size;
1235
1236
0
    while( remaining_value_data_size > 0 )
1237
0
    {
1238
0
      if( extent == NULL )
1239
0
      {
1240
0
        libcerror_error_set(
1241
0
         error,
1242
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
1243
0
         LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1244
0
         "%s: missing extent: %d.",
1245
0
         function,
1246
0
         extent_index );
1247
1248
0
        goto on_error;
1249
0
      }
1250
0
      allocation_group_index = (int) ( extent->physical_block_number >> io_handle->number_of_relative_block_number_bits );
1251
0
      relative_block_number  = extent->physical_block_number & ( ( 1 << io_handle->number_of_relative_block_number_bits ) - 1 );
1252
1253
#if defined( HAVE_DEBUG_OUTPUT )
1254
      if( libcnotify_verbose != 0 )
1255
      {
1256
        libcnotify_printf(
1257
         "%s: extent: %d allocation group index\t: %d\n",
1258
         function,
1259
         extent_index,
1260
         allocation_group_index );
1261
1262
        libcnotify_printf(
1263
         "%s: extent: %d relative block number\t: %" PRIu64 "\n",
1264
         function,
1265
         extent_index,
1266
         relative_block_number );
1267
1268
        libcnotify_printf(
1269
         "\n" );
1270
      }
1271
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
1272
1273
0
      data_segment_offset = ( ( (off64_t) allocation_group_index * io_handle->allocation_group_size ) + relative_block_number ) * io_handle->block_size;
1274
0
      data_segment_size   = (size64_t) extent->number_of_blocks * io_handle->block_size;
1275
1276
0
      if( data_segment_size > remaining_value_data_size )
1277
0
      {
1278
0
        data_segment_size = remaining_value_data_size;
1279
0
      }
1280
0
      if( libfdata_stream_append_segment(
1281
0
           safe_data_stream,
1282
0
           &segment_index,
1283
0
           0,
1284
0
           data_segment_offset,
1285
0
           data_segment_size,
1286
0
           extent->range_flags,
1287
0
           error ) != 1 )
1288
0
      {
1289
0
        libcerror_error_set(
1290
0
         error,
1291
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
1292
0
         LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
1293
0
         "%s: unable to append extent: %d data stream segment.",
1294
0
         function,
1295
0
         extent_index );
1296
1297
0
        goto on_error;
1298
0
      }
1299
0
      remaining_value_data_size -= data_segment_size;
1300
1301
0
      if( remaining_value_data_size > 0 )
1302
0
      {
1303
0
        if( libfsxfs_inode_get_attributes_extent_by_index(
1304
0
             inode,
1305
0
             extent_index,
1306
0
             &extent,
1307
0
             error ) != 1 )
1308
0
        {
1309
0
          libcerror_error_set(
1310
0
           error,
1311
0
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
1312
0
           LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1313
0
           "%s: unable to retrieve data extent: %d.",
1314
0
           function,
1315
0
           extent_index );
1316
1317
0
          goto on_error;
1318
0
        }
1319
0
      }
1320
0
    }
1321
0
    *data_stream = safe_data_stream;
1322
0
  }
1323
0
  return( 1 );
1324
1325
0
on_error:
1326
0
  if( safe_data_stream != NULL )
1327
0
  {
1328
0
    libfdata_stream_free(
1329
0
     &safe_data_stream,
1330
0
     NULL );
1331
0
  }
1332
0
  return( -1 );
1333
0
}
1334