Coverage Report

Created: 2025-06-24 07:14

/src/libfsntfs/libfsntfs/libfsntfs_cluster_block_vector.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Cluster 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 <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
685
{
46
685
  libfdata_vector_t *safe_cluster_block_vector = NULL;
47
685
  libfsntfs_data_run_t *data_run               = NULL;
48
685
  static char *function                        = "libfsntfs_cluster_block_vector_initialize";
49
685
  size64_t attribute_data_vcn_size             = 0;
50
685
  size64_t calculated_allocated_data_size      = 0;
51
685
  size64_t stored_allocated_data_size          = 0;
52
685
  off64_t attribute_data_vcn_offset            = 0;
53
685
  off64_t calculated_attribute_data_vcn_offset = 0;
54
685
  uint16_t attribute_data_flags                = 0;
55
685
  int attribute_index                          = 0;
56
685
  int data_run_index                           = 0;
57
685
  int number_of_data_runs                      = 0;
58
685
  int segment_index                            = 0;
59
60
685
  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
685
  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
685
  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
685
  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
685
  if( libfsntfs_mft_attribute_get_data_flags(
105
685
       mft_attribute,
106
685
       &attribute_data_flags,
107
685
       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
685
  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
684
  if( libfsntfs_mft_attribute_get_allocated_data_size(
130
684
       mft_attribute,
131
684
       &stored_allocated_data_size,
132
684
       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
684
  if( libfdata_vector_initialize(
144
684
       &safe_cluster_block_vector,
145
684
       (size64_t) io_handle->cluster_block_size,
146
684
       (intptr_t *) io_handle,
147
684
       NULL,
148
684
       NULL,
149
684
       (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
684
       NULL,
151
684
       LIBFDATA_DATA_HANDLE_FLAG_NON_MANAGED,
152
684
       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.15k
  while( mft_attribute != NULL )
164
789
  {
165
789
    if( libfsntfs_mft_attribute_get_data_vcn_range(
166
789
         mft_attribute,
167
789
         (uint64_t *) &attribute_data_vcn_offset,
168
789
         (uint64_t *) &attribute_data_vcn_size,
169
789
         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
788
    if( attribute_data_vcn_size != 0xffffffffffffffffULL )
181
769
    {
182
769
      if( (uint64_t) attribute_data_vcn_offset > (uint64_t) ( ( INT64_MAX / io_handle->cluster_block_size ) - 1 ) )
183
86
      {
184
86
        libcerror_error_set(
185
86
         error,
186
86
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
187
86
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
188
86
         "%s: invalid attribute data first VCN value out of bounds.",
189
86
         function );
190
191
86
        goto on_error;
192
86
      }
193
683
      if( attribute_data_vcn_size > (size64_t) ( ( INT64_MAX / io_handle->cluster_block_size ) - 1 ) )
194
82
      {
195
82
        libcerror_error_set(
196
82
         error,
197
82
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
198
82
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
199
82
         "%s: invalid attribute data last VCN value out of bounds.",
200
82
         function );
201
202
82
        goto on_error;
203
82
      }
204
601
      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
547
      attribute_data_vcn_size   += 1;
216
547
      attribute_data_vcn_size   -= attribute_data_vcn_offset;
217
547
      attribute_data_vcn_offset *= io_handle->cluster_block_size;
218
547
      attribute_data_vcn_size   *= io_handle->cluster_block_size;
219
220
547
      if( ( calculated_attribute_data_vcn_offset != 0 )
221
547
       && ( calculated_attribute_data_vcn_offset != attribute_data_vcn_offset ) )
222
99
      {
223
99
        libcerror_error_set(
224
99
         error,
225
99
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
226
99
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
227
99
         "%s: invalid attribute data VCN offset value out of bounds.",
228
99
         function );
229
230
99
        goto on_error;
231
99
      }
232
448
      calculated_attribute_data_vcn_offset = attribute_data_vcn_offset + (off64_t) attribute_data_vcn_size;
233
448
    }
234
467
    if( libfsntfs_mft_attribute_get_number_of_data_runs(
235
467
         mft_attribute,
236
467
         &number_of_data_runs,
237
467
         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
467
    for( data_run_index = 0;
250
1.63k
         data_run_index < number_of_data_runs;
251
1.17k
         data_run_index++ )
252
1.17k
    {
253
1.17k
      if( libfsntfs_mft_attribute_get_data_run_by_index(
254
1.17k
           mft_attribute,
255
1.17k
           data_run_index,
256
1.17k
           &data_run,
257
1.17k
           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.17k
      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.17k
      if( libfdata_vector_append_segment(
284
1.17k
           safe_cluster_block_vector,
285
1.17k
           &segment_index,
286
1.17k
           0,
287
1.17k
           data_run->start_offset,
288
1.17k
           data_run->size,
289
1.17k
           data_run->range_flags,
290
1.17k
           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.17k
      calculated_allocated_data_size += data_run->size;
304
1.17k
    }
305
466
    attribute_index++;
306
307
466
    if( libfsntfs_mft_attribute_get_next_attribute(
308
466
         mft_attribute,
309
466
         &mft_attribute,
310
466
         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
466
  }
323
361
  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
282
  *cluster_block_vector = safe_cluster_block_vector;
337
338
282
  return( 1 );
339
340
403
on_error:
341
403
  if( safe_cluster_block_vector != NULL )
342
402
  {
343
402
    libfdata_vector_free(
344
402
     &safe_cluster_block_vector,
345
402
     NULL );
346
402
  }
347
403
  return( -1 );
348
361
}
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
45.7k
{
367
45.7k
  libfsntfs_cluster_block_t *cluster_block = NULL;
368
45.7k
  static char *function                    = "libfsntfs_cluster_block_vector_read_element_data";
369
370
45.7k
  LIBFSNTFS_UNREFERENCED_PARAMETER( data_handle )
371
45.7k
  LIBFSNTFS_UNREFERENCED_PARAMETER( element_index )
372
45.7k
  LIBFSNTFS_UNREFERENCED_PARAMETER( element_data_file_index )
373
45.7k
  LIBFSNTFS_UNREFERENCED_PARAMETER( read_flags )
374
375
45.7k
  if( ( cluster_block_size == 0 )
376
45.7k
   || ( 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
45.7k
  if( libfsntfs_cluster_block_initialize(
388
45.7k
       &cluster_block,
389
45.7k
       (size_t) cluster_block_size,
390
45.7k
       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
45.7k
  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
45.7k
  else
418
45.7k
  {
419
45.7k
    if( libfsntfs_cluster_block_read_file_io_handle(
420
45.7k
         cluster_block,
421
45.7k
         file_io_handle,
422
45.7k
         cluster_block_offset,
423
45.7k
         error ) != 1 )
424
183
    {
425
183
      libcerror_error_set(
426
183
       error,
427
183
       LIBCERROR_ERROR_DOMAIN_IO,
428
183
       LIBCERROR_IO_ERROR_READ_FAILED,
429
183
       "%s: unable to read cluster block at offset: %" PRIi64 " (0x%08" PRIx64 ").",
430
183
       function,
431
183
       cluster_block_offset,
432
183
       cluster_block_offset );
433
434
183
      goto on_error;
435
183
    }
436
45.7k
  }
437
45.6k
  if( libfdata_vector_set_element_value_by_index(
438
45.6k
       vector,
439
45.6k
       (intptr_t *) file_io_handle,
440
45.6k
       cache,
441
45.6k
       element_index,
442
45.6k
       (intptr_t *) cluster_block,
443
45.6k
       (int (*)(intptr_t **, libcerror_error_t **)) &libfsntfs_cluster_block_free,
444
45.6k
       LIBFDATA_VECTOR_ELEMENT_VALUE_FLAG_MANAGED,
445
45.6k
       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
45.6k
  return( 1 );
457
458
183
on_error:
459
183
  if( cluster_block != NULL )
460
183
  {
461
183
    libfsntfs_cluster_block_free(
462
183
     &cluster_block,
463
183
     NULL );
464
183
  }
465
183
  return( -1 );
466
45.6k
}
467