Coverage Report

Created: 2026-07-10 07:32

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-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 <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
602
{
46
602
  libfdata_vector_t *safe_cluster_block_vector = NULL;
47
602
  libfsntfs_data_run_t *data_run               = NULL;
48
602
  static char *function                        = "libfsntfs_cluster_block_vector_initialize";
49
602
  size64_t attribute_data_vcn_size             = 0;
50
602
  size64_t calculated_allocated_data_size      = 0;
51
602
  size64_t stored_allocated_data_size          = 0;
52
602
  off64_t attribute_data_vcn_offset            = 0;
53
602
  off64_t calculated_attribute_data_vcn_offset = 0;
54
602
  uint16_t attribute_data_flags                = 0;
55
602
  int attribute_index                          = 0;
56
602
  int data_run_index                           = 0;
57
602
  int number_of_data_runs                      = 0;
58
602
  int segment_index                            = 0;
59
60
602
  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
602
  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
602
  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
602
  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
602
  if( libfsntfs_mft_attribute_get_data_flags(
105
602
       mft_attribute,
106
602
       &attribute_data_flags,
107
602
       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
602
  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
601
  if( libfsntfs_mft_attribute_get_allocated_data_size(
130
601
       mft_attribute,
131
601
       &stored_allocated_data_size,
132
601
       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
601
  if( libfdata_vector_initialize(
144
601
       &safe_cluster_block_vector,
145
601
       (size64_t) io_handle->cluster_block_size,
146
601
       (intptr_t *) io_handle,
147
601
       NULL,
148
601
       NULL,
149
601
       (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
601
       NULL,
151
601
       LIBFDATA_DATA_HANDLE_FLAG_NON_MANAGED,
152
601
       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.04k
  while( mft_attribute != NULL )
164
729
  {
165
729
    if( libfsntfs_mft_attribute_get_data_vcn_range(
166
729
         mft_attribute,
167
729
         (uint64_t *) &attribute_data_vcn_offset,
168
729
         (uint64_t *) &attribute_data_vcn_size,
169
729
         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
728
    if( attribute_data_vcn_size != 0xffffffffffffffffULL )
181
707
    {
182
707
      if( (uint64_t) attribute_data_vcn_offset > (uint64_t) ( ( INT64_MAX / io_handle->cluster_block_size ) - 1 ) )
183
84
      {
184
84
        libcerror_error_set(
185
84
         error,
186
84
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
187
84
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
188
84
         "%s: invalid attribute data first VCN value out of bounds.",
189
84
         function );
190
191
84
        goto on_error;
192
84
      }
193
623
      if( attribute_data_vcn_size > (size64_t) ( ( INT64_MAX / io_handle->cluster_block_size ) - 1 ) )
194
50
      {
195
50
        libcerror_error_set(
196
50
         error,
197
50
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
198
50
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
199
50
         "%s: invalid attribute data last VCN value out of bounds.",
200
50
         function );
201
202
50
        goto on_error;
203
50
      }
204
573
      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
519
      attribute_data_vcn_size   += 1;
216
519
      attribute_data_vcn_size   -= attribute_data_vcn_offset;
217
519
      attribute_data_vcn_offset *= io_handle->cluster_block_size;
218
519
      attribute_data_vcn_size   *= io_handle->cluster_block_size;
219
220
519
      if( ( calculated_attribute_data_vcn_offset != 0 )
221
97
       && ( calculated_attribute_data_vcn_offset != attribute_data_vcn_offset ) )
222
96
      {
223
96
        libcerror_error_set(
224
96
         error,
225
96
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
226
96
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
227
96
         "%s: invalid attribute data VCN offset value out of bounds.",
228
96
         function );
229
230
96
        goto on_error;
231
96
      }
232
423
      calculated_attribute_data_vcn_offset = attribute_data_vcn_offset + (off64_t) attribute_data_vcn_size;
233
423
    }
234
444
    if( libfsntfs_mft_attribute_get_number_of_data_runs(
235
444
         mft_attribute,
236
444
         &number_of_data_runs,
237
444
         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
444
    for( data_run_index = 0;
250
1.70k
         data_run_index < number_of_data_runs;
251
1.25k
         data_run_index++ )
252
1.26k
    {
253
1.26k
      if( libfsntfs_mft_attribute_get_data_run_by_index(
254
1.26k
           mft_attribute,
255
1.26k
           data_run_index,
256
1.26k
           &data_run,
257
1.26k
           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.26k
      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.26k
      if( libfdata_vector_append_segment(
284
1.26k
           safe_cluster_block_vector,
285
1.26k
           &segment_index,
286
1.26k
           0,
287
1.26k
           data_run->start_offset,
288
1.26k
           data_run->size,
289
1.26k
           data_run->range_flags,
290
1.26k
           error ) != 1 )
291
2
      {
292
2
        libcerror_error_set(
293
2
         error,
294
2
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
295
2
         LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
296
2
         "%s: unable to append attribute: %d data run: %d vector segment.",
297
2
         function,
298
2
         attribute_index,
299
2
         data_run_index );
300
301
2
        goto on_error;
302
2
      }
303
1.25k
      calculated_allocated_data_size += data_run->size;
304
1.25k
    }
305
442
    attribute_index++;
306
307
442
    if( libfsntfs_mft_attribute_get_next_attribute(
308
442
         mft_attribute,
309
442
         &mft_attribute,
310
442
         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
442
  }
323
314
  if( calculated_allocated_data_size != stored_allocated_data_size )
324
79
  {
325
79
    libcerror_error_set(
326
79
     error,
327
79
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
328
79
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
329
79
     "%s: size of data runs: %" PRIu64 " does not match allocated data size: %" PRIu64 ".",
330
79
     function,
331
79
     calculated_allocated_data_size,
332
79
     stored_allocated_data_size );
333
334
79
    goto on_error;
335
79
  }
336
235
  *cluster_block_vector = safe_cluster_block_vector;
337
338
235
  return( 1 );
339
340
367
on_error:
341
367
  if( safe_cluster_block_vector != NULL )
342
366
  {
343
366
    libfdata_vector_free(
344
366
     &safe_cluster_block_vector,
345
366
     NULL );
346
366
  }
347
367
  return( -1 );
348
314
}
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
66.6k
{
367
66.6k
  libfsntfs_cluster_block_t *cluster_block = NULL;
368
66.6k
  static char *function                    = "libfsntfs_cluster_block_vector_read_element_data";
369
370
66.6k
  LIBFSNTFS_UNREFERENCED_PARAMETER( data_handle )
371
66.6k
  LIBFSNTFS_UNREFERENCED_PARAMETER( element_index )
372
66.6k
  LIBFSNTFS_UNREFERENCED_PARAMETER( element_data_file_index )
373
66.6k
  LIBFSNTFS_UNREFERENCED_PARAMETER( read_flags )
374
375
66.6k
  if( ( cluster_block_size == 0 )
376
66.6k
   || ( 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
66.6k
  if( libfsntfs_cluster_block_initialize(
388
66.6k
       &cluster_block,
389
66.6k
       (size_t) cluster_block_size,
390
66.6k
       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
66.6k
  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
66.6k
  else
418
66.6k
  {
419
66.6k
    if( libfsntfs_cluster_block_read_file_io_handle(
420
66.6k
         cluster_block,
421
66.6k
         file_io_handle,
422
66.6k
         cluster_block_offset,
423
66.6k
         error ) != 1 )
424
191
    {
425
191
      libcerror_error_set(
426
191
       error,
427
191
       LIBCERROR_ERROR_DOMAIN_IO,
428
191
       LIBCERROR_IO_ERROR_READ_FAILED,
429
191
       "%s: unable to read cluster block at offset: %" PRIi64 " (0x%08" PRIx64 ").",
430
191
       function,
431
191
       cluster_block_offset,
432
191
       cluster_block_offset );
433
434
191
      goto on_error;
435
191
    }
436
66.6k
  }
437
66.4k
  if( libfdata_vector_set_element_value_by_index(
438
66.4k
       vector,
439
66.4k
       (intptr_t *) file_io_handle,
440
66.4k
       cache,
441
66.4k
       element_index,
442
66.4k
       (intptr_t *) cluster_block,
443
66.4k
       (int (*)(intptr_t **, libcerror_error_t **)) &libfsntfs_cluster_block_free,
444
66.4k
       LIBFDATA_VECTOR_ELEMENT_VALUE_FLAG_MANAGED,
445
66.4k
       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
66.4k
  return( 1 );
457
458
191
on_error:
459
191
  if( cluster_block != NULL )
460
191
  {
461
191
    libfsntfs_cluster_block_free(
462
191
     &cluster_block,
463
     NULL );
464
191
  }
465
191
  return( -1 );
466
66.4k
}
467