Coverage Report

Created: 2026-05-30 07:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libfsntfs/libfsntfs/libfsntfs_index_entry.c
Line
Count
Source
1
/*
2
 * Index entry entry 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 <memory.h>
24
#include <types.h>
25
26
#include "libfsntfs_fixup_values.h"
27
#include "libfsntfs_index_entry.h"
28
#include "libfsntfs_index_entry_header.h"
29
#include "libfsntfs_index_node.h"
30
#include "libfsntfs_libbfio.h"
31
#include "libfsntfs_libcerror.h"
32
#include "libfsntfs_libcnotify.h"
33
34
#include "fsntfs_index.h"
35
36
/* Creates an index entry
37
 * Make sure the value index_entry is referencing, is set to NULL
38
 * Returns 1 if successful or -1 on error
39
 */
40
int libfsntfs_index_entry_initialize(
41
     libfsntfs_index_entry_t **index_entry,
42
     libcerror_error_t **error )
43
650
{
44
650
  static char *function = "libfsntfs_index_entry_initialize";
45
46
650
  if( index_entry == NULL )
47
0
  {
48
0
    libcerror_error_set(
49
0
     error,
50
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
51
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
52
0
     "%s: invalid index entry.",
53
0
     function );
54
55
0
    return( -1 );
56
0
  }
57
650
  if( *index_entry != NULL )
58
0
  {
59
0
    libcerror_error_set(
60
0
     error,
61
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
62
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
63
0
     "%s: invalid index entry value already set.",
64
0
     function );
65
66
0
    return( -1 );
67
0
  }
68
650
  *index_entry = memory_allocate_structure(
69
650
                  libfsntfs_index_entry_t );
70
71
650
  if( *index_entry == NULL )
72
0
  {
73
0
    libcerror_error_set(
74
0
     error,
75
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
76
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
77
0
     "%s: unable to create index entry.",
78
0
     function );
79
80
0
    goto on_error;
81
0
  }
82
650
  if( memory_set(
83
650
       *index_entry,
84
650
       0,
85
650
       sizeof( libfsntfs_index_entry_t ) ) == NULL )
86
0
  {
87
0
    libcerror_error_set(
88
0
     error,
89
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
90
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
91
0
     "%s: unable to clear index entry.",
92
0
     function );
93
94
0
    memory_free(
95
0
     *index_entry );
96
97
0
    *index_entry = NULL;
98
99
0
    return( -1 );
100
0
  }
101
650
  return( 1 );
102
103
0
on_error:
104
0
  if( *index_entry != NULL )
105
0
  {
106
0
    memory_free(
107
0
     *index_entry );
108
109
0
    *index_entry = NULL;
110
0
  }
111
0
  return( -1 );
112
650
}
113
114
/* Frees an index entry
115
 * Returns 1 if successful or -1 on error
116
 */
117
int libfsntfs_index_entry_free(
118
     libfsntfs_index_entry_t **index_entry,
119
     libcerror_error_t **error )
120
650
{
121
650
  static char *function = "libfsntfs_index_entry_free";
122
650
  int result            = 1;
123
124
650
  if( index_entry == NULL )
125
0
  {
126
0
    libcerror_error_set(
127
0
     error,
128
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
129
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
130
0
     "%s: invalid index entry.",
131
0
     function );
132
133
0
    return( -1 );
134
0
  }
135
650
  if( *index_entry != NULL )
136
650
  {
137
650
    if( ( *index_entry )->node != NULL )
138
0
    {
139
0
      if( libfsntfs_index_node_free(
140
0
           &( ( *index_entry )->node ),
141
0
           error ) != 1 )
142
0
      {
143
0
        libcerror_error_set(
144
0
         error,
145
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
146
0
         LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
147
0
         "%s: unable to free index node.",
148
0
         function );
149
150
0
        result = -1;
151
0
      }
152
0
    }
153
650
    memory_free(
154
650
     *index_entry );
155
156
650
    *index_entry = NULL;
157
650
  }
158
650
  return( result );
159
650
}
160
161
/* Reads the index entry
162
 * Returns 1 if successful or -1 on error
163
 */
