Coverage Report

Created: 2026-01-13 07:09

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-2025, 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
626
{
44
626
  static char *function = "libfsntfs_index_entry_initialize";
45
46
626
  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
626
  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
626
  *index_entry = memory_allocate_structure(
69
626
                  libfsntfs_index_entry_t );
70
71
626
  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
626
  if( memory_set(
83
626
       *index_entry,
84
626
       0,
85
626
       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
626
  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
626
}
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
626
{
121
626
  static char *function = "libfsntfs_index_entry_free";
122
626
  int result            = 1;
123
124
626
  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
626
  if( *index_entry != NULL )
136
626
  {
137
626
    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
626
    memory_free(
154
626
     *index_entry );
155
156
626
    *index_entry = NULL;
157
626
  }
158
626
  return( result );
159
626
}
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
626
{
172
626
  libfsntfs_index_entry_header_t *index_entry_header = NULL;
173
626
  uint8_t *index_entry_data                          = NULL;
174
626
  static char *function                              = "libfsntfs_index_entry_read_file_io_handle";
175
626
  size_t data_offset                                 = 0;
176
626
  size_t index_node_size                             = 0;
177
626
  size_t index_values_offset                         = 0;
178
626
  size_t unknown_data_size                           = 0;
179
626
  ssize_t read_count                                 = 0;
180
626
  off64_t index_value_vcn_offset                     = 0;
181
626
  uint16_t fixup_values_offset                       = 0;
182
626
  uint16_t number_of_fixup_values                    = 0;
183
184
626
  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
626
  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
626
  if( ( index_entry_size < ( sizeof( fsntfs_index_entry_header_t ) + sizeof( fsntfs_index_node_header_t ) ) )
207
626
   || ( 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
626
  index_entry_data = (uint8_t *) memory_allocate(
219
626
                                  sizeof( uint8_t ) * index_entry_size );
220
221
626
  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
626
  read_count = libbfio_handle_read_buffer_at_offset(
244
626
                file_io_handle,
245
626
                index_entry_data,
246
626
                (size_t) index_entry_size,
247
626
                file_offset,
248
626
                error );
249
250
626
  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
625
  if( libfsntfs_index_entry_header_initialize(
265
625
       &index_entry_header,
266
625
       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
625
  if( libfsntfs_index_entry_header_read_data(
278
625
       index_entry_header,
279
625
       index_entry_data,
280
625
       (size_t) index_entry_size,
281
625
       error ) != 1 )
282
2
  {
283
2
    libcerror_error_set(
284
2
     error,
285
2
     LIBCERROR_ERROR_DOMAIN_IO,
286
2
     LIBCERROR_IO_ERROR_READ_FAILED,
287
2
     "%s: unable to read index entry header.",
288
2
     function );
289
290
2
    goto on_error;
291
2
  }
292
623
  data_offset = sizeof( fsntfs_index_entry_header_t );
293
294
623
  if( libfsntfs_index_node_initialize(
295
623
       &( index_entry->node ),
296
623
       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
623
  if( libfsntfs_index_node_read_header(
308
623
       index_entry->node,
309
623
       index_entry_data,
310
623
       (size_t) index_entry_size,
311
623
       data_offset,
312
623
       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
622
  data_offset += sizeof( fsntfs_index_node_header_t );
324
325
622
  if( libfsntfs_index_entry_header_get_fixup_values_offset(
326
622
       index_entry_header,
327
622
       &fixup_values_offset,
328
622
       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
622
  index_values_offset = (size_t) index_entry->node->header->index_values_offset + sizeof( fsntfs_index_entry_header_t );
341
342
622
  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
621
  if( data_offset < fixup_values_offset )
354
38
  {
355
38
    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
38
    data_offset += unknown_data_size;
370
38
  }
371
621
  if( libfsntfs_index_entry_header_get_number_of_fixup_values(
372
621
       index_entry_header,
373
621
       &number_of_fixup_values,
374
621
       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
621
  if( number_of_fixup_values > 0 )
386
568
  {
387
568
    if( libfsntfs_fixup_values_apply(
388
568
         index_entry_data,
389
568
         (size_t) index_entry_size,
390
568
         fixup_values_offset,
391
568
         number_of_fixup_values,
392
568
         error ) != 1 )
393
6
    {
394
6
      libcerror_error_set(
395
6
       error,
396
6
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
397
6
       LIBCERROR_RUNTIME_ERROR_SET_FAILED,
398
6
       "%s: unable to apply fix-up values.",
399
6
       function );
400
401
6
      goto on_error;
402
6
    }
403
562
    data_offset += 2 + ( (size_t) number_of_fixup_values * 2 );
404
562
  }
405
615
  if( libfsntfs_index_entry_header_free(
406
615
       &index_entry_header,
407
615
       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
615
  index_value_vcn_offset = (off64_t) index_entry_index * index_entry_size;
419
420
615
  if( libfsntfs_index_node_read_values(
421
615
       index_entry->node,
422
615
       index_value_vcn_offset,
423
615
       index_entry_data,
424
615
       (size_t) index_entry_size,
425
615
       data_offset,
426
615
       error ) != 1 )
427
11
  {
428
11
    libcerror_error_set(
429
11
     error,
430
11
     LIBCERROR_ERROR_DOMAIN_IO,
431
11
     LIBCERROR_IO_ERROR_READ_FAILED,
432
11
     "%s: unable to read index node values.",
433
11
     function );
434
435
11
    goto on_error;
436
11
  }
437
/* TODO refactor */
438
604
  index_node_size = (size_t) index_entry->node->header->size - sizeof( fsntfs_index_node_header_t );
439
440
604
  if( data_offset < (size_t) index_values_offset )
441
599
  {
442
599
    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
599
    data_offset     += unknown_data_size;
457
599
    index_node_size -= unknown_data_size;
458
599
  }
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
604
  memory_free(
477
604
   index_entry_data );
478
479
604
  return( 1 );
480
481
22
on_error:
482
22
  if( index_entry->node != NULL )
483
19
  {
484
19
    libfsntfs_index_node_free(
485
19
     &( index_entry->node ),
486
19
     NULL );
487
19
  }
488
22
  if( index_entry_header != NULL )
489
10
  {
490
10
    libfsntfs_index_entry_header_free(
491
10
     &index_entry_header,
492
10
     NULL );
493
10
  }
494
22
  if( index_entry_data != NULL )
495
22
  {
496
22
    memory_free(
497
22
     index_entry_data );
498
22
  }
499
22
  return( -1 );
500
615
}
501