Coverage Report

Created: 2026-04-04 07:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libfsntfs/libfsntfs/libfsntfs_compressed_data_handle.c
Line
Count
Source
1
/*
2
 * The compressed 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 <byte_stream.h>
24
#include <memory.h>
25
#include <types.h>
26
27
#include "libfsntfs_compressed_data_handle.h"
28
#include "libfsntfs_compression.h"
29
#include "libfsntfs_definitions.h"
30
#include "libfsntfs_libbfio.h"
31
#include "libfsntfs_libcerror.h"
32
#include "libfsntfs_libcnotify.h"
33
#include "libfsntfs_libfdata.h"
34
#include "libfsntfs_unused.h"
35
36
/* Creates compressed data handle
37
 * Make sure the value data_handle is referencing, is set to NULL
38
 * Returns 1 if successful or -1 on error
39
 */
40
int libfsntfs_compressed_data_handle_initialize(
41
     libfsntfs_compressed_data_handle_t **data_handle,
42
     libfdata_stream_t *compressed_data_stream,
43
     uint32_t compression_method,
44
     size64_t uncompressed_data_size,
45
     libcerror_error_t **error )
46
0
{
47
0
  static char *function        = "libfsntfs_compressed_data_handle_initialize";
48
0
  size_t compression_unit_size = 0;
49
50
0
  if( data_handle == NULL )
51
0
  {
52
0
    libcerror_error_set(
53
0
     error,
54
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
55
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
56
0
     "%s: invalid data handle.",
57
0
     function );
58
59
0
    return( -1 );
60
0
  }
61
0
  if( *data_handle != NULL )
62
0
  {
63
0
    libcerror_error_set(
64
0
     error,
65
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
66
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
67
0
     "%s: invalid data handle value already set.",
68
0
     function );
69
70
0
    return( -1 );
71
0
  }
72
0
  if( compressed_data_stream == 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 compressed data stream.",
79
0
     function );
80
81
0
    return( -1 );
82
0
  }
83
0
  switch( compression_method )
84
0
  {
85
0
    case 0:
86
0
      compression_method    = LIBFSNTFS_COMPRESSION_METHOD_LZXPRESS_HUFFMAN;
87
0
      compression_unit_size = 4096;
88
0
      break;
89
90
0
    case 1:
91
0
      compression_method    = LIBFSNTFS_COMPRESSION_METHOD_LZX;
92
0
      compression_unit_size = 32768;
93
0
      break;
94
95
0
    case 2:
96
0
      compression_method    = LIBFSNTFS_COMPRESSION_METHOD_LZXPRESS_HUFFMAN;
97
0
      compression_unit_size = 8192;
98
0
      break;
99
100
0
    case 3:
101
0
      compression_method    = LIBFSNTFS_COMPRESSION_METHOD_LZXPRESS_HUFFMAN;
102
0
      compression_unit_size = 16384;
103
0
      break;
104
105
0
    default:
106
0
      libcerror_error_set(
107
0
       error,
108
0
       LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
109
0
       LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
110
0
       "%s: unsupported compression method: %" PRIu32 ".",
111
0
       function,
112
0
       compression_method );
113
114
0
      return( -1 );
115
0
  }
116
0
  *data_handle = memory_allocate_structure(
117
0
                  libfsntfs_compressed_data_handle_t );
118
119
0
  if( *data_handle == NULL )
120
0
  {
121
0
    libcerror_error_set(
122
0
     error,
123
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
124
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
125
0
     "%s: unable to create data handle.",
126
0
     function );
127
128
0
    goto on_error;
129
0
  }
130
0
  if( memory_set(
131
0
       *data_handle,
132
0
       0,
133
0
       sizeof( libfsntfs_compressed_data_handle_t ) ) == NULL )
