Coverage Report

Created: 2025-09-05 06:58

/src/libfsntfs/libfsntfs/libfsntfs_directory_entry.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Directory entry 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 <byte_stream.h>
24
#include <memory.h>
25
#include <types.h>
26
27
#include "libfsntfs_directory_entry.h"
28
#include "libfsntfs_file_name_values.h"
29
#include "libfsntfs_index_value.h"
30
#include "libfsntfs_libcdata.h"
31
#include "libfsntfs_libcerror.h"
32
#include "libfsntfs_libcnotify.h"
33
34
/* Creates a directory entry
35
 * Make sure the value directory_entry is referencing, is set to NULL
36
 * Returns 1 if successful or -1 on error
37
 */
38
int libfsntfs_directory_entry_initialize(
39
     libfsntfs_directory_entry_t **directory_entry,
40
     libcerror_error_t **error )
41
523
{
42
523
  static char *function = "libfsntfs_directory_entry_initialize";
43
44
523
  if( directory_entry == NULL )
45
0
  {
46
0
    libcerror_error_set(
47
0
     error,
48
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
49
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
50
0
     "%s: invalid directory entry.",
51
0
     function );
52
53
0
    return( -1 );
54
0
  }
55
523
  if( *directory_entry != NULL )
56
0
  {
57
0
    libcerror_error_set(
58
0
     error,
59
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
60
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
61
0
     "%s: invalid directory entry value already set.",
62
0
     function );
63
64
0
    return( -1 );
65
0
  }
66
523
  *directory_entry = memory_allocate_structure(
67
523
                      libfsntfs_directory_entry_t );
68
69
523
  if( *directory_entry == NULL )
70
0
  {
71
0
    libcerror_error_set(
72
0
     error,
73
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
74
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
75
0
     "%s: unable to create directory entry.",
76
0
     function );
77
78
0
    goto on_error;
79
0
  }
80
523
  if( memory_set(
81
523
       *directory_entry,
82
523
       0,
83
523
       sizeof( libfsntfs_directory_entry_t ) ) == NULL )
84
0
  {
85
0
    libcerror_error_set(
86
0
     error,
87
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
88
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
89
0
     "%s: unable to clear directory entry.",
90
0
     function );
91
92
0
    memory_free(
93
0
     *directory_entry );
94
95
0
    *directory_entry = NULL;
96
97
0
    return( -1 );
98
0
  }
99
523
  return( 1 );
100
101
0
on_error:
102
0
  if( *directory_entry != NULL )
103
0
  {
104
0
    memory_free(
105
0
     *directory_entry );
106
107
0
    *directory_entry = NULL;
108
0
  }
109
0
  return( -1 );
110
523
}
111
112
/* Frees a directory entry
113
 * Returns 1 if successful or -1 on error
114
 */
115
int libfsntfs_directory_entry_free(
116
     libfsntfs_directory_entry_t **directory_entry,
117
     libcerror_error_t **error )
118
523
{
119
523
  static char *function = "libfsntfs_directory_entry_free";
120
523
  int result            = 1;
121
122
523
  if( directory_entry == NULL )
123
0
  {
124
0
    libcerror_error_set(
125
0
     error,
126
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
127
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
128
0
     "%s: invalid directory entry.",
129
0
     function );
130
131
0
    return( -1 );
132
0
  }
133
523
  if( *directory_entry != NULL )
134
523
  {
135
523
    if( ( *directory_entry )->file_name_values != NULL )
136
94
    {
137
94
      if( libfsntfs_file_name_values_free(
138
94
           &( ( *directory_entry )->file_name_values ),
139
94
           error ) != 1 )
140
0
      {
141
0
        libcerror_error_set(
142
0
         error,
143
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
144
0
         LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
145
0
         "%s: unable to free file name values.",
146
0
         function );
147
148
0
        result = -1;
149
0
      }
150
94
    }
151
523
    if( ( *directory_entry )->short_file_name_values != NULL )
152
431
    {
153
431
      if( libfsntfs_file_name_values_free(
154
431
           &( ( *directory_entry )->short_file_name_values ),
155
431
           error ) != 1 )
156
0
      {
157
0
        libcerror_error_set(
158
0
         error,
159
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
160
0
         LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
161
0
         "%s: unable to free short file name values.",
162
0
         function );
163
164
0
        result = -1;
165
0
      }
166
431
    }
167
523
    memory_free(
168
523
     *directory_entry );
169
170
523
    *directory_entry = NULL;
171
523
  }
172
523
  return( result );
173
523
}
174
175
/* Clones a directory entry
176
 * Returns 1 if successful or -1 on error
177
 */
178
int libfsntfs_directory_entry_clone(
179
     libfsntfs_directory_entry_t **destination_directory_entry,
180
     libfsntfs_directory_entry_t *source_directory_entry,
181
     libcerror_error_t **error )
