Coverage Report

Created: 2026-05-30 07:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libfsntfs/libfsntfs/libfsntfs_compression_unit_data_handle.c
Line
Count
Source
1
/*
2
 * The compression unit data handle 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 "libfsntfs_compression_unit_data_handle.h"
27
#include "libfsntfs_compression_unit_descriptor.h"
28
#include "libfsntfs_data_run.h"
29
#include "libfsntfs_definitions.h"
30
#include "libfsntfs_io_handle.h"
31
#include "libfsntfs_libcerror.h"
32
#include "libfsntfs_libcnotify.h"
33
#include "libfsntfs_mft_attribute.h"
34
35
/* Creates compression unit data handle
36
 * Make sure the value data_handle is referencing, is set to NULL
37
 * Returns 1 if successful or -1 on error
38
 */
39
int libfsntfs_compression_unit_data_handle_initialize(
40
     libfsntfs_compression_unit_data_handle_t **data_handle,
41
     libfsntfs_io_handle_t *io_handle,
42
     libfsntfs_mft_attribute_t *mft_attribute,
43
     libcerror_error_t **error )
44
2.26k
{
45
2.26k
  libfsntfs_compression_unit_descriptor_t *descriptor = NULL;
46
2.26k
  libfsntfs_data_run_t *data_run                      = NULL;
47
2.26k
  libfsntfs_mft_attribute_t *safe_mft_attribute       = NULL;
48
2.26k
  static char *function                               = "libfsntfs_compression_unit_data_handle_initialize";
49
2.26k
  size64_t attribute_data_vcn_size                    = 0;
50
2.26k
  size64_t calculated_allocated_data_size             = 0;
51
2.26k
  size64_t data_run_size                              = 0;
52
2.26k
  size64_t data_segment_size                          = 0;
53
2.26k
  size64_t remaining_compression_unit_size            = 0;
54
2.26k
  size64_t stored_allocated_data_size                 = 0;
55
2.26k
  size_t compression_unit_size                        = 0;
56
2.26k
  off64_t attribute_data_vcn_offset                   = 0;
57
2.26k
  off64_t calculated_attribute_data_vcn_offset        = 0;
58
2.26k
  off64_t data_offset                                 = 0;
59
2.26k
  off64_t data_run_offset                             = 0;
60
2.26k
  off64_t data_segment_offset                         = 0;
61
2.26k
  uint16_t data_flags                                 = 0;
62
2.26k
  int attribute_index                                 = 0;
63
2.26k
  int data_run_index                                  = 0;
64
2.26k
  int descriptor_index                                = 0;
65
2.26k
  int entry_index                                     = 0;
66
2.26k
  int number_of_data_runs                             = 0;
67
2.26k
  int total_data_run_index                            = 0;
68
2.26k
  int total_number_of_data_runs                       = 0;
69
70
#if defined( HAVE_DEBUG_OUTPUT )
71
  char *data_segment_type                             = NULL;
72
#endif
73
74
2.26k
  if( data_handle == NULL )
75
0
  {
76
0
    libcerror_error_set(
77
0
     error,
78
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
79
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
80
0
     "%s: invalid data handle.",
81
0
     function );
82
83
0
    return( -1 );
84
0
  }
85
2.26k
  if( *data_handle != NULL )
86
0
  {
87
0
    libcerror_error_set(
88
0
     error,
89
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
90
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
91
0
     "%s: invalid data handle value already set.",
92
0
     function );
93
94
0
    return( -1 );
95
0
  }
96
2.26k
  if( io_handle == NULL )
97
0
  {
98
0
    libcerror_error_set(
99
0
     error,
100
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
101
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
102
0
     "%s: invalid IO handle.",
103
0
     function );
104
105
0
    return( -1 );
106
0
  }
107
2.26k
  if( io_handle->cluster_block_size == 0 )
108
0
  {
109
0
    libcerror_error_set(
110
0
     error,
111
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
112
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
113
0
     "%s: invalid IO handle - cluster block size value out of bounds.",
114
0
     function );
115
116
0
    return( -1 );
117
0
  }
118
2.26k
  if( libfsntfs_mft_attribute_get_data_flags(
119
2.26k
       mft_attribute,
120
2.26k
       &data_flags,
121
2.26k
       error ) != 1 )
122
0
  {
123
0
    libcerror_error_set(
124
0
     error,
125
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
126
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
127
0
     "%s: unable to retrieve attribute data flags.",
128
0
     function );
129
130
0
    goto on_error;
131
0
  }
132
2.26k
  if( ( data_flags & LIBFSNTFS_ATTRIBUTE_FLAG_COMPRESSION_MASK ) == 0 )
133
0
  {
134
0
    libcerror_error_set(
135
0
     error,
136
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
137
0
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
138
0
     "%s: unsupported uncompressed attribute data.",
139
0
     function );
140
141
0
    goto on_error;
142
0
  }
143
2.26k
  if( libfsntfs_mft_attribute_get_allocated_data_size(
144
2.26k
       mft_attribute,
145
2.26k
       &stored_allocated_data_size,
146
2.26k
       error ) != 1 )
147
0
  {
148
0
    libcerror_error_set(
149
0
     error,
150
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
151
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
152
0
     "%s: unable to retrieve attribute allocated data size.",
153
0
     function );
154
155
0
    goto on_error;
156
0
  }
157
2.26k
  if( libfsntfs_mft_attribute_get_compression_unit_size(
158
2.26k
       mft_attribute,
159
2.26k
       &compression_unit_size,
160
2.26k
       error ) != 1 )
161
0
  {
162
0
    libcerror_error_set(
163
0
     error,
164
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
165
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
166
0
     "%s: unable to retrieve compression unit size.",
167
0
     function );
168
169
0
    goto on_error;
170
0
  }
171
2.26k
  if( ( compression_unit_size == 0 )
172
2.26k
   || ( compression_unit_size > (size_t) SSIZE_MAX ) )
173
0
  {
174
0
    libcerror_error_set(
175
0
     error,
176
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
177
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
178
0
     "%s: invalid compression unit size value out of bounds.",
179
0
     function );
180
181
0
    goto on_error;
182
0
  }
183
2.26k
  *data_handle = memory_allocate_structure(
184
2.26k
                  libfsntfs_compression_unit_data_handle_t );
185
186
2.26k
  if( *data_handle == NULL )
187
0
  {
188
0
    libcerror_error_set(
189
0
     error,
190
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
191
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
192
0
     "%s: unable to create data handle.",
193
0
     function );
194
195
0
    goto on_error;
196
0
  }
197
2.26k
  if( memory_set(
198
2.26k
       *data_handle,
199
2.26k
       0,
200
2.26k
       sizeof( libfsntfs_compression_unit_data_handle_t ) ) == NULL )
201
0
  {
202
0
    libcerror_error_set(
203
0
     error,
204
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
205
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
206
0
     "%s: unable to clear data handle.",
207
0
     function );
208
209
0
    memory_free(
210
0
     *data_handle );
211
212
0
    *data_handle = NULL;
213
214
0
    return( -1 );
215
0
  }
216
2.26k
  if( libcdata_array_initialize(
217
2.26k
       &( ( *data_handle )->descriptors_array ),
218
2.26k
       0,
219
2.26k
       error ) != 1 )
220
0
  {
221
0
    libcerror_error_set(
222
0
     error,
223
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
224
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
225
0
     "%s: unable to create descriptors array.",
226
0
     function );
227
228
0
    goto on_error;
229
0
  }
230
2.26k
  safe_mft_attribute = mft_attribute;
231
2.26k
  attribute_index    = 0;
232
233
4.21k
  while( safe_mft_attribute != NULL )
234
2.38k
  {
235
2.38k
    if( libfsntfs_mft_attribute_get_data_vcn_range(
236
2.38k
         safe_mft_attribute,
237
2.38k
         (uint64_t *) &attribute_data_vcn_offset,
238
2.38k
         (uint64_t *) &attribute_data_vcn_size,
239
2.38k
         error ) != 1 )
240
2
    {
241
2
      libcerror_error_set(
242
2
       error,
243
2
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
244
2
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
245
2
       "%s: unable to retrieve attribute data VCN range.",
246
2
       function );
247
248
2
      goto on_error;
249
2
    }
250
2.38k
    if( attribute_data_vcn_size != 0xffffffffffffffffULL )
251
1.91k
    {
252
1.91k
      if( (uint64_t) attribute_data_vcn_offset > (uint64_t) ( ( INT64_MAX / io_handle->cluster_block_size ) - 1 ) )
253
151
      {
254
151
        libcerror_error_set(
255
151
         error,
256
151
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
257
151
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
258
151
         "%s: invalid attribute data first VCN value out of bounds.",
259
151
         function );
260
261
151
        goto on_error;
262
151
      }
263
1.76k
      if( attribute_data_vcn_size > (size64_t) ( ( INT64_MAX / io_handle->cluster_block_size ) - 1 ) )
264
174
      {
265
174
        libcerror_error_set(
266
174
         error,
267
174
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
268
174
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
269
174
         "%s: invalid attribute data last VCN value out of bounds.",
270
174
         function );
271
272
174
        goto on_error;
273
174
      }
274
1.58k
      if( attribute_data_vcn_offset > (off64_t) attribute_data_vcn_size )
275
109
      {
276
109
        libcerror_error_set(
277
109
         error,
278
109
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
279
109
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
280
109
         "%s: invalid attribute data first VCN value out of bounds.",
281
109
         function );
282
283
109
        goto on_error;
284
109
      }
285
1.47k
      attribute_data_vcn_size   += 1;
286
1.47k
      attribute_data_vcn_size   -= attribute_data_vcn_offset;
287
1.47k
      attribute_data_vcn_offset *= io_handle->cluster_block_size;
288
1.47k
      attribute_data_vcn_size   *= io_handle->cluster_block_size;
289
290
1.47k
      if( ( calculated_attribute_data_vcn_offset != 0 )
291
2
       && ( calculated_attribute_data_vcn_offset != attribute_data_vcn_offset ) )
292
0
      {
293
0
        libcerror_error_set(
294
0
         error,
295
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
296
0
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
297
0
         "%s: invalid attribute data VCN offset value out of bounds.",
298
0
         function );
299
300
0
        goto on_error;
301
0
      }
302
1.47k
      calculated_attribute_data_vcn_offset = attribute_data_vcn_offset + (off64_t) attribute_data_vcn_size;
303
1.47k
    }
304
1.95k
    if( libfsntfs_mft_attribute_get_number_of_data_runs(
305
1.95k
         safe_mft_attribute,
306
1.95k
         &number_of_data_runs,
307
1.95k
         error ) != 1 )
308
0
    {
309
0
      libcerror_error_set(
310
0
       error,
311
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
312
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
313
0
       "%s: unable to retrieve number of data runs.",
314
0
       function );
315
316
0
      goto on_error;
317
0
    }
318
1.95k
    total_number_of_data_runs += number_of_data_runs;
319
320
1.95k
    if( libfsntfs_mft_attribute_get_next_attribute(
321
1.95k
         safe_mft_attribute,
322
1.95k
         &safe_mft_attribute,
323
1.95k
         error ) != 1 )
324
0
    {
325
0
      libcerror_error_set(
326
0
       error,
327
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
328
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
329
0
       "%s: unable to retrieve next MFT attribute: %d.",
330
0
       function,
331
0
       attribute_index );
332
333
0
      goto on_error;
334
0
    }
335
1.95k
    attribute_index++;
336
1.95k
  }
337
1.82k
  safe_mft_attribute = mft_attribute;
338
1.82k
  attribute_index    = 0;
339
340
3.61k
  while( safe_mft_attribute != NULL )
341
1.95k
  {
342
1.95k
    if( libfsntfs_mft_attribute_get_number_of_data_runs(
343
1.95k
         safe_mft_attribute,
344
1.95k
         &number_of_data_runs,
345
1.95k
         error ) != 1 )
346
0
    {
347
0
      libcerror_error_set(
348
0
       error,
349
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
350
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
351
0
       "%s: unable to retrieve number of data runs.",
352
0
       function );
353
354
0
      goto on_error;
355
0
    }
356
1.95k
    for( data_run_index = 0;
357
92.5k
         data_run_index < number_of_data_runs;
358
90.6k
         data_run_index++ )
359
90.7k
    {
360
90.7k
      if( libfsntfs_mft_attribute_get_data_run_by_index(
361
90.7k
           safe_mft_attribute,
362
90.7k
           data_run_index,
363
90.7k
           &data_run,
364
90.7k
           error ) != 1 )
365
0
      {
366
0
        libcerror_error_set(
367
0
         error,
368
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
369
0
         LIBCERROR_RUNTIME_ERROR_GET_FAILED,
370
0
         "%s: unable to retrieve data run: %d.",
371
0
         function,
372
0
         data_run_index );
373
374
0
        goto on_error;
375
0
      }
376
90.7k
      if( data_run == NULL )
377
0
      {
378
0
        libcerror_error_set(
379
0
         error,
380
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
381
0
         LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
382
0
         "%s: missing data run: %d.",
383
0
         function,
384
0
         data_run_index );
385
386
0
        goto on_error;
387
0
      }
388
90.7k
      data_run_offset = data_run->start_offset;
389
90.7k
      data_run_size   = data_run->size;
390
391
90.7k
      calculated_allocated_data_size += data_run->size;
392
393
#if defined( HAVE_DEBUG_OUTPUT )
394
      if( libcnotify_verbose != 0 )
395
      {
396
        if( ( data_run->range_flags & LIBFDATA_RANGE_FLAG_IS_SPARSE ) != 0 )
397
        {
398
          data_segment_type = "sparse ";
399
        }
400
        else
401
        {
402
          data_segment_type = "";
403
        }
404
        libcnotify_printf(
405
         "%s: %sdata run: %d offset: 0x%08" PRIx64 ", size: %" PRIu64 ".\n",
406
         function,
407
         data_segment_type,
408
         data_run_index,
409
         data_run_offset,
410
         data_run_size );
411
412
        libcnotify_printf(
413
         "\n" );
414
      }
415
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
416
417
309k
      while( data_run_size > 0 )
418
219k
      {
419
219k
        if( descriptor == NULL )
420
133k
        {
421
133k
          if( libfsntfs_compression_unit_descriptor_initialize(
422
133k
               &descriptor,
423
133k
               error ) != 1 )
424
0
          {
425
0
            libcerror_error_set(
426
0
             error,
427
0
             LIBCERROR_ERROR_DOMAIN_RUNTIME,
428
0
             LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
429
0
             "%s: unable to create compression unit descriptor.",
430
0
             function );
431
432
0
            goto on_error;
433
0
          }
434
133k
          descriptor->data_run_offset = data_run_offset;
435
133k
          descriptor->data_offset     = data_offset;
436
437
133k
          data_segment_offset = 0;
438
439
133k
          if( data_run_size <= compression_unit_size )
440
65.9k
          {
441
65.9k
            descriptor->compression_unit_size = compression_unit_size;
442
65.9k
          }
443
67.6k
          else
444
67.6k
          {
445
67.6k
            descriptor->compression_unit_size = ( data_run_size / compression_unit_size ) * compression_unit_size;
446
#if defined( HAVE_DEBUG_OUTPUT )
447
            if( libcnotify_verbose != 0 )
448
            {
449
              libcnotify_printf(
450
               "%s: uncompressed data run size: %" PRIu64 "\n",
451
               function,
452
               descriptor->compression_unit_size );
453
            }
454
#endif
455
67.6k
          }
456
133k
          remaining_compression_unit_size = descriptor->compression_unit_size;
457
133k
        }
458
219k
        if( ( data_run->range_flags & LIBFDATA_RANGE_FLAG_IS_SPARSE ) == 0 )
459
14.4k
        {
460
14.4k
          descriptor->data_range_flags = data_run->range_flags;
461
14.4k
        }
462
        /* Sparse data runs mark the end of a compression unit and they
463
         * should be at minimum the size of the remaining data in the compression unit
464
         */
465
204k
        else if( remaining_compression_unit_size < compression_unit_size )
466
80.9k
        {
467
80.9k
          if( ( total_data_run_index == ( total_number_of_data_runs - 1 ) )
468
788
           && ( data_run_size < (size64_t) remaining_compression_unit_size ) )
469
29
          {
470
#if defined( HAVE_DEBUG_OUTPUT )
471
            if( libcnotify_verbose != 0 )
472
            {
473
              libcnotify_printf(
474
               "%s: last sparse data run: %d size does not align with compression unit size.\n",
475
               function,
476
               data_run_index );
477
            }
478
#endif
479
29
            remaining_compression_unit_size = 0;
480
29
          }
481
80.9k
          descriptor->data_range_flags = LIBFDATA_RANGE_FLAG_IS_COMPRESSED;
482
80.9k
        }
483
219k
        if( data_run_size < remaining_compression_unit_size )
484
85.8k
        {
485
85.8k
          data_segment_size = data_run_size;
486
85.8k
        }
487
133k
        else
488
133k
        {
489
133k
          data_segment_size = remaining_compression_unit_size;
490
133k
        }
491
#if defined( HAVE_DEBUG_OUTPUT )
492
        if( libcnotify_verbose != 0 )
493
        {
494
          if( ( data_run->range_flags & LIBFDATA_RANGE_FLAG_IS_SPARSE ) != 0 )
495
          {
496
            data_segment_type = "sparse ";
497
          }
498
          else
499
          {
500
            data_segment_type = "";
501
          }
502
          libcnotify_printf(
503
           "%s: compression unit: %d %sdata segment offset: 0x%08" PRIx64 ", size: %" PRIu64 ".\n",
504
           function,
505
           descriptor_index,
506
           data_segment_type,
507
           data_segment_offset,
508
           data_segment_size );
509
        }
510
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
511
512
219k
        if( libfsntfs_compression_unit_descriptor_append_data_segment(
513
219k
             descriptor,
514
219k
             data_run_offset,
515
219k
             data_segment_size,
516
219k
             data_run->range_flags,
517
219k
             error ) != 1 )
518
168
        {
519
168
          libcerror_error_set(
520
168
           error,
521
168
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
522
168
           LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
523
168
           "%s: unable to append data segment to compressed block descriptor: %d.",
524
168
           function,
525
168
           descriptor_index );
526
527
168
          goto on_error;
528
168
        }
529
219k
        if( ( data_run->range_flags & LIBFDATA_RANGE_FLAG_IS_SPARSE ) == 0 )
530
14.3k
        {
531
14.3k
          data_run_offset += data_segment_size;
532
14.3k
        }
533
219k
        data_segment_offset             += data_segment_size;
534
219k
        data_run_size                   -= data_segment_size;
535
219k
        remaining_compression_unit_size -= data_segment_size;
536
537
219k
        if( remaining_compression_unit_size == 0 )
538
133k
        {
539
#if defined( HAVE_DEBUG_OUTPUT )
540
          if( libcnotify_verbose != 0 )
541
          {
542
            if( libfsntfs_compression_unit_descriptor_print(
543
                 descriptor,
544
                 io_handle,
545
                 descriptor_index,
546
                 error ) != 1 )
547
            {
548
              libcerror_error_set(
549
               error,
550
               LIBCERROR_ERROR_DOMAIN_RUNTIME,
551
               LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
552
               "%s: unable to print the compressed block descriptor: %d.",
553
               function,
554
               descriptor_index );
555
556
              goto on_error;
557
            }
558
          }
559
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
560
561
133k
          if( libcdata_array_append_entry(
562
133k
               ( *data_handle )->descriptors_array,
563
133k
               &entry_index,
564
133k
               (intptr_t *) descriptor,
565
133k
               error ) != 1 )
566
0
          {
567
0
            libcerror_error_set(
568
0
             error,
569
0
             LIBCERROR_ERROR_DOMAIN_RUNTIME,
570
0
             LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
571
0
             "%s: unable to append compressed block descriptor: %d to array.",
572
0
             function,
573
0
             descriptor_index );
574
575
0
            goto on_error;
576
0
          }
577
133k
          data_offset += descriptor->compression_unit_size;
578
579
133k
          descriptor = NULL;
580
581
133k
          descriptor_index++;
582
133k
        }
583
219k
      }
584
90.6k
      total_data_run_index++;
585
90.6k
    }
586
1.78k
    if( libfsntfs_mft_attribute_get_next_attribute(
587
1.78k
         safe_mft_attribute,
588
1.78k
         &safe_mft_attribute,
589
1.78k
         error ) != 1 )
590
0
    {
591
0
      libcerror_error_set(
592
0
       error,
593
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
594
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
595
0
       "%s: unable to retrieve next MFT attribute: %d.",
596
0
       function,
597
0
       attribute_index );
598
599
0
      goto on_error;
600
0
    }
601
1.78k
    attribute_index++;
602
1.78k
  }
603
1.65k
  if( calculated_allocated_data_size != stored_allocated_data_size )
604
272
  {
605
272
    libcerror_error_set(
606
272
     error,
607
272
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
608
272
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
609
272
     "%s: size of data runs: %" PRIu64 " does not match allocated data size: %" PRIu64 ".",
610
272
     function,
611
272
     calculated_allocated_data_size,
612
272
     stored_allocated_data_size );
613
614
272
    goto on_error;
615
272
  }
616
1.38k
  if( remaining_compression_unit_size != 0 )
617
8
  {
618
8
    libcerror_error_set(
619
8
     error,
620
8
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
621
8
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
622
8
     "%s: invalid remaining compression unit size value out of bounds.",
623
8
     function );
624
625
8
    goto on_error;
626
8
  }
627
1.37k
  ( *data_handle )->compression_unit_size = compression_unit_size;
628
629
#if defined( HAVE_DEBUG_OUTPUT )
630
  if( libcnotify_verbose != 0 )
631
  {
632
    libcnotify_printf(
633
     "\n" );
634
  }
635
#endif
636
1.37k
  return( 1 );
637
638
884
on_error:
639
884
  if( descriptor != NULL )
640
363
  {
641
363
    libfsntfs_compression_unit_descriptor_free(
642
363
     &descriptor,
643
363
     NULL );
644
363
  }
645
884
  if( *data_handle != NULL )
646
884
  {
647
884
    if( ( *data_handle )->descriptors_array != NULL )
648
884
    {
649
884
      libcdata_array_free(
650
884
       &( ( *data_handle )->descriptors_array ),
651
884
       (int (*)(intptr_t **, libcerror_error_t **)) &libfsntfs_compression_unit_descriptor_free,
652
884
       NULL );
653
884
    }
654
884
    memory_free(
655
884
     *data_handle );
656
657
884
    *data_handle = NULL;
658
884
  }
659
884
  return( -1 );
660
1.38k
}
661
662
/* Frees a data handle
663
 * Returns 1 if successful or -1 on error
664
 */