134
0
  {
135
0
    libcerror_error_set(
136
0
     error,
137
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
138
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
139
0
     "%s: unable to clear data handle.",
140
0
     function );
141
142
0
    memory_free(
143
0
     *data_handle );
144
145
0
    *data_handle = NULL;
146
147
0
    return( -1 );
148
0
  }
149
0
  ( *data_handle )->compressed_segment_data = (uint8_t *) memory_allocate(
150
0
                                                           sizeof( uint8_t ) * compression_unit_size );
151
152
0
  if( ( *data_handle )->compressed_segment_data == NULL )
153
0
  {
154
0
    libcerror_error_set(
155
0
     error,
156
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
157
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
158
0
     "%s: unable to create compressed segment data.",
159
0
     function );
160
161
0
    goto on_error;
162
0
  }
163
0
  ( *data_handle )->segment_data = (uint8_t *) memory_allocate(
164
0
                                                sizeof( uint8_t ) * compression_unit_size );
165
166
0
  if( ( *data_handle )->segment_data == NULL )
167
0
  {
168
0
    libcerror_error_set(
169
0
     error,
170
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
171
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
172
0
     "%s: unable to create segment data.",
173
0
     function );
174
175
0
    goto on_error;
176
0
  }
177
0
  ( *data_handle )->compressed_data_stream         = compressed_data_stream;
178
0
  ( *data_handle )->current_compressed_block_index = (uint32_t) -1;
179
0
  ( *data_handle )->uncompressed_data_size         = uncompressed_data_size;
180
0
  ( *data_handle )->compression_method             = (int) compression_method;
181
0
  ( *data_handle )->compression_unit_size          = compression_unit_size;
182
183
0
  return( 1 );
184
185
0
on_error:
186
0
  if( *data_handle != NULL )
187
0
  {
188
0
    if( ( *data_handle )->segment_data != NULL )
189
0
    {
190
0
      memory_free(
191
0
       ( *data_handle )->segment_data );
192
0
    }
193
0
    if( ( *data_handle )->compressed_segment_data != NULL )
194
0
    {
195
0
      memory_free(
196
0
       ( *data_handle )->compressed_segment_data );
197
0
    }
198
0
    memory_free(
199
0
     *data_handle );
200
201
0
    *data_handle = NULL;
202
0
  }
203
0
  return( -1 );
204
0
}
205
206
/* Frees data handle
207
 * Returns 1 if successful or -1 on error
208
 */
209
int libfsntfs_compressed_data_handle_free(
210
     libfsntfs_compressed_data_handle_t **data_handle,
211
     libcerror_error_t **error )
212
0
{
213
0
  static char *function = "libfsntfs_compressed_data_handle_free";
214
215
0
  if( data_handle == NULL )
216
0
  {
217
0
    libcerror_error_set(
218
0
     error,
219
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
220
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
221
0
     "%s: invalid data handle.",
222
0
     function );
223
224
0
    return( -1 );
225
0
  }
226
0
  if( *data_handle != NULL )
227
0
  {
228
0
    if( ( *data_handle )->segment_data != NULL )
229
0
    {
230
0
      memory_free(
231
0
       ( *data_handle )->segment_data );
232
0
    }
233
0
    if( ( *data_handle )->compressed_segment_data != NULL )
234
0
    {
235
0
      memory_free(
236
0
       ( *data_handle )->compressed_segment_data );
237
0
    }
238
0
    if( ( *data_handle )->compressed_block_offsets != NULL )
239
0
    {
240
0
      memory_free(
241
0
       ( *data_handle )->compressed_block_offsets );
242
0
    }
243
0
    if( ( *data_handle )->compressed_data_stream != NULL )
244
0
    {
245
0
      libfdata_stream_free(
246
0
       &( ( *data_handle )->compressed_data_stream ),
247
0
       NULL );
248
0
    }
249
0
    memory_free(
250
0
     *data_handle );
251
252
0
    *data_handle = NULL;
253
0
  }
254
0
  return( 1 );
255
0
}
256
257
/* Determines the compressed block offsets
258
 * Returns 1 if successful or -1 on error
259
 */