182
47
{
183
47
  static char *function = "libfsntfs_directory_entry_clone";
184
185
47
  if( destination_directory_entry == NULL )
186
0
  {
187
0
    libcerror_error_set(
188
0
     error,
189
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
190
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
191
0
     "%s: invalid directory entry.",
192
0
     function );
193
194
0
    return( -1 );
195
0
  }
196
47
  if( *destination_directory_entry != NULL )
197
0
  {
198
0
    libcerror_error_set(
199
0
     error,
200
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
201
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
202
0
     "%s: invalid destination directory entry value already set.",
203
0
     function );
204
205
0
    return( -1 );
206
0
  }
207
47
  if( source_directory_entry == NULL )
208
0
  {
209
0
    *destination_directory_entry = source_directory_entry;
210
211
0
    return( 1 );
212
0
  }
213
47
  if( libfsntfs_directory_entry_initialize(
214
47
       destination_directory_entry,
215
47
       error ) != 1 )
216
0
  {
217
0
    libcerror_error_set(
218
0
     error,
219
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
220
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
221
0
     "%s: unable to create destination directory entry.",
222
0
     function );
223
224
0
    goto on_error;
225
0
  }
226
47
  if( libfsntfs_file_name_values_clone(
227
47
       &( ( *destination_directory_entry )->file_name_values ),
228
47
       source_directory_entry->file_name_values,
229
47
       error ) != 1 )
230
0
  {
231
0
    libcerror_error_set(
232
0
     error,
233
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
234
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
235
0
     "%s: unable to create destination file name values.",
236
0
     function );
237
238
0
    goto on_error;
239
0
  }
240
47
  if( libfsntfs_file_name_values_clone(
241
47
       &( ( *destination_directory_entry )->short_file_name_values ),
242
47
       source_directory_entry->short_file_name_values,
243
47
       error ) != 1 )
244
0
  {
245
0
    libcerror_error_set(
246
0
     error,
247
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
248
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
249
0
     "%s: unable to create destination short file name values.",
250
0
     function );
251
252
0
    goto on_error;
253
0
  }
254
47
  ( *destination_directory_entry )->file_reference = source_directory_entry->file_reference;
255
256
47
  return( 1 );
257
258
0
on_error:
259
0
  if( *destination_directory_entry != NULL )
260
0
  {
261
0
    libfsntfs_directory_entry_free(
262
0
     destination_directory_entry,
263
0
     NULL );
264
0
  }
265
0
  return( -1 );
266
47
}
267
268
/* Compares 2 directory entries by file reference
269
 * Returns LIBCDATA_COMPARE_LESS, LIBCDATA_COMPARE_EQUAL, LIBCDATA_COMPARE_GREATER if successful or -1 on error
270
 */
271
int libfsntfs_directory_entry_compare_by_file_reference(
272
     libfsntfs_directory_entry_t *first_directory_entry,
273
     libfsntfs_directory_entry_t *second_directory_entry,
274
     libcerror_error_t **error )
275
1.62k
{
276
1.62k
  static char *function           = "libfsntfs_directory_entry_compare_by_file_reference";
277
1.62k
  uint64_t first_mft_entry_index  = 0;
278
1.62k
  uint64_t second_mft_entry_index = 0;
279
1.62k
  uint16_t first_sequence_number  = 0;
280
1.62k
  uint16_t second_sequence_number = 0;
281
282
1.62k
  if( first_directory_entry == NULL )
283
0
  {
284
0
    libcerror_error_set(
285
0
     error,
286
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
287
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
288
0
     "%s: invalid first directory entry.",
289
0
     function );
290
291
0
    return( -1 );
292
0
  }
293
1.62k
  if( second_directory_entry == NULL )
294
0
  {
295
0
    libcerror_error_set(
296
0
     error,
297
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
298
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
299
0
     "%s: invalid second directory entry.",
300
0
     function );
301
302
0
    return( -1 );
303
0
  }
304
1.62k
  first_mft_entry_index  = first_directory_entry->file_reference & 0xffffffffffffUL;
305
1.62k
  second_mft_entry_index = second_directory_entry->file_reference & 0xffffffffffffUL;
306
307
1.62k
  if( first_mft_entry_index < second_mft_entry_index )
308
316
  {
309
316
    return( LIBCDATA_COMPARE_LESS );
310
316
  }
311
1.30k
  else if( first_mft_entry_index > second_mft_entry_index )
312
1.22k
  {
313
1.22k
    return( LIBCDATA_COMPARE_GREATER );
314
1.22k
  }
315
80
  first_sequence_number  = (uint16_t) ( first_directory_entry->file_reference >> 48 );
316
80
  second_sequence_number = (uint16_t) ( second_directory_entry->file_reference >> 48 );
317
318
80
  if( first_sequence_number < second_sequence_number )
319
23
  {
320
23
    return( LIBCDATA_COMPARE_LESS );
321
23
  }
322
57
  else if( first_sequence_number > second_sequence_number )
323
38
  {
324
38
    return( LIBCDATA_COMPARE_GREATER );
325
38
  }
326
19
  return( LIBCDATA_COMPARE_EQUAL );
327
80
}
328
329
/* Retrieves the MFT entry index
330
 * Returns 1 if successful or -1 on error
331
 */