665
int libfsntfs_compression_unit_data_handle_free(
666
     libfsntfs_compression_unit_data_handle_t **data_handle,
667
     libcerror_error_t **error )
668
1.37k
{
669
1.37k
  static char *function = "libfsntfs_compression_unit_data_handle_free";
670
1.37k
  int result            = 1;
671
672
1.37k
  if( data_handle == NULL )
673
0
  {
674
0
    libcerror_error_set(
675
0
     error,
676
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
677
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
678
0
     "%s: invalid data handle.",
679
0
     function );
680
681
0
    return( -1 );
682
0
  }
683
1.37k
  if( *data_handle != NULL )
684
1.37k
  {
685
1.37k
    if( libcdata_array_free(
686
1.37k
         &( ( *data_handle )->descriptors_array ),
687
1.37k
         (int (*)(intptr_t **, libcerror_error_t **)) &libfsntfs_compression_unit_descriptor_free,
688
1.37k
         error ) != 1 )
689
0
    {
690
0
      libcerror_error_set(
691
0
       error,
692
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
693
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
694
0
       "%s: unable to free descriptors array.",
695
0
       function );
696
697
0
      result = -1;
698
0
    }
699
1.37k
    memory_free(
700
1.37k
     *data_handle );
701
702
1.37k
    *data_handle = NULL;
703
1.37k
  }
704
1.37k
  return( result );
705
1.37k
}
706
707
/* Retrieves the number of descriptors
708
 * Returns 1 if successful or -1 on error
709
 */
