Coverage Report

Created: 2025-09-05 06:58

/src/libfsntfs/libfsntfs/libfsntfs_compressed_block_vector.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Compressed block vector functions
3
 *
4
 * Copyright (C) 2010-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 <memory.h>
24
#include <types.h>
25
26
#include "libfsntfs_compressed_block.h"
27
#include "libfsntfs_compressed_block_vector.h"
28
#include "libfsntfs_compression_unit_data_handle.h"
29
#include "libfsntfs_compression_unit_descriptor.h"
30
#include "libfsntfs_compression.h"
31
#include "libfsntfs_definitions.h"
32
#include "libfsntfs_io_handle.h"
33
#include "libfsntfs_libcerror.h"
34
#include "libfsntfs_libfdata.h"
35
#include "libfsntfs_mft_attribute.h"
36
#include "libfsntfs_unused.h"
37
38
/* Creates a compressed block vector
39
 * Make sure the value compressed_block_vector is referencing, is set to NULL
40
 * Returns 1 if successful or -1 on error
41
 */
42
int libfsntfs_compressed_block_vector_initialize(
43
     libfdata_vector_t **compressed_block_vector,
44
     libfsntfs_io_handle_t *io_handle,
45
     libfsntfs_mft_attribute_t *mft_attribute,
46
     libcerror_error_t **error )