332
int libfsntfs_directory_entry_get_mft_entry_index(
333
     libfsntfs_directory_entry_t *directory_entry,
334
     uint64_t *mft_entry_index,
335
     libcerror_error_t **error )
336
47
{
337
47
  static char *function = "libfsntfs_directory_entry_get_mft_entry_index";
338
339
47
  if( directory_entry == NULL )
340
0
  {
341
0
    libcerror_error_set(
342
0
     error,
343
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
344
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
345
0
     "%s: invalid directory entry.",
346
0
     function );
347
348
0
    return( -1 );
349
0
  }
350
47
  if( mft_entry_index == NULL )
351
0
  {
352
0
    libcerror_error_set(
353
0
     error,
354
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
355
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
356
0
     "%s: invalid MFT entry index.",
357
0
     function );
358
359
0
    return( -1 );
360
0
  }
361
47
  if( ( directory_entry->file_reference & 0xffffffffffffUL ) > (uint64_t) INT_MAX )
362
10
  {
363
10
    libcerror_error_set(
364
10
     error,
365
10
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
366
10
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
367
10
     "%s: invalid MFT entry index value out of bounds.",
368
10
     function );
369
370
10
    return( -1 );
371
10
  }
372
37
  *mft_entry_index = (int) ( directory_entry->file_reference & 0xffffffffffffUL );
373
374
37
  return( 1 );
375
47
}
376
377
/* Retrieves the file reference
378
 * Returns 1 if successful or -1 on error
379
 */
380
int libfsntfs_directory_entry_get_file_reference(
381
     libfsntfs_directory_entry_t *directory_entry,
382
     uint64_t *file_reference,
383
     libcerror_error_t **error )
384
0
{
385
0
  static char *function = "libfsntfs_directory_entry_get_file_reference";
386
387
0
  if( directory_entry == NULL )
388
0
  {
389
0
    libcerror_error_set(
390
0
     error,
391
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
392
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
393
0
     "%s: invalid directory entry.",
394
0
     function );
395
396
0
    return( -1 );
397
0
  }
398
0
  if( file_reference == NULL )
399
0
  {
400
0
    libcerror_error_set(
401
0
     error,
402
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
403
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
404
0
     "%s: invalid file reference.",
405
0
     function );
406
407
0
    return( -1 );
408
0
  }
409
0
  *file_reference = directory_entry->file_reference;
410
411
0
  return( 1 );
412
0
}
413
414
/* Retrieves the parent file reference
415
 * Returns 1 if successful or -1 on error
416
 */
417
int libfsntfs_directory_entry_get_parent_file_reference(
418
     libfsntfs_directory_entry_t *directory_entry,
419
     uint64_t *parent_file_reference,
420
     libcerror_error_t **error )
421
0
{
422
0
  static char *function = "libfsntfs_directory_entry_get_parent_file_reference";
423
424
0
  if( directory_entry == NULL )
425
0
  {
426
0
    libcerror_error_set(
427
0
     error,
428
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
429
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
430
0
     "%s: invalid directory entry.",
431
0
     function );
432
433
0
    return( -1 );
434
0
  }
435
0
  if( libfsntfs_file_name_values_get_parent_file_reference(
436
0
       directory_entry->file_name_values,
437
0
       parent_file_reference,
438
0
       error ) != 1 )
439
0
  {
440
0
    libcerror_error_set(
441
0
     error,
442
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
443
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
444
0
     "%s: unable to retrieve parent reference from file name values.",
445
0
     function );
446
447
0
    return( -1 );
448
0
  }
449
0
  return( 1 );
450
0
}
451
452
/* Retrieves the size of the UTF-8 encoded name
453
 * This function uses UTF-8 RFC 2279 (or 6-byte UTF-8) to support characters outside Unicode
454
 * The returned size includes the end of string character
455
 * Returns 1 if successful or -1 on error
456
 */
457
int libfsntfs_directory_entry_get_utf8_name_size(
458
     libfsntfs_directory_entry_t *directory_entry,
459
     size_t *utf8_string_size,
460
     libcerror_error_t **error )