164
int libfsntfs_index_entry_read_file_io_handle(
165
     libfsntfs_index_entry_t *index_entry,
166
     libbfio_handle_t *file_io_handle,
167
     off64_t file_offset,
168
     uint32_t index_entry_size,
169
     uint32_t index_entry_index,
170
     libcerror_error_t **error )
171
650
{
172
650
  libfsntfs_index_entry_header_t *index_entry_header = NULL;
173
650
  uint8_t *index_entry_data                          = NULL;
174
650
  static char *function                              = "libfsntfs_index_entry_read_file_io_handle";
175
650
  size_t data_offset                                 = 0;
176
650
  size_t index_node_size                             = 0;
177
650
  size_t index_values_offset                         = 0;
178
650
  size_t unknown_data_size                           = 0;
179
650
  ssize_t read_count                                 = 0;
180
650
  off64_t index_value_vcn_offset                     = 0;
181
650
  uint16_t fixup_values_offset                       = 0;
182
650
  uint16_t number_of_fixup_values                    = 0;
183
184
650
  if( index_entry == NULL )
185
0
  {
186
0
    libcerror_error_set(
187
0
     error,
188
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
189
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
190
0
     "%s: invalid index entry.",
191
0
     function );
192
193
0
    return( -1 );
194
0
  }
195
650
  if( index_entry->node != NULL )
196
0
  {
197
0
    libcerror_error_set(
198
0
     error,
199
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
200
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
201
0
     "%s: invalid index entry - node value already set.",
202
0
     function );
203
204
0
    return( -1 );
205
0
  }
206
650
  if( ( index_entry_size < ( sizeof( fsntfs_index_entry_header_t ) + sizeof( fsntfs_index_node_header_t ) ) )
207
650
   || ( index_entry_size > MEMORY_MAXIMUM_ALLOCATION_SIZE ) )
208
0
  {
209
0
    libcerror_error_set(
210
0
     error,
211
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
212
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
213
0
     "%s: invalid IO handle - index entry size value out of bounds.",
214
0
     function );
215
216
0
    goto on_error;
217
0
  }
218
650
  index_entry_data = (uint8_t *) memory_allocate(
219
650
                                  sizeof( uint8_t ) * index_entry_size );
220
221
650
  if( index_entry_data == NULL )
222
0
  {
223
0
    libcerror_error_set(
224
0
     error,
225
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
226
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
227
0
     "%s: unable to create index entry data.",
228
0
     function );
229
230
0
    goto on_error;
231
0
  }
232
#if defined( HAVE_DEBUG_OUTPUT )
233
  if( libcnotify_verbose != 0 )
234
  {
235
    libcnotify_printf(
236
     "%s: reading index entry: %" PRIu32 " at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
237
     function,
238
     index_entry_index,
239
     file_offset,
240
     file_offset );
241
  }
242
#endif
243
650
  read_count = libbfio_handle_read_buffer_at_offset(
244
650
                file_io_handle,
245
650
                index_entry_data,
246
650
                (size_t) index_entry_size,
247
650
                file_offset,
248
650
                error );
249
250
650
  if( read_count != (ssize_t) index_entry_size )
251
1
  {
252
1
    libcerror_error_set(
253
1
     error,
254
1
     LIBCERROR_ERROR_DOMAIN_IO,
255
1
     LIBCERROR_IO_ERROR_READ_FAILED,
256
1
     "%s: unable to read index entry: %" PRIu32 " data at offset: %" PRIi64 " (0x%08" PRIx64 ").",
257
1
     function,
258
1
     index_entry_index,
259
1
     file_offset,
260
1
     file_offset );
261
262
1
    goto on_error;
263
1
  }
264
649
  if( libfsntfs_index_entry_header_initialize(
265
649
       &index_entry_header,
266
649
       error ) != 1 )
267
0
  {
268
0
    libcerror_error_set(
269
0
     error,
270
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
271
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
272
0
     "%s: unable to create index entry header.",
273
0
     function );
274
275
0
    goto on_error;
276
0
  }
277
649
  if( libfsntfs_index_entry_header_read_data(
278
649
       index_entry_header,
279
649
       index_entry_data,
280
649
       (size_t) index_entry_size,
281
649
       error ) != 1 )
282
3
  {
283
3
    libcerror_error_set(
284
3
     error,
285
3
     LIBCERROR_ERROR_DOMAIN_IO,
286
3
     LIBCERROR_IO_ERROR_READ_FAILED,
287
3
     "%s: unable to read index entry header.",
288
3
     function );
289
290
3
    goto on_error;
291
3
  }
292
646
  data_offset = sizeof( fsntfs_index_entry_header_t );
293
294
646
  if( libfsntfs_index_node_initialize(
295
646
       &( index_entry->node ),
296
646
       error ) != 1 )
297
0
  {
298
0
    libcerror_error_set(
299
0
     error,
300
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
301
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
302
0
     "%s: unable to create index node.",
303
0
     function );
304
305
0
    goto on_error;
306
0
  }
307
646
  if( libfsntfs_index_node_read_header(
308
646
       index_entry->node,
309
646
       index_entry_data,
310
646
       (size_t) index_entry_size,
311
646
       data_offset,
312
646
       error ) != 1 )
313
1
  {
314
1
    libcerror_error_set(
315
1
     error,
316
1
     LIBCERROR_ERROR_DOMAIN_IO,
317
1
     LIBCERROR_IO_ERROR_READ_FAILED,
318
1
     "%s: unable to read index node header.",
319
1
     function );
320
321
1
    goto on_error;
322
1
  }
323
645
  data_offset += sizeof( fsntfs_index_node_header_t );
324
325
645
  if( libfsntfs_index_entry_header_get_fixup_values_offset(
326
645
       index_entry_header,
327
645
       &fixup_values_offset,
328
645
       error ) != 1 )
329
0
  {
330
0
    libcerror_error_set(
331
0
     error,
332
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
333
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
334
0
     "%s: unable to retrieve fix-up values offset.",
335
0
     function );
336
337
0
    goto on_error;
338
0
  }
339
/* TODO check bounds of index_values_offset */
340
645
  index_values_offset = (size_t) index_entry->node->header->index_values_offset + sizeof( fsntfs_index_entry_header_t );
341
342
645
  if( fixup_values_offset > index_values_offset )
343
1
  {
344
1
    libcerror_error_set(
345
1
     error,
346
1
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
347
1
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
348
1
     "%s: fix-up values offset exceeds index values offset.",
349
1
     function );
350
351
1
    goto on_error;
352
1
  }
353
644
  if( data_offset < fixup_values_offset )
354
47
  {
355
47
    unknown_data_size = (size_t) fixup_values_offset - data_offset;
356
357
#if defined( HAVE_DEBUG_OUTPUT )
358
    if( libcnotify_verbose != 0 )
359
    {
360
      libcnotify_printf(
361
       "%s: unknown data:\n",
362
       function );
363
      libcnotify_print_data(
364
       &( index_entry_data[ data_offset ] ),
365
       unknown_data_size,
366
       0 );
367
    }
368
#endif
369
47
    data_offset += unknown_data_size;
370
47
  }
371
644
  if( libfsntfs_index_entry_header_get_number_of_fixup_values(
372
644
       index_entry_header,
373
644
       &number_of_fixup_values,
374
644
       error ) != 1 )
375
0
  {
376
0
    libcerror_error_set(
377
0
     error,
378
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
379
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
380
0
     "%s: unable to retrieve number of fix-up values.",
381
0
     function );
382
383
0
    goto on_error;
384
0
  }
385
644
  if( number_of_fixup_values > 0 )
386
572
  {
387
572
    if( libfsntfs_fixup_values_apply(
388
572
         index_entry_data,
389
572
         (size_t) index_entry_size,
390
572
         fixup_values_offset,
391
572
         number_of_fixup_values,
392
572
         error ) != 1 )
393
7
    {
394
7
      libcerror_error_set(
395
7
       error,
396
7
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
397
7
       LIBCERROR_RUNTIME_ERROR_SET_FAILED,
398
7
       "%s: unable to apply fix-up values.",
399
7
       function );
400
401
7
      goto on_error;
402
7
    }
403
565
    data_offset += 2 + ( (size_t) number_of_fixup_values * 2 );
404
565
  }
405
637
  if( libfsntfs_index_entry_header_free(
406
637
       &index_entry_header,
407
637
       error ) != 1 )
408
0
  {
409
0
    libcerror_error_set(
410
0
     error,
411
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
412
0
     LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
413
0
     "%s: unable to free index entry header.",
414
0
     function );
415
416
0
    goto on_error;
417
0
  }
418
637
  index_value_vcn_offset = (off64_t) index_entry_index * index_entry_size;
419
420
637
  if( libfsntfs_index_node_read_values(
421
637
       index_entry->node,
422
637
       index_value_vcn_offset,
423
637
       index_entry_data,
424
637
       (size_t) index_entry_size,
425
637
       data_offset,
426
637
       error ) != 1 )
427
12
  {
428
12
    libcerror_error_set(
429
12
     error,
430
12
     LIBCERROR_ERROR_DOMAIN_IO,
431
12
     LIBCERROR_IO_ERROR_READ_FAILED,
432
12
     "%s: unable to read index node values.",
433
12
     function );
434
435
12
    goto on_error;
436
12
  }
437
/* TODO refactor */
438
625
  index_node_size = (size_t) index_entry->node->header->size - sizeof( fsntfs_index_node_header_t );
439
440
625
  if( data_offset < (size_t) index_values_offset )
441
618
  {
442
618
    unknown_data_size = (size_t) index_values_offset - data_offset;
443
444
#if defined( HAVE_DEBUG_OUTPUT )
445
    if( libcnotify_verbose != 0 )
446
    {
447
      libcnotify_printf(
448
       "%s: unknown data:\n",
449
       function );
450
      libcnotify_print_data(
451
       &( index_entry_data[ data_offset ] ),
452
       unknown_data_size,
453
       0 );
454
    }
455
#endif
456
618
    data_offset     += unknown_data_size;
457
618
    index_node_size -= unknown_data_size;
458
618
  }
459
#if defined( HAVE_DEBUG_OUTPUT )
460
  if( libcnotify_verbose != 0 )
461
  {
462
    data_offset += index_node_size;
463
464
    if( data_offset < (size_t) index_entry_size )
465
    {
466
      libcnotify_printf(
467
       "%s: trailing data:\n",
468
       function );
469
      libcnotify_print_data(
470
       &( index_entry_data[ data_offset ] ),
471
       (size_t) index_entry_size - data_offset,
472
       LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
473
    }
474
  }
475
#endif
476
625
  memory_free(
477
625
   index_entry_data );
478
479
625
  return( 1 );
480
481
25
on_error:
482
25
  if( index_entry->node != NULL )
483
21
  {
484
21
    libfsntfs_index_node_free(
485
21
     &( index_entry->node ),
486
21
     NULL );
487
21
  }
488
25
  if( index_entry_header != NULL )
489
12
  {
490
12
    libfsntfs_index_entry_header_free(
491
12
     &index_entry_header,
492
12
     NULL );
493
12
  }
494
25
  if( index_entry_data != NULL )
495
25
  {
496
25
    memory_free(
497
25
     index_entry_data );
498
25
  }
499
25
  return( -1 );
500
637
}
501