260
int libfsntfs_compressed_data_handle_get_compressed_block_offsets(
261
     libfsntfs_compressed_data_handle_t *data_handle,
262
     libbfio_handle_t *file_io_handle,
263
     libcerror_error_t **error )
264
0
{
265
0
  uint8_t *chunk_offsets_data               = NULL;
266
0
  static char *function                     = "libfsntfs_compressed_data_handle_get_compressed_block_offsets";
267
0
  size64_t compressed_data_size             = 0;
268
0
  size_t chunk_offset_data_size             = 0;
269
0
  size_t chunk_offsets_data_size            = 0;
270
0
  size_t data_offset                        = 0;
271
0
  ssize_t read_count                        = 0;
272
0
  uint64_t compressed_block_index           = 0;
273
0
  uint64_t compressed_block_offset          = 0;
274
0
  uint64_t previous_compressed_block_offset = 0;
275
276
0
  if( data_handle == NULL )
277
0
  {
278
0
    libcerror_error_set(
279
0
     error,
280
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
281
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
282
0
     "%s: invalid data handle.",
283
0
     function );
284
285
0
    return( -1 );
286
0
  }
287
0
  if( data_handle->compressed_block_offsets != NULL )
288
0
  {
289
0
    libcerror_error_set(
290
0
     error,
291
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
292
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
293
0
     "%s: invalid data handle - compressed block offsets value already set.",
294
0
     function );
295
296
0
    return( -1 );
297
0
  }
298
0
  if( libfdata_stream_get_size(
299
0
       data_handle->compressed_data_stream,
300
0
       &compressed_data_size,
301
0
       error ) != 1 )
302
0
  {
303
0
    libcerror_error_set(
304
0
     error,
305
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
306
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
307
0
     "%s: unable to retrieve compressed data size.",
308
0
     function );
309
310
0
    goto on_error;
311
0
  }
312
0
  if( compressed_data_size > (size64_t) UINT32_MAX )
313
0
  {
314
0
    chunk_offset_data_size = 8;
315
0
  }
316
0
  else
317
0
  {
318
0
    chunk_offset_data_size = 4;
319
0
  }
320
0
  chunk_offsets_data_size = data_handle->uncompressed_data_size / data_handle->compression_unit_size;
321
322
0
  if( ( data_handle->uncompressed_data_size % data_handle->compression_unit_size ) != 0 )
323
0
  {
324
0
    chunk_offsets_data_size++;
325
0
  }
326
0
  if( chunk_offsets_data_size > ( (size_t) MEMORY_MAXIMUM_ALLOCATION_SIZE / chunk_offset_data_size ) )
327
0
  {
328
0
    libcerror_error_set(
329
0
     error,
330
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
331
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
332
0
     "%s: invalid number of chunk offsets data size value exceeds maximum allocation size.",
333
0
     function );
334
335
0
    goto on_error;
336
0
  }
337
0
  chunk_offsets_data_size *= chunk_offset_data_size;
338
339
0
  chunk_offsets_data = (uint8_t *) memory_allocate(
340
0
                                    sizeof( uint8_t ) * chunk_offsets_data_size );
341
342
0
  if( chunk_offsets_data == NULL )
343
0
  {
344
0
    libcerror_error_set(
345
0
     error,
346
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
347
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
348
0
     "%s: unable to create chunk offsets data.",
349
0
     function );
350
351
0
    goto on_error;
352
0
  }
353
0
  read_count = libfdata_stream_read_buffer_at_offset(
354
0
                data_handle->compressed_data_stream,
355
0
                (intptr_t *) file_io_handle,
356
0
                chunk_offsets_data,
357
0
                chunk_offsets_data_size,
358
0
                0,
359
0
                0,
360
0
                error );
361
362
0
  if( read_count != (ssize_t) chunk_offsets_data_size )
363
0
  {
364
0
    libcerror_error_set(
365
0
     error,
366
0
     LIBCERROR_ERROR_DOMAIN_IO,
367
0
     LIBCERROR_IO_ERROR_READ_FAILED,
368
0
     "%s: unable to read chunk offsets data from compressed data stream.",
369
0
     function );
370
371
0
    goto on_error;
372
0
  }
373
#if defined( HAVE_DEBUG_OUTPUT )
374
    if( libcnotify_verbose != 0 )
375
    {
376
      libcnotify_printf(
377
       "%s: chunk offsets data:\n",
378
       function );
379
      libcnotify_print_data(
380
       chunk_offsets_data,
381
       chunk_offsets_data_size,
382
       LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
383
    }
384
#endif
385
0
  previous_compressed_block_offset = chunk_offset_data_size;
386
387
0
  compressed_block_index++;
388
389
0
  for( data_offset = 0;
390
0
       data_offset < chunk_offsets_data_size;
391
0
       data_offset += chunk_offset_data_size )
392
0
  {
393
0
    if( chunk_offset_data_size == 8 )
394
0
    {
395
0
      byte_stream_copy_to_uint64_little_endian(
396
0
       &( chunk_offsets_data[ data_offset ] ),
397
0
       compressed_block_offset );
398
0
    }
399
0
    else
400
0
    {
401
0
      byte_stream_copy_to_uint32_little_endian(
402
0
       &( chunk_offsets_data[ data_offset ] ),
403
0
       compressed_block_offset );
404
0
    }
405
0
    if( ( compressed_block_offset <= previous_compressed_block_offset )
406
0
     || ( compressed_block_offset >= compressed_data_size ) )
407
0
    {
408
0
      break;
409
0
    }
410
0
    previous_compressed_block_offset = compressed_block_offset;
411
412
0
    compressed_block_index++;
413
0
  }
414
0
  data_handle->number_of_compressed_blocks = compressed_block_index;
415
416
#if defined( HAVE_DEBUG_OUTPUT )
417
  if( libcnotify_verbose != 0 )
418
  {
419
    libcnotify_printf(
420
     "%s: number of compressed blocks\t: %" PRIu64 "\n",
421
     function,
422
     data_handle->number_of_compressed_blocks );
423
  }
424
#endif
425
0
  if( (size_t) data_handle->number_of_compressed_blocks > ( (size_t) ( MEMORY_MAXIMUM_ALLOCATION_SIZE / sizeof( uint64_t ) ) - 1 ) )
426
0
  {
427
0
    libcerror_error_set(
428
0
     error,
429
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
430
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
431
0
     "%s: invalid number of compressed blocks value exceeds maximum allocation size.",
432
0
     function );
433
434
0
    goto on_error;
435
0
  }
436
0
  data_handle->compressed_block_offsets = (uint64_t *) memory_allocate(
437
0
                                                        sizeof( uint64_t ) * ( data_handle->number_of_compressed_blocks + 1 ) );
438
439
0
  if( data_handle->compressed_block_offsets == NULL )
440
0
  {
441
0
    libcerror_error_set(
442
0
     error,
443
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
444
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
445
0
     "%s: unable to create compressed block offsets.",
446
0
     function );
447
448
0
    goto on_error;
449
0
  }
450
#if defined( HAVE_DEBUG_OUTPUT )
451
  if( libcnotify_verbose != 0 )
452
  {
453
    libcnotify_printf(
454
     "%s: compressed block: % 2d offset\t: %" PRIzd " (0x%08" PRIzx ")\n",
455
     function,
456
     0,
457
     data_offset,
458
     data_offset );
459
  }
460
#endif
461
0
  data_handle->compressed_block_offsets[ 0 ] = data_offset;
462
463
0
  data_offset = 0;
464
465
0
  for( compressed_block_index = 1;
466
0
       compressed_block_index < data_handle->number_of_compressed_blocks;
467
0
       compressed_block_index++ )
468
0
  {
469
0
    if( chunk_offset_data_size == 8 )
470
0
    {
471
0
      byte_stream_copy_to_uint64_little_endian(
472
0
       &( chunk_offsets_data[ data_offset ] ),
473
0
       compressed_block_offset );
474
0
    }
475
0
    else
476
0
    {
477
0
      byte_stream_copy_to_uint32_little_endian(
478
0
       &( chunk_offsets_data[ data_offset ] ),
479
0
       compressed_block_offset );
480
0
    }
481
#if defined( HAVE_DEBUG_OUTPUT )
482
    if( libcnotify_verbose != 0 )
483
    {
484
      libcnotify_printf(
485
       "%s: compressed block: % 2" PRIu64 " offset\t: %" PRIu64 " (0x%08" PRIx64 ")\n",
486
       function,
487
       compressed_block_index,
488
       compressed_block_offset,
489
       compressed_block_offset );
490
    }
491
#endif
492
0
    if( ( compressed_block_offset == 0 )
493
0
     || ( compressed_block_offset >= ( (uint64_t) INT64_MAX - data_handle->compressed_block_offsets[ 0 ] ) ) )
494
0
    {
495
0
      libcerror_error_set(
496
0
       error,
497
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
498
0
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
499
0
       "%s: invalid compressed block offset: %d value out of bounds.",
500
0
       function,
501
0
       compressed_block_index );
502
503
0
      goto on_error;
504
0
    }
505
0
    data_offset += chunk_offset_data_size;
506
507
0
    data_handle->compressed_block_offsets[ compressed_block_index ] = data_handle->compressed_block_offsets[ 0 ] + compressed_block_offset;
508
0
  }
509
#if defined( HAVE_DEBUG_OUTPUT )
510
  if( libcnotify_verbose != 0 )
511
  {
512
    libcnotify_printf(
513
     "%s: compressed block: % 2" PRIu64 " offset\t: %" PRIu64 " (0x%08" PRIx64 ")\n",
514
     function,
515
     compressed_block_index,
516
     compressed_data_size,
517
     compressed_data_size );
518
  }
519
#endif
520
0
  data_handle->compressed_block_offsets[ compressed_block_index ] = (uint64_t) compressed_data_size;
521
522
#if defined( HAVE_DEBUG_OUTPUT )
523
  if( libcnotify_verbose != 0 )
524
  {
525
    libcnotify_printf(
526
     "\n" );
527
  }
528
#endif
529
0
  memory_free(
530
0
   chunk_offsets_data );
531
532
0
  return( 1 );
533
534
0
on_error:
535
0
  if( data_handle->compressed_block_offsets != NULL )
536
0
  {
537
0
    memory_free(
538
0
     data_handle->compressed_block_offsets );
539
540
0
    data_handle->compressed_block_offsets = NULL;
541
0
  }
542
0
  if( chunk_offsets_data != NULL )
543
0
  {
544
0
    memory_free(
545
0
     chunk_offsets_data );
546
0
  }
547
0
  return( -1 );
548
0
}
549
550
/* Reads data from the current offset into a compressed
551
 * Callback for the data stream
552
 * Returns the number of bytes read or -1 on error
553
 */
554
ssize_t libfsntfs_compressed_data_handle_read_segment_data(
555
         libfsntfs_compressed_data_handle_t *data_handle,
556
         intptr_t *file_io_handle,
557
         int segment_index,
558
         int segment_file_index LIBFSNTFS_ATTRIBUTE_UNUSED,
559
         uint8_t *segment_data,
560
         size_t segment_data_size,
561
         uint32_t segment_flags LIBFSNTFS_ATTRIBUTE_UNUSED,
562
         uint8_t read_flags LIBFSNTFS_ATTRIBUTE_UNUSED,
563
         libcerror_error_t **error )
564
0
{
565
0
  uint8_t *read_buffer              = NULL;
566
0
  static char *function             = "libfsntfs_compressed_data_handle_read_segment_data";
567
0
  size_t data_offset                = 0;
568
0
  size_t read_size                  = 0;
569
0
  size_t segment_data_offset        = 0;
570
0
  ssize_t read_count                = 0;
571
0
  off64_t data_stream_offset        = 0;
572
0
  off64_t uncompressed_block_offset = 0;
573
0
  uint64_t compressed_block_index   = 0;
574
575
0
  LIBFSNTFS_UNREFERENCED_PARAMETER( file_io_handle )
576
0
  LIBFSNTFS_UNREFERENCED_PARAMETER( segment_file_index )
577
0
  LIBFSNTFS_UNREFERENCED_PARAMETER( segment_flags )
578
0
  LIBFSNTFS_UNREFERENCED_PARAMETER( read_flags )
579
580
0
  if( data_handle == NULL )
581
0
  {
582
0
    libcerror_error_set(
583
0
     error,
584
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
585
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
586
0
     "%s: invalid data handle.",
587
0
     function );
588
589
0
    return( -1 );
590
0
  }
591
0
  if( segment_index != 0 )
592
0
  {
593
0
    libcerror_error_set(
594
0
     error,
595
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
596
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
597
0
     "%s: invalid segment index value out of bounds.",
598
0
     function );
599
600
0
    return( -1 );
601
0
  }
602
0
  if( segment_data == NULL )
603
0
  {
604
0
    libcerror_error_set(
605
0
     error,
606
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
607
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
608
0
     "%s: invalid segment data.",
609
0
     function );
610
611
0
    return( -1 );
612
0
  }
613
0
  if( segment_data_size > (size_t) SSIZE_MAX )
614
0
  {
615
0
    libcerror_error_set(
616
0
     error,
617
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
618
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
619
0
     "%s: invalid segment data size value exceeds maximum.",
620
0
     function );
621
622
0
    return( -1 );
623
0
  }
624
0
  if( data_handle->compressed_block_offsets == NULL )
625
0
  {
626
0
    if( libfsntfs_compressed_data_handle_get_compressed_block_offsets(
627
0
         data_handle,
628
0
         (libbfio_handle_t *) file_io_handle,
629
0
         error ) != 1 )
630
0
    {
631
0
      libcerror_error_set(
632
0
       error,
633
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
634
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
635
0
       "%s: unable to determine compressed block offsets.",
636
0
       function );
637
638
0
      return( -1 );
639
0
    }
640
0
  }
641
0
  if( (size64_t) data_handle->current_offset >= data_handle->uncompressed_data_size )
642
0
  {
643
0
    return( 0 );
644
0
  }
645
0
  compressed_block_index = (uint64_t) ( data_handle->current_offset / data_handle->compression_unit_size );
646
0
  data_offset            = (size_t) ( data_handle->current_offset % data_handle->compression_unit_size );
647
648
0
  while( segment_data_size > 0 )
649
0
  {
650
0
    if( compressed_block_index >= data_handle->number_of_compressed_blocks )
651
0
    {
652
0
      libcerror_error_set(
653
0
       error,
654
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
655
0
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
656
0
       "%s: invalid compressed block index value out of bounds.",
657
0
       function );
658
659
0
      return( -1 );
660
0
    }
661
0
    if( data_handle->current_compressed_block_index != compressed_block_index )
662
0
    {
663
0
      data_stream_offset = data_handle->compressed_block_offsets[ compressed_block_index ];
664
0
      read_size          = (size_t) ( data_handle->compressed_block_offsets[ compressed_block_index + 1 ] - data_stream_offset );
665
666
0
      data_handle->segment_data_size = data_handle->compression_unit_size;
667
668
0
      if( data_handle->segment_data_size > ( data_handle->uncompressed_data_size - data_handle->current_offset ) )
669
0
      {
670
0
        data_handle->segment_data_size = data_handle->uncompressed_data_size - data_handle->current_offset;
671
0
      }
672
0
      if( read_size > data_handle->segment_data_size )
673
0
      {
674
0
        libcerror_error_set(
675
0
         error,
676
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
677
0
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
678
0
         "%s: invalid segment data size value out of bounds.",
679
0
         function );
680
681
0
        return( -1 );
682
0
      }
683
0
      if( read_size < data_handle->segment_data_size )
684
0
      {
685
0
        read_buffer = data_handle->compressed_segment_data;
686
0
      }
687
0
      else
688
0
      {
689
0
        read_buffer = data_handle->segment_data;
690
0
      }
691
#if defined( HAVE_DEBUG_OUTPUT )
692
      if( libcnotify_verbose != 0 )
693
      {
694
        libcnotify_printf(
695
         "%s: compressed block: % 2" PRIu64 " offset\t: %" PRIu64 " (0x%08" PRIx64 ")\n",
696
         function,
697
         compressed_block_index,
698
         data_stream_offset,
699
         data_stream_offset );
700
701
        libcnotify_printf(
702
         "\n" );
703
      }
704
#endif
705
0
      read_count = libfdata_stream_read_buffer_at_offset(
706
0
                    data_handle->compressed_data_stream,
707
0
                    (intptr_t *) file_io_handle,
708
0
                    read_buffer,
709
0
                    read_size,
710
0
                    data_stream_offset,
711
0
                    0,
712
0
                    error );
713
714
0
      if( read_count != (ssize_t) read_size )
715
0
      {
716
0
        libcerror_error_set(
717
0
         error,
718
0
         LIBCERROR_ERROR_DOMAIN_IO,
719
0
         LIBCERROR_IO_ERROR_READ_FAILED,
720
0
         "%s: unable to read buffer at offset: %" PRIi64 " (0x%08" PRIx64 ") from data stream.",
721
0
         function,
722
0
         data_stream_offset,
723
0
         data_stream_offset );
724
725
0
        return( -1 );
726
0
      }
727
0
      if( read_buffer == data_handle->compressed_segment_data )
728
0
      {
729
#if defined( HAVE_DEBUG_OUTPUT )
730
        if( libcnotify_verbose != 0 )
731
        {
732
          libcnotify_printf(
733
           "%s: compressed block data:\n",
734
           function );
735
          libcnotify_print_data(
736
           data_handle->compressed_segment_data,
737
           read_size,
738
           LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
739
        }
740
#endif
741
0
        if( libfsntfs_decompress_data(
742
0
             data_handle->compressed_segment_data,
743
0
             (size_t) read_count,
744
0
             data_handle->compression_method,
745
0
             data_handle->segment_data,
746
0
             &( data_handle->segment_data_size ),
747
0
             error ) != 1 )
748
0
        {
749
0
          libcerror_error_set(
750
0
           error,
751
0
           LIBCERROR_ERROR_DOMAIN_ENCRYPTION,
752
0
           LIBCERROR_ENCRYPTION_ERROR_GENERIC,
753
0
           "%s: unable to decompress data.",
754
0
           function );
755
756
0
          return( -1 );
757
0
        }
758
0
        uncompressed_block_offset = ( compressed_block_index + 1 ) * data_handle->compression_unit_size;
759
760
0
        if( ( (size64_t) uncompressed_block_offset < data_handle->uncompressed_data_size )
761
0
         && ( data_handle->segment_data_size != data_handle->compression_unit_size ) )
762
0
        {
763
0
          libcerror_error_set(
764
0
           error,
765
0
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
766
0
           LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
767
0
           "%s: invalid uncompressed segment data size value out of bounds.",
768
0
           function );
769
770
0
          return( -1 );
771
0
        }
772
0
      }
773
#if defined( HAVE_DEBUG_OUTPUT )
774
      if( libcnotify_verbose != 0 )
775
      {
776
        libcnotify_printf(
777
         "%s: uncompressed block data:\n",
778
         function );
779
        libcnotify_print_data(
780
         data_handle->segment_data,
781
         data_handle->segment_data_size,
782
         LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
783
      }
784
#endif
785
0
      data_handle->current_compressed_block_index = compressed_block_index;
786
0
    }
787
0
    if( data_offset >= data_handle->segment_data_size )
788
0
    {
789
0
      libcerror_error_set(
790
0
       error,
791
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
792
0
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
793
0
       "%s: invalid data offset value out of bounds.",
794
0
       function );
795
796
0
      return( -1 );
797
0
    }
798
0
    read_size = data_handle->segment_data_size - data_offset;
799
800
0
    if( read_size > segment_data_size )
801
0
    {
802
0
      read_size = segment_data_size;
803
0
    }
804
0
    if( memory_copy(
805
0
         &( segment_data[ segment_data_offset ] ),
806
0
         &( data_handle->segment_data[ data_offset ] ),
807
0
         read_size ) == NULL )
808
0
    {
809
0
      libcerror_error_set(
810
0
       error,
811
0
       LIBCERROR_ERROR_DOMAIN_MEMORY,
812
0
       LIBCERROR_MEMORY_ERROR_COPY_FAILED,
813
0
       "%s: unable to copy data.",
814
0
       function );
815
816
0
      return( -1 );
817
0
    }
818
0
    data_offset          = 0;
819
0
    segment_data_size   -= read_size;
820
0
    segment_data_offset += read_size;
821
822
0
    compressed_block_index++;
823
824
0
    data_handle->current_offset += read_size;
825
826
0
    if( (size64_t) data_handle->current_offset >= data_handle->uncompressed_data_size )
827
0
    {
828
0
      break;
829
0
    }
830
0
  }
831
0
  return( (ssize_t) segment_data_offset );
832
0
}
833
834
/* Seeks a certain offset of the data
835
 * Callback for the data stream
836
 * Returns the offset if seek is successful or -1 on error
837
 */
838
off64_t libfsntfs_compressed_data_handle_seek_segment_offset(
839
         libfsntfs_compressed_data_handle_t *data_handle,
840
         intptr_t *file_io_handle LIBFSNTFS_ATTRIBUTE_UNUSED,
841
         int segment_index,
842
         int segment_file_index LIBFSNTFS_ATTRIBUTE_UNUSED,
843
         off64_t segment_offset,
844
         libcerror_error_t **error )
845
0
{
846
0
  static char *function = "libfsntfs_compressed_data_handle_seek_segment_offset";
847
848
0
  LIBFSNTFS_UNREFERENCED_PARAMETER( file_io_handle )
849
0
  LIBFSNTFS_UNREFERENCED_PARAMETER( segment_file_index )
850
851
0
  if( data_handle == NULL )
852
0
  {
853
0
    libcerror_error_set(
854
0
     error,
855
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
856
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
857
0
     "%s: invalid data handle.",
858
0
     function );
859
860
0
    return( -1 );
861
0
  }
862
0
  if( segment_index != 0 )
863
0
  {
864
0
    libcerror_error_set(
865
0
     error,
866
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
867
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
868
0
     "%s: invalid segment index value out of bounds.",
869
0
     function );
870
871
0
    return( -1 );
872
0
  }
873
0
  if( segment_offset < 0 )
874
0
  {
875
0
    libcerror_error_set(
876
0
     error,
877
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
878
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
879
0
     "%s: invalid segment offset value out of bounds.",
880
0
     function );
881
882
0
    return( -1 );
883
0
  }
884
0
  data_handle->current_offset = segment_offset;
885
886
0
  return( segment_offset );
887
0
}
888