461
0
{
462
0
  static char *function = "libfsntfs_directory_entry_get_utf8_name_size";
463
464
0
  if( directory_entry == NULL )
465
0
  {
466
0
    libcerror_error_set(
467
0
     error,
468
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
469
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
470
0
     "%s: invalid directory entry.",
471
0
     function );
472
473
0
    return( -1 );
474
0
  }
475
0
  if( libfsntfs_file_name_values_get_utf8_name_size(
476
0
       directory_entry->file_name_values,
477
0
       utf8_string_size,
478
0
       error ) != 1 )
479
0
  {
480
0
    libcerror_error_set(
481
0
     error,
482
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
483
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
484
0
     "%s: unable to retrieve size of UTF-8 name from file name values.",
485
0
     function );
486
487
0
    return( -1 );
488
0
  }
489
0
  return( 1 );
490
0
}
491
492
/* Retrieves the UTF-8 encoded name
493
 * This function uses UTF-8 RFC 2279 (or 6-byte UTF-8) to support characters outside Unicode
494
 * The size should include the end of string character
495
 * Returns 1 if successful or -1 on error
496
 */
497
int libfsntfs_directory_entry_get_utf8_name(
498
     libfsntfs_directory_entry_t *directory_entry,
499
     uint8_t *utf8_string,
500
     size_t utf8_string_size,
501
     libcerror_error_t **error )
502
0
{
503
0
  static char *function = "libfsntfs_directory_entry_get_utf8_name";
504
505
0
  if( directory_entry == NULL )
506
0
  {
507
0
    libcerror_error_set(
508
0
     error,
509
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
510
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
511
0
     "%s: invalid directory entry.",
512
0
     function );
513
514
0
    return( -1 );
515
0
  }
516
0
  if( libfsntfs_file_name_values_get_utf8_name(
517
0
       directory_entry->file_name_values,
518
0
       utf8_string,
519
0
       utf8_string_size,
520
0
       error ) != 1 )
521
0
  {
522
0
    libcerror_error_set(
523
0
     error,
524
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
525
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
526
0
     "%s: unable to retrieve UTF-8 name from file name values.",
527
0
     function );
528
529
0
    return( -1 );
530
0
  }
531
0
  return( 1 );
532
0
}
533
534
/* Retrieves the size of the UTF-16 encoded name
535
 * This function uses UCS-2 (with surrogates) to support characters outside Unicode
536
 * The returned size includes the end of string character
537
 * Returns 1 if successful or -1 on error
538
 */
539
int libfsntfs_directory_entry_get_utf16_name_size(
540
     libfsntfs_directory_entry_t *directory_entry,
541
     size_t *utf16_string_size,
542
     libcerror_error_t **error )
543
0
{
544
0
  static char *function = "libfsntfs_directory_entry_get_utf16_name_size";
545
546
0
  if( directory_entry == NULL )
547
0
  {
548
0
    libcerror_error_set(
549
0
     error,
550
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
551
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
552
0
     "%s: invalid directory entry.",
553
0
     function );
554
555
0
    return( -1 );
556
0
  }
557
0
  if( libfsntfs_file_name_values_get_utf16_name_size(
558
0
       directory_entry->file_name_values,
559
0
       utf16_string_size,
560
0
       error ) != 1 )
561
0
  {
562
0
    libcerror_error_set(
563
0
     error,
564
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
565
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
566
0
     "%s: unable to retrieve size of UTF-16 name from file name values.",
567
0
     function );
568
569
0
    return( -1 );
570
0
  }
571
0
  return( 1 );
572
0
}
573
574
/* Retrieves the UTF-16 encoded name
575
 * This function uses UCS-2 (with surrogates) to support characters outside Unicode
576
 * The size should include the end of string character
577
 * Returns 1 if successful or -1 on error
578
 */
579
int libfsntfs_directory_entry_get_utf16_name(
580
     libfsntfs_directory_entry_t *directory_entry,
581
     uint16_t *utf16_string,
582
     size_t utf16_string_size,
583
     libcerror_error_t **error )
584
0
{
585
0
  static char *function = "libfsntfs_directory_entry_get_utf16_name";
586
587
0
  if( directory_entry == NULL )
588
0
  {
589
0
    libcerror_error_set(
590
0
     error,
591
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
592
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
593
0
     "%s: invalid directory entry.",
594
0
     function );
595
596
0
    return( -1 );
597
0
  }
598
0
  if( libfsntfs_file_name_values_get_utf16_name(
599
0
       directory_entry->file_name_values,
600
0
       utf16_string,
601
0
       utf16_string_size,
602
0
       error ) != 1 )
603
0
  {
604
0
    libcerror_error_set(
605
0
     error,
606
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
607
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
608
0
     "%s: unable to retrieve UTF-16 name from file name values.",
609
0
     function );
610
611
0
    return( -1 );
612
0
  }
613
0
  return( 1 );
614
0
}
615