Coverage Report

Created: 2024-02-25 07:20

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