Coverage Report

Created: 2026-01-20 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libfsntfs/libfsntfs/libfsntfs_cluster_block_vector.c
Line
Count
Source
1
/*
2
 * Cluster block vector functions
3
 *
4
 * Copyright (C) 2010-2025, 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 "libfsntfs_cluster_block.h"
26
#include "libfsntfs_cluster_block_vector.h"
27
#include "libfsntfs_data_run.h"
28
#include "libfsntfs_definitions.h"
29
#include "libfsntfs_io_handle.h"
30
#include "libfsntfs_libbfio.h"
31
#include "libfsntfs_libcerror.h"
32
#include "libfsntfs_libfdata.h"
33
#include "libfsntfs_mft_attribute.h"
34
#include "libfsntfs_unused.h"
35
36
/* Creates a cluster block vector
37
 * Make sure the value cluster_block_vector is referencing, is set to NULL
38
 * Returns 1 if successful or -1 on error
39
 */
40
int libfsntfs_cluster_block_vector_initialize(
41
     libfdata_vector_t **cluster_block_vector,
42
     libfsntfs_io_handle_t *io_handle,
43
     libfsntfs_mft_attribute_t *mft_attribute,
44
     libcerror_error_t **error )
45
650
{
46
650
  libfdata_vector_t *safe_cluster_block_vector = NULL;
47
650
  libfsntfs_data_run_t *data_run               = NULL;
48
650
  static char *function                        = "libfsntfs_cluster_block_vector_initialize";
49
650
  size64_t attribute_data_vcn_size             = 0;
50
650
  size64_t calculated_allocated_data_size      = 0;
51
650
  size64_t stored_allocated_data_size          = 0;
52
650
  off64_t attribute_data_vcn_offset            = 0;
53
650
  off64_t calculated_attribute_data_vcn_offset = 0;
54
650
  uint16_t attribute_data_flags                = 0;
55
650
  int attribute_index                          = 0;
56
650
  int data_run_index                           = 0;
57
650
  int number_of_data_runs                      = 0;
58
650
  int segment_index                            = 0;
59
60
650
  if( cluster_block_vector == NULL )
61
0
  {
62
0
    libcerror_error_set(
63
0
     error,
64
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
65
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
66
0
     "%s: invalid cluster block vector.",
67
0
     function );
68
69
0
    return( -1 );
70
0
  }
71
650
  if( *cluster_block_vector != NULL )
72
0
  {
73
0
    libcerror_error_set(
74
0
     error,
75
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
76
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
77
0
     "%s: invalid cluster block vector value already set.",
78
0
     function );
79
80
0
    return( -1 );
81
0
  }
82
650
  if( io_handle == NULL )
83
0
  {
84
0
    libcerror_error_set(
85
0
     error,
86
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
87
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
88
0
     "%s: invalid IO handle.",
89
0
     function );
90
91
0
    return( -1 );
92
0
  }
93
650
  if( io_handle->cluster_block_size == 0 )
94
0
  {
95
0
    libcerror_error_set(
96
0
     error,
97
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
98
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
99
0
     "%s: invalid IO handle - cluster block size value out of bounds.",
100
0
     function );
101
102
0
    return( -1 );
103
0
  }
104
650
  if( libfsntfs_mft_attribute_get_data_flags(
105
650
       mft_attribute,
106
650
       &attribute_data_flags,
107
650
       error ) != 1 )
108
0
  {
109
0
    libcerror_error_set(
110
0
     error,
111
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
112
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
113
0
     "%s: unable to retrieve attribute data flags.",
114
0
     function );
115
116
0
    goto on_error;
117
0
  }
118
650
  if( ( attribute_data_flags & LIBFSNTFS_ATTRIBUTE_FLAG_COMPRESSION_MASK ) != 0 )
119
1
  {
120
1
    libcerror_error_set(
121
1
     error,
122
1
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
123
1
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
124
1
     "%s: unsupported compressed attribute data.",
125
1
     function );
126
127
1
    goto on_error;
128
1
  }
129
649
  if( libfsntfs_mft_attribute_get_allocated_data_size(
130
649
       mft_attribute,
131
649
       &stored_allocated_data_size,
132
649
       error ) != 1 )
133
0
  {
134
0
    libcerror_error_set(
135
0
     error,
136
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
137
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
138
0
     "%s: unable to retrieve attribute allocated data size.",
139
0
     function );
140
141
0
    goto on_error;
142
0
  }
143
649
  if( libfdata_vector_initialize(
144
649
       &safe_cluster_block_vector,
145
649
       (size64_t) io_handle->cluster_block_size,
146
649
       (intptr_t *) io_handle,
147
649
       NULL,
148
649
       NULL,
149
649
       (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_cluster_block_vector_read_element_data,
150
649
       NULL,
151
649
       LIBFDATA_DATA_HANDLE_FLAG_NON_MANAGED,
152
649
       error ) != 1 )
153
0
  {
154
0
    libcerror_error_set(
155
0
     error,
156
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
157
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
158
0
     "%s: unable to create cluster block vector.",
159
0
     function );
160
161
0
    goto on_error;
162
0
  }
163
1.11k
  while( mft_attribute != NULL )
164
736
  {
165
736
    if( libfsntfs_mft_attribute_get_data_vcn_range(
166
736
         mft_attribute,
167
736
         (uint64_t *) &attribute_data_vcn_offset,
168
736
         (uint64_t *) &attribute_data_vcn_size,
169
736
         error ) != 1 )
170
1
    {
171
1
      libcerror_error_set(
172
1
       error,
173
1
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
174
1
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
175
1
       "%s: unable to retrieve attribute data VCN range.",
176
1
       function );
177
178
1
      goto on_error;
179
1
    }
180
735
    if( attribute_data_vcn_size != 0xffffffffffffffffULL )
181
717
    {
182
717
      if( (uint64_t) attribute_data_vcn_offset > (uint64_t) ( ( INT64_MAX / io_handle->cluster_block_size ) - 1 ) )
183
82
      {
184
82
        libcerror_error_set(
185
82
         error,
186
82
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
187
82
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
188
82
         "%s: invalid attribute data first VCN value out of bounds.",
189
82
         function );
190
191
82
        goto on_error;
192
82
      }
193
635
      if( attribute_data_vcn_size > (size64_t) ( ( INT64_MAX / io_handle->cluster_block_size ) - 1 ) )
194
52
      {
195
52
        libcerror_error_set(
196
52
         error,
197
52
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
198
52
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
199
52
         "%s: invalid attribute data last VCN value out of bounds.",
200
52
         function );
201
202
52
        goto on_error;
203
52
      }
204
583
      if( attribute_data_vcn_offset > (off64_t) attribute_data_vcn_size )
205
54
      {
206
54
        libcerror_error_set(
207
54
         error,
208
54
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
209
54
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
210
54
         "%s: invalid attribute data first VCN value exceeds last VCN value.",
211
54
         function );
212
213
54
        goto on_error;
214
54
      }
215
529
      attribute_data_vcn_size   += 1;
216
529
      attribute_data_vcn_size   -= attribute_data_vcn_offset;
217
529
      attribute_data_vcn_offset *= io_handle->cluster_block_size;
218
529
      attribute_data_vcn_size   *= io_handle->cluster_block_size;
219
220
529
      if( ( calculated_attribute_data_vcn_offset != 0 )
221
80
       && ( calculated_attribute_data_vcn_offset != attribute_data_vcn_offset ) )
222
79
      {
223
79
        libcerror_error_set(
224
79
         error,
225
79
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
226
79
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
227
79
         "%s: invalid attribute data VCN offset value out of bounds.",
228
79
         function );
229
230
79
        goto on_error;
231
79
      }
232
450
      calculated_attribute_data_vcn_offset = attribute_data_vcn_offset + (off64_t) attribute_data_vcn_size;
233
450
    }
234
468
    if( libfsntfs_mft_attribute_get_number_of_data_runs(
235
468
         mft_attribute,
236
468
         &number_of_data_runs,
237
468
         error ) != 1 )
238
0
    {
239
0
      libcerror_error_set(
240
0
       error,
241
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
242
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
243
0
       "%s: unable to retrieve attribute: %d number of data runs.",
244
0
       function,
245
0
       attribute_index );
246
247
0
      goto on_error;
248
0
    }
249
468
    for( data_run_index = 0;
250
1.64k
         data_run_index < number_of_data_runs;
251
1.18k
         data_run_index++ )
252
1.18k
    {
253
1.18k
      if( libfsntfs_mft_attribute_get_data_run_by_index(
254
1.18k
           mft_attribute,
255
1.18k
           data_run_index,
256
1.18k
           &data_run,
257
1.18k
           error ) != 1 )
258
0
      {
259
0
        libcerror_error_set(
260
0
         error,
261
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
262
0
         LIBCERROR_RUNTIME_ERROR_GET_FAILED,
263
0
         "%s: unable to retrieve attribute: %d data run: %d.",
264
0
         function,
265
0
         attribute_index,
266
0
         data_run_index );
267
268
0
        goto on_error;
269
0
      }
270
1.18k
      if( data_run == NULL )
271
0
      {
272
0
        libcerror_error_set(
273
0
         error,
274
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
275
0
         LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
276
0
         "%s: missing attribute: %d data run: %d.",
277
0
         function,
278
0
         attribute_index,
279
0
         data_run_index );
280
281
0
        goto on_error;
282
0
      }
283
1.18k
      if( libfdata_vector_append_segment(
284
1.18k
           safe_cluster_block_vector,
285
1.18k
           &segment_index,
286
1.18k
           0,
287
1.18k
           data_run->start_offset,
288
1.18k
           data_run->size,
289
1.18k
           data_run->range_flags,
290
1.18k
           error ) != 1 )
291
1
      {
292
1
        libcerror_error_set(
293
1
         error,
294
1
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
295
1
         LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
296
1
         "%s: unable to append attribute: %d data run: %d vector segment.",
297
1
         function,
298
1
         attribute_index,
299
1
         data_run_index );
300
301
1
        goto on_error;
302
1
      }
303
1.18k
      calculated_allocated_data_size += data_run->size;
304
1.18k
    }
305
467
    attribute_index++;
306
307
467
    if( libfsntfs_mft_attribute_get_next_attribute(
308
467
         mft_attribute,
309
467
         &mft_attribute,
310
467
         error ) != 1 )
311
0
    {
312
0
      libcerror_error_set(
313
0
       error,
314
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
315
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
316
0
       "%s: unable to retrieve next MFT attribute: %d.",
317
0
       function,
318
0
       attribute_index );
319
320
0
      goto on_error;
321
0
    }
322
467
  }
323
380
  if( calculated_allocated_data_size != stored_allocated_data_size )
324
78
  {
325
78
    libcerror_error_set(
326
78
     error,
327
78
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
328
78
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
329
78
     "%s: size of data runs: %" PRIu64 " does not match allocated data size: %" PRIu64 ".",
330
78
     function,
331
78
     calculated_allocated_data_size,
332
78
     stored_allocated_data_size );
333
334
78
    goto on_error;
335
78
  }
336
302
  *cluster_block_vector = safe_cluster_block_vector;
337
338
302
  return( 1 );
339
340
348
on_error:
341
348
  if( safe_cluster_block_vector != NULL )
342
347
  {
343
347
    libfdata_vector_free(
344
347
     &safe_cluster_block_vector,
345
347
     NULL );
346
347
  }
347
348
  return( -1 );
348
380
}
349
350
/* Reads a cluster block
351
 * Callback function for the cluster block vector
352
 * Returns 1 if successful or -1 on error
353
 */
354
int libfsntfs_cluster_block_vector_read_element_data(
355
     intptr_t *data_handle LIBFSNTFS_ATTRIBUTE_UNUSED,
356
     libbfio_handle_t *file_io_handle,
357
     libfdata_vector_t *vector,
358
     libfdata_cache_t *cache,
359
     int element_index LIBFSNTFS_ATTRIBUTE_UNUSED,
360
     int element_data_file_index LIBFSNTFS_ATTRIBUTE_UNUSED,
361
     off64_t cluster_block_offset,
362
     size64_t cluster_block_size,
363
     uint32_t range_flags,
364
     uint8_t read_flags LIBFSNTFS_ATTRIBUTE_UNUSED,
365
     libcerror_error_t **error )
366
51.5k
{
367
51.5k
  libfsntfs_cluster_block_t *cluster_block = NULL;
368
51.5k
  static char *function                    = "libfsntfs_cluster_block_vector_read_element_data";
369
370
51.5k
  LIBFSNTFS_UNREFERENCED_PARAMETER( data_handle )
371
51.5k
  LIBFSNTFS_UNREFERENCED_PARAMETER( element_index )
372
51.5k
  LIBFSNTFS_UNREFERENCED_PARAMETER( element_data_file_index )
373
51.5k
  LIBFSNTFS_UNREFERENCED_PARAMETER( read_flags )
374
375
51.5k
  if( ( cluster_block_size == 0 )
376
51.5k
   || ( cluster_block_size > (size64_t) SSIZE_MAX ) )
377
0
  {
378
0
    libcerror_error_set(
379
0
     error,
380
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
381
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
382
0
     "%s: invalid cluster block size value out of bounds.",
383
0
     function );
384
385
0
    return( -1 );
386
0
  }
387
51.5k
  if( libfsntfs_cluster_block_initialize(
388
51.5k
       &cluster_block,
389
51.5k
       (size_t) cluster_block_size,
390
51.5k
       error ) != 1 )
391
0
  {
392
0
    libcerror_error_set(
393
0
     error,
394
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
395
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
396
0
     "%s: unable to create cluster block.",
397
0
     function );
398
399
0
    goto on_error;
400
0
  }
401
51.5k
  if( ( range_flags & LIBFDATA_RANGE_FLAG_IS_SPARSE ) != 0 )
402
0
  {
403
0
    if( libfsntfs_cluster_block_clear(
404
0
         cluster_block,
405
0
         error ) != 1 )
406
0
    {
407
0
      libcerror_error_set(
408
0
       error,
409
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
410
0
       LIBCERROR_RUNTIME_ERROR_SET_FAILED,
411
0
       "%s: unable to clear cluster block.",
412
0
       function );
413
414
0
      goto on_error;
415
0
    }
416
0
  }
417
51.5k
  else
418
51.5k
  {
419
51.5k
    if( libfsntfs_cluster_block_read_file_io_handle(
420
51.5k
         cluster_block,
421
51.5k
         file_io_handle,
422
51.5k
         cluster_block_offset,
423
51.5k
         error ) != 1 )
424
217
    {
425
217
      libcerror_error_set(
426
217
       error,
427
217
       LIBCERROR_ERROR_DOMAIN_IO,
428
217
       LIBCERROR_IO_ERROR_READ_FAILED,
429
217
       "%s: unable to read cluster block at offset: %" PRIi64 " (0x%08" PRIx64 ").",
430
217
       function,
431
217
       cluster_block_offset,
432
217
       cluster_block_offset );
433
434
217
      goto on_error;
435
217
    }
436
51.5k
  }
437
51.3k
  if( libfdata_vector_set_element_value_by_index(
438
51.3k
       vector,
439
51.3k
       (intptr_t *) file_io_handle,
440
51.3k
       cache,
441
51.3k
       element_index,
442
51.3k
       (intptr_t *) cluster_block,
443
51.3k
       (int (*)(intptr_t **, libcerror_error_t **)) &libfsntfs_cluster_block_free,
444
51.3k
       LIBFDATA_VECTOR_ELEMENT_VALUE_FLAG_MANAGED,
445
51.3k
       error ) != 1 )
446
0
  {
447
0
    libcerror_error_set(
448
0
     error,
449
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
450
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
451
0
     "%s: unable to set cluster block as element value.",
452
0
     function );
453
454
0
    goto on_error;
455
0
  }
456
51.3k
  return( 1 );
457
458
217
on_error:
459
217
  if( cluster_block != NULL )
460
217
  {
461
217
    libfsntfs_cluster_block_free(
462
217
     &cluster_block,
463
     NULL );
464
217
  }
465
217
  return( -1 );
466
51.3k
}
467