Coverage Report

Created: 2025-06-24 07:14

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