710
int libfsntfs_compression_unit_data_handle_get_number_of_descriptors(
711
     libfsntfs_compression_unit_data_handle_t *data_handle,
712
     int *number_of_descriptors,
713
     libcerror_error_t **error )
714
1.37k
{
715
1.37k
  static char *function = "libfsntfs_compression_unit_data_handle_get_number_of_descriptors";
716
717
1.37k
  if( data_handle == NULL )
718
0
  {
719
0
    libcerror_error_set(
720
0
     error,
721
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
722
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
723
0
     "%s: invalid data handle.",
724
0
     function );
725
726
0
    return( -1 );
727
0
  }
728
1.37k
  if( libcdata_array_get_number_of_entries(
729
1.37k
       data_handle->descriptors_array,
730
1.37k
       number_of_descriptors,
731
1.37k
       error ) != 1 )
732
0
  {
733
0
    libcerror_error_set(
734
0
     error,
735
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
736
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
737
0
     "%s: unable to retrieve number of entries from descriptors array.",
738
0
     function );
739
740
0
    return( -1 );
741
0
  }
742
1.37k
  return( 1 );
743
1.37k
}
744
745
/* Retrieves a specific descriptor
746
 * Returns 1 if successful or -1 on error
747
 */
748
int libfsntfs_compression_unit_data_handle_get_descriptor_by_index(
749
     libfsntfs_compression_unit_data_handle_t *data_handle,
750
     int descriptor_index,
751
     libfsntfs_compression_unit_descriptor_t **descriptor,
752
     libcerror_error_t **error )
753
55.8k
{
754
55.8k
  static char *function = "libfsntfs_compression_unit_data_handle_get_descriptor_by_index";
755
756
55.8k
  if( data_handle == NULL )
757
0
  {
758
0
    libcerror_error_set(
759
0
     error,
760
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
761
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
762
0
     "%s: invalid data handle.",
763
0
     function );
764
765
0
    return( -1 );
766
0
  }
767
55.8k
  if( libcdata_array_get_entry_by_index(
768
55.8k
       data_handle->descriptors_array,
769
55.8k
       descriptor_index,
770
55.8k
       (intptr_t **) descriptor,
771
55.8k
       error ) != 1 )
772
0
  {
773
0
    libcerror_error_set(
774
0
     error,
775
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
776
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
777
0
     "%s: unable to retrieve entry: %d from descriptors array.",
778
0
     function,
779
0
     descriptor_index );
780
781
0
    return( -1 );
782
0
  }
783
55.8k
  return( 1 );
784
55.8k
}
785