47
2.11k
{
48
2.11k
  libfdata_vector_t *safe_compressed_block_vector       = NULL;
49
2.11k
  libfsntfs_compression_unit_data_handle_t *data_handle = NULL;
50
2.11k
  libfsntfs_compression_unit_descriptor_t *descriptor   = NULL;
51
2.11k
  static char *function                                 = "libfsntfs_compressed_block_vector_initialize";
52
2.11k
  int descriptor_index                                  = 0;
53
2.11k
  int number_of_descriptors                             = 0;
54
2.11k
  int segment_index                                     = 0;
55
56
2.11k
  if( compressed_block_vector == NULL )
57
0
  {
58
0
    libcerror_error_set(
59
0
     error,
60
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
61
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
62
0
     "%s: invalid compressed block vector.",
63
0
     function );
64
65
0
    return( -1 );
66
0
  }
67
2.11k
  if( *compressed_block_vector != NULL )
68
0
  {
69
0
    libcerror_error_set(
70
0
     error,
71
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
72
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
73
0
     "%s: invalid compressed block vector value already set.",
74
0
     function );
75
76
0
    return( -1 );
77
0
  }
78
2.11k
  if( io_handle == NULL )
79
0
  {
80
0
    libcerror_error_set(
81
0
     error,
82
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
83
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
84
0
     "%s: invalid IO handle.",
85
0
     function );
86
87
0
    return( -1 );
88
0
  }
89
2.11k
  if( libfsntfs_compression_unit_data_handle_initialize(
90
2.11k
       &data_handle,
91
2.11k
       io_handle,
92
2.11k
       mft_attribute,
93
2.11k
       error ) != 1 )
94
826
  {
95
826
    libcerror_error_set(
96
826
     error,
97
826
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
98
826
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
99
826
     "%s: unable to create compression unit data handle.",
100
826
     function );
101
102
826
    goto on_error;
103
826
  }
104
1.28k
  if( libfdata_vector_initialize(
105
1.28k
       &safe_compressed_block_vector,
106
1.28k
       (size64_t) data_handle->compression_unit_size,
107
1.28k
       (intptr_t *) data_handle,
108
1.28k
       (int (*)(intptr_t **, libcerror_error_t **)) &libfsntfs_compression_unit_data_handle_free,
109
1.28k
       NULL,
110
1.28k
       (int (*)(intptr_t *, intptr_t *, libfdata_vector_t *, libfdata_cache_t *, int, int, off64_t, size64_t, uint32_t, uint8_t, libcerror_error_t **)) &libfsntfs_compressed_block_vector_read_element_data,
111
1.28k
       NULL,
112
1.28k
       LIBFDATA_DATA_HANDLE_FLAG_MANAGED,
113
1.28k
       error ) != 1 )
114
0
  {
115
0
    libcerror_error_set(
116
0
     error,
117
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
118
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
119
0
     "%s: unable to create compressed block vector.",
120
0
     function );
121
122
0
    goto on_error;
123
0
  }
124
1.28k
  if( libfsntfs_compression_unit_data_handle_get_number_of_descriptors(
125
1.28k
       data_handle,
126
1.28k
       &number_of_descriptors,
127
1.28k
       error ) != 1 )
128
0
  {
129
0
    libcerror_error_set(
130
0
     error,
131
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
132
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
133
0
     "%s: unable to retrieve number of descriptors.",
134
0
     function );
135
136
0
    data_handle = NULL;
137
138
0
    goto on_error;
139
0
  }
140
1.28k
  for( descriptor_index = 0;
141
48.0k
       descriptor_index < number_of_descriptors;
142
46.7k
       descriptor_index++ )
143
46.7k
  {
144
46.7k
    if( libfsntfs_compression_unit_data_handle_get_descriptor_by_index(
145
46.7k
         data_handle,
146
46.7k
         descriptor_index,
147
46.7k
         &descriptor,
148
46.7k
         error ) != 1 )
149
0
    {
150
0
      libcerror_error_set(
151
0
       error,
152
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
153
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
154
0
       "%s: unable to retrieve descriptor: %d.",
155
0
       function,
156
0
       descriptor_index );
157
158
0
      data_handle = NULL;
159
160
0
      goto on_error;
161
0
    }
162
46.7k
    if( descriptor == NULL )
163
0
    {
164
0
      libcerror_error_set(
165
0
       error,
166
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
167
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
168
0
       "%s: missing descriptor: %d.",
169
0
       function,
170
0
       descriptor_index );
171
172
0
      data_handle = NULL;
173
174
0
      goto on_error;
175
0
    }
176
46.7k
    if( libfdata_vector_append_segment(
177
46.7k
         safe_compressed_block_vector,
178
46.7k
         &segment_index,
179
46.7k
         descriptor_index,
180
46.7k
         descriptor->data_offset,
181
46.7k
         descriptor->compression_unit_size,
182
46.7k
         descriptor->data_range_flags,
183
46.7k
         error ) != 1 )
184
3
    {
185
3
      libcerror_error_set(
186
3
       error,
187
3
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
188
3
       LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
189
3
       "%s: unable to append compression unit: %d segment to compressed block vector.",
190
3
       function,
191
3
       descriptor_index );
192
193
3
      data_handle = NULL;
194
195
3
      goto on_error;
196
3
    }
197
46.7k
  }
198
1.28k
  *compressed_block_vector = safe_compressed_block_vector;
199
200
1.28k
  return( 1 );
201
202
829
on_error:
203
829
  if( safe_compressed_block_vector != NULL )
204
3
  {
205
3
    libfdata_vector_free(
206
3
     &safe_compressed_block_vector,
207
3
     NULL );
208
3
  }
209
829
  if( data_handle != NULL )
210
0
  {
211
0
    libfsntfs_compression_unit_data_handle_free(
212
0
     &data_handle,
213
0
     NULL );
214
0
  }
215
829
  return( -1 );
216
1.28k
}
217
218
/* Reads a compressed block
219
 * Callback function for the compressed block vector
220
 * Returns 1 if successful or -1 on error
221
 */
222
int libfsntfs_compressed_block_vector_read_element_data(
223
     libfsntfs_compression_unit_data_handle_t *data_handle,
224
     libbfio_handle_t *file_io_handle,
225
     libfdata_vector_t *vector,
226
     libfdata_cache_t *cache,
227
     int element_index,
228
     int element_data_file_index,
229
     off64_t element_data_offset,
230
     size64_t compressed_block_size,
231
     uint32_t range_flags,
232
     uint8_t read_flags LIBFSNTFS_ATTRIBUTE_UNUSED,
233
     libcerror_error_t **error )
