Coverage Report

Created: 2026-03-05 07:45

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