234
12.8k
{
235
12.8k
  libfsntfs_compressed_block_t *compressed_block                       = NULL;
236
12.8k
  libfsntfs_compression_unit_descriptor_t *compression_unit_descriptor = NULL;
237
12.8k
  uint8_t *compressed_block_data                                       = NULL;
238
12.8k
  uint8_t *compressed_data                                             = NULL;
239
12.8k
  const char *block_type                                               = NULL;
240
12.8k
  static char *function                                                = "libfsntfs_compressed_block_vector_read_element_data";
241
12.8k
  ssize_t read_count                                                   = 0;
242
12.8k
  off64_t data_stream_offset                                           = 0;
243
12.8k
  int result                                                           = 0;
244
245
12.8k
  LIBFSNTFS_UNREFERENCED_PARAMETER( read_flags )
246
247
12.8k
  if( ( compressed_block_size == 0 )
248
12.8k
   || ( compressed_block_size > (size64_t) SSIZE_MAX ) )
249
0
  {
250
0
    libcerror_error_set(
251
0
     error,
252
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
253
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
254
0
     "%s: invalid compressed block size value out of bounds.",
255
0
     function );
256
257
0
    return( -1 );
258
0
  }
259
12.8k
  if( libfsntfs_compression_unit_data_handle_get_descriptor_by_index(
260
12.8k
       data_handle,
261
12.8k
       element_data_file_index,
262
12.8k
       &compression_unit_descriptor,
263
12.8k
       error ) != 1 )
264
0
  {
265
0
    libcerror_error_set(
266
0
     error,
267
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
268
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
269
0
     "%s: unable to retrieve compression unit descriptor: %d.",
270
0
     function,
271
0
     element_data_file_index );
272
273
0
    goto on_error;
274
0
  }
275
12.8k
  if( compression_unit_descriptor == NULL )
276
0
  {
277
0
    libcerror_error_set(
278
0
     error,
279
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
280
0
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
281
0
     "%s: missing compression unit descriptor: %d.",
282
0
     function,
283
0
     element_data_file_index );
284
285
0
    goto on_error;
286
0
  }
287
12.8k
  if( libfsntfs_compressed_block_initialize(
288
12.8k
       &compressed_block,
289
12.8k
       compressed_block_size,
290
12.8k
       error ) != 1 )
291
23
  {
292
23
    libcerror_error_set(
293
23
     error,
294
23
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
295
23
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
296
23
     "%s: unable to create compressed block.",
297
23
     function );
298
299
23
    goto on_error;
300
23
  }
301
12.8k
  if( compressed_block == NULL )
302
0
  {
303
0
    libcerror_error_set(
304
0
     error,
305
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
306
0
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
307
0
     "%s: missing compressed block.",
308
0
     function );
309
310
0
    goto on_error;
311
0
  }
312
12.8k
  if( ( range_flags & LIBFDATA_RANGE_FLAG_IS_COMPRESSED ) != 0 )
313
401
  {
314
401
    compressed_data = (uint8_t *) memory_allocate(
315
401
                                   sizeof( uint8_t ) * (size_t) compressed_block_size );
316
317
401
    if( compressed_data == NULL )
318
0
    {
319
0
      libcerror_error_set(
320
0
       error,
321
0
       LIBCERROR_ERROR_DOMAIN_MEMORY,
322
0
       LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
323
0
       "%s: unable to create compressed data.",
324
0
       function );
325
326
0
      goto on_error;
327
0
    }
328
401
    compressed_block_data = compressed_data;
329
330
    /* Make sure to read from the start of the data stream
331
     * otherwise successive reads will fail
332
     */
333
401
    data_stream_offset = 0;
334
335
401
    block_type = "compressed";
336
401
  }
337
12.4k
  else
338
12.4k
  {
339
12.4k
    compressed_block_data = compressed_block->data;
340
12.4k
    data_stream_offset    = element_data_offset - compression_unit_descriptor->data_offset;
341
342
12.4k
    block_type = "uncompressed";
343
12.4k
  }
344
12.8k
  read_count = libfdata_stream_read_buffer_at_offset(
345
12.8k
                compression_unit_descriptor->data_stream,
346
12.8k
                (intptr_t *) file_io_handle,
347
12.8k
                compressed_block_data,
348
12.8k
                compressed_block_size,
349
12.8k
                data_stream_offset,
350
12.8k
                0,
351
12.8k
                error );
352
353
12.8k
  if( read_count != (ssize_t) compressed_block_size )
354
314
  {
355
314
    libcerror_error_set(
356
314
     error,
357
314
     LIBCERROR_ERROR_DOMAIN_IO,
358
314
     LIBCERROR_IO_ERROR_READ_FAILED,
359
314
     "%s: unable to read %s block at offset: %" PRIi64 " (0x%08" PRIx64 ").",
360
314
     function,
361
314
     block_type,
362
314
     data_stream_offset,
363
314
     data_stream_offset );
364
365
314
    goto on_error;
366
314
  }
367
12.5k
  if( ( range_flags & LIBFDATA_RANGE_FLAG_IS_COMPRESSED ) != 0 )
368
390
  {
369
390
    result = libfsntfs_decompress_data(
370
390
              compressed_data,
371
390
              (size_t) compressed_block_size,
372
390
              LIBFSNTFS_COMPRESSION_METHOD_LZNT1,
373
390
              compressed_block->data,
374
390
              &( compressed_block->data_size ),
375
390
              error );
376
377
390
    if( result != 1 )
378
116
    {
379
116
      libcerror_error_set(
380
116
       error,
381
116
       LIBCERROR_ERROR_DOMAIN_COMPRESSION,
382
116
       LIBCERROR_COMPRESSION_ERROR_DECOMPRESS_FAILED,
383
116
       "%s: unable to decompress compressed data.",
384
116
       function );
385
386
116
      goto on_error;
387
116
    }
388
274
    memory_free(
389
274
     compressed_data );
390
391
274
    compressed_data = NULL;
392
393
    /* If the compressed block data size is 0 or the compressed block was truncated
394
     * fill the remainder of the compressed block with 0-byte values
395
     */
396
274
    if( compressed_block->data_size < compressed_block_size )
397
256
    {
398
256
      if( memory_set(
399
256
           &( compressed_block->data[ compressed_block->data_size ] ),
400
256
           0,
401
256
           compressed_block_size - compressed_block->data_size ) == NULL )
402
0
      {
403
0
        libcerror_error_set(
404
0
         error,
405
0
         LIBCERROR_ERROR_DOMAIN_MEMORY,
406
0
         LIBCERROR_MEMORY_ERROR_SET_FAILED,
407
0
         "%s: unable to clear remainder of compressed block.",
408
0
         function );
409
410
0
        goto on_error;
411
0
      }
412
256
      compressed_block->data_size = compressed_block_size;
413
256
    }
414
274
  }
415
12.3k
  if( libfdata_vector_set_element_value_by_index(
416
12.3k
       vector,
417
12.3k
       (intptr_t *) file_io_handle,
418
12.3k
       cache,
419
12.3k
       element_index,
420
12.3k
       (intptr_t *) compressed_block,
421
12.3k
       (int (*)(intptr_t **, libcerror_error_t **)) &libfsntfs_compressed_block_free,
422
12.3k
       LIBFDATA_VECTOR_ELEMENT_VALUE_FLAG_MANAGED,
423
12.3k
       error ) != 1 )
424
0
  {
425
0
    libcerror_error_set(
426
0
     error,
427
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
428
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
429
0
     "%s: unable to set cluster block as element value.",
430
0
     function );
431
432
0
    goto on_error;
433
0
  }
434
12.3k
  return( 1 );
435
436
453
on_error:
437
453
  if( compressed_data != NULL )
438
127
  {
439
127
    memory_free(
440
127
     compressed_data );
441
127
  }
442
453
  if( compressed_block != NULL )
443
430
  {
444
430
    libfsntfs_compressed_block_free(
445
430
     &compressed_block,
446
430
     NULL );
447
430
  }
448
453
  return( -1 );
449
12.3k
}
450