Coverage Report

Created: 2026-02-19 06:51

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libolecf/libolecf/libolecf_directory_entry.c
Line
Count
Source
1
/*
2
 * The directory entry functions
3
 *
4
 * Copyright (C) 2008-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 <byte_stream.h>
24
#include <memory.h>
25
#include <types.h>
26
27
#include "libolecf_debug.h"
28
#include "libolecf_definitions.h"
29
#include "libolecf_directory_entry.h"
30
#include "libolecf_libcdata.h"
31
#include "libolecf_libcerror.h"
32
#include "libolecf_libcnotify.h"
33
#include "libolecf_libfdatetime.h"
34
#include "libolecf_libfguid.h"
35
#include "libolecf_libuna.h"
36
37
#include "olecf_directory.h"
38
39
/* Creates a directory entry
40
 * Make sure the value directoyry_entry is referencing, is set to NULL
41
 * Returns 1 if successful or -1 on error
42
 */
43
int libolecf_directory_entry_initialize(
44
     libolecf_directory_entry_t **directory_entry,
45
     libcerror_error_t **error )
46
229k
{
47
229k
  static char *function = "libolecf_directory_entry_initialize";
48
49
229k
  if( directory_entry == NULL )
50
0
  {
51
0
    libcerror_error_set(
52
0
     error,
53
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
54
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
55
0
     "%s: invalid directory_entry.",
56
0
     function );
57
58
0
    return( -1 );
59
0
  }
60
229k
  if( *directory_entry != NULL )
61
0
  {
62
0
    libcerror_error_set(
63
0
     error,
64
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
65
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
66
0
     "%s: invalid directory entry value already set.",
67
0
     function );
68
69
0
    return( -1 );
70
0
  }
71
229k
  *directory_entry = memory_allocate_structure(
72
229k
                      libolecf_directory_entry_t );
73
74
229k
  if( *directory_entry == NULL )
75
0
  {
76
0
    libcerror_error_set(
77
0
     error,
78
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
79
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
80
0
     "%s: unable to create directory entry.",
81
0
     function );
82
83
0
    goto on_error;
84
0
  }
85
229k
  if( memory_set(
86
229k
       *directory_entry,
87
229k
       0,
88
229k
       sizeof( libolecf_directory_entry_t ) ) == NULL )
89
0
  {
90
0
    libcerror_error_set(
91
0
     error,
92
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
93
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
94
0
     "%s: unable to clear directory entry.",
95
0
     function );
96
97
0
    goto on_error;
98
0
  }
99
229k
  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
229k
}
111
112
/* Frees a directory entry
113
 * Returns 1 if successful or -1 on error
114
 */
115
int libolecf_directory_entry_free(
116
     libolecf_directory_entry_t **directory_entry,
117
     libcerror_error_t **error )
118
223k
{
119
223k
  static char *function = "libolecf_directory_entry_free";
120
121
223k
  if( directory_entry == NULL )
122
0
  {
123
0
    libcerror_error_set(
124
0
     error,
125
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
126
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
127
0
     "%s: invalid directory entry.",
128
0
     function );
129
130
0
    return( -1 );
131
0
  }
132
223k
  if( *directory_entry != NULL )
133
223k
  {
134
223k
    if( ( *directory_entry )->name != NULL )
135
193k
    {
136
193k
      memory_free(
137
193k
       ( *directory_entry )->name );
138
193k
    }
139
223k
    memory_free(
140
223k
     *directory_entry );
141
142
223k
    *directory_entry = NULL;
143
223k
  }
144
223k
  return( 1 );
145
223k
}
146
147
/* Frees a directory entry that is not part of the directory tree
148
 * Returns 1 if successful or -1 on error
149
 */
150
int libolecf_directory_entry_free_not_in_tree(
151
     libolecf_directory_entry_t **directory_entry,
152
     libcerror_error_t **error )
153
22.3k
{
154
22.3k
  static char *function = "libolecf_directory_entry_free_not_in_tree";
155
156
22.3k
  if( directory_entry == NULL )
157
0
  {
158
0
    libcerror_error_set(
159
0
     error,
160
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
161
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
162
0
     "%s: invalid directory entry.",
163
0
     function );
164
165
0
    return( -1 );
166
0
  }
167
22.3k
  if( ( *directory_entry != NULL )
168
22.3k
   && ( ( *directory_entry )->set_in_tree == 0 ) )
169
6.55k
  {
170
6.55k
    if( ( *directory_entry )->name != NULL )
171
5.48k
    {
172
5.48k
      memory_free(
173
5.48k
       ( *directory_entry )->name );
174
5.48k
    }
175
6.55k
    memory_free(
176
6.55k
     *directory_entry );
177
178
6.55k
    *directory_entry = NULL;
179
6.55k
  }
180
22.3k
  return( 1 );
181
22.3k
}
182
183
/* Compares two directory entries
184
 * Returns LIBCDATA_COMPARE_LESS, LIBCDATA_COMPARE_EQUAL, LIBCDATA_COMPARE_GREATER if successful or -1 on error
185
 */
186
int libolecf_directory_entry_compare(
187
     libolecf_directory_entry_t *first_directory_entry,
188
     libolecf_directory_entry_t *second_directory_entry,
189
     libcerror_error_t **error )
190
19.4M
{
191
19.4M
  static char *function = "libolecf_directory_entry_compare";
192
193
19.4M
  if( first_directory_entry == NULL )
194
0
  {
195
0
    libcerror_error_set(
196
0
     error,
197
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
198
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
199
0
     "%s: invalid first directory entry.",
200
0
     function );
201
202
0
    return( -1 );
203
0
  }
204
19.4M
  if( second_directory_entry == NULL )
205
0
  {
206
0
    libcerror_error_set(
207
0
     error,
208
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
209
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
210
0
     "%s: invalid second directory entry.",
211
0
     function );
212
213
0
    return( -1 );
214
0
  }
215
19.4M
  if( first_directory_entry->directory_identifier < second_directory_entry->directory_identifier )
216
51.7k
  {
217
51.7k
    return( LIBCDATA_COMPARE_LESS );
218
51.7k
  }
219
19.3M
  if( first_directory_entry->directory_identifier > second_directory_entry->directory_identifier )
220
19.3M
  {
221
19.3M
    return( LIBCDATA_COMPARE_GREATER );
222
19.3M
  }
223
0
  return( LIBCDATA_COMPARE_EQUAL );
224
19.3M
}
225
226
/* Reads a directory entry
227
 * Returns 1 if successful, 0 if empty or -1 on error
228
 */
229
int libolecf_directory_entry_read_data(
230
     libolecf_directory_entry_t *directory_entry,
231
     int directory_entry_index,
232
     const uint8_t *data,
233
     size_t data_size,
234
     uint8_t byte_order,
235
     libcerror_error_t **error )
236
229k
{
237
229k
  static char *function   = "libolecf_directory_entry_read_data";
238
229k
  uint16_t name_data_size = 0;
239
240
#if defined( HAVE_DEBUG_OUTPUT )
241
  uint32_t value_32bit  = 0;
242
#endif
243
244
229k
  if( directory_entry == NULL )
245
0
  {
246
0
    libcerror_error_set(
247
0
     error,
248
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
249
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
250
0
     "%s: invalid directory entry.",
251
0
     function );
252
253
0
    return( -1 );
254
0
  }
255
229k
  if( data == NULL )
256
0
  {
257
0
    libcerror_error_set(
258
0
     error,
259
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
260
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
261
0
     "%s: invalid data.",
262
0
     function );
263
264
0
    return( -1 );
265
0
  }
266
229k
  if( ( data_size < sizeof( olecf_directory_entry_t ) )
267
229k
   || ( data_size > (size_t) SSIZE_MAX ) )
268
0
  {
269
0
    libcerror_error_set(
270
0
     error,
271
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
272
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
273
0
     "%s: invalid data size value out of bounds.",
274
0
     function );
275
276
0
    return( -1 );
277
0
  }
278
229k
  if( ( byte_order != LIBOLECF_ENDIAN_BIG )
279
225k
   && ( byte_order != LIBOLECF_ENDIAN_LITTLE ) )
280
0
  {
281
0
    libcerror_error_set(
282
0
     error,
283
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
284
0
     LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
285
0
     "%s: unsupported byte order.",
286
0
     function );
287
288
0
    return( -1 );
289
0
  }
290
229k
  directory_entry->type = ( (olecf_directory_entry_t *) data )->type;
291
292
/* TODO use memory compare */
293
229k
  if( directory_entry->type == LIBOLECF_ITEM_TYPE_EMPTY )
294
25.7k
  {
295
25.7k
    return( 0 );
296
25.7k
  }
297
203k
  if( byte_order == LIBOLECF_ENDIAN_LITTLE )
298
201k
  {
299
201k
    byte_stream_copy_to_uint16_little_endian(
300
201k
     ( (olecf_directory_entry_t *) data )->name_data_size,
301
201k
     name_data_size );
302
201k
  }
303
2.01k
  else if( byte_order == LIBOLECF_ENDIAN_BIG )
304
2.01k
  {
305
2.01k
    byte_stream_copy_to_uint16_big_endian(
306
2.01k
     ( (olecf_directory_entry_t *) data )->name_data_size,
307
2.01k
     name_data_size );
308
2.01k
  }
309
203k
  if( name_data_size > 0 )
310
198k
  {
311
198k
    if( (size_t) name_data_size > sizeof( olecf_directory_entry_t ) )
312
51
    {
313
51
      libcerror_error_set(
314
51
       error,
315
51
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
316
51
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
317
51
       "%s: name byte size value out of bounds.",
318
51
       function );
319
320
51
      goto on_error;
321
51
    }
322
198k
    directory_entry->name = (uint8_t *) memory_allocate(
323
198k
                                         sizeof( uint8_t ) * name_data_size );
324
325
198k
    if( directory_entry->name == NULL )
326
0
    {
327
0
      libcerror_error_set(
328
0
       error,
329
0
       LIBCERROR_ERROR_DOMAIN_MEMORY,
330
0
       LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
331
0
       "%s: unable to create name.",
332
0
       function );
333
334
0
      goto on_error;
335
0
    }
336
198k
    if( memory_copy(
337
198k
         directory_entry->name,
338
198k
         ( (olecf_directory_entry_t *) data )->name,
339
198k
         name_data_size ) == NULL )
340
0
    {
341
0
      libcerror_error_set(
342
0
       error,
343
0
       LIBCERROR_ERROR_DOMAIN_MEMORY,
344
0
       LIBCERROR_MEMORY_ERROR_COPY_FAILED,
345
0
       "%s: unable to copy name.",
346
0
       function );
347
348
0
      goto on_error;
349
0
    }
350
198k
  }
351
203k
  directory_entry->directory_identifier = (uint32_t) directory_entry_index;
352
203k
  directory_entry->name_size            = (size_t) name_data_size;
353
354
203k
  if( byte_order == LIBOLECF_ENDIAN_LITTLE )
355
201k
  {
356
201k
    byte_stream_copy_to_uint32_little_endian(
357
201k
     ( (olecf_directory_entry_t *) data )->previous_directory_identifier,
358
201k
     directory_entry->previous_directory_identifier );
359
360
201k
    byte_stream_copy_to_uint32_little_endian(
361
201k
     ( (olecf_directory_entry_t *) data )->next_directory_identifier,
362
201k
     directory_entry->next_directory_identifier );
363
364
201k
    byte_stream_copy_to_uint32_little_endian(
365
201k
     ( (olecf_directory_entry_t *) data )->sub_directory_identifier,
366
201k
     directory_entry->sub_directory_identifier );
367
368
201k
    byte_stream_copy_to_uint64_little_endian(
369
201k
     ( (olecf_directory_entry_t *) data )->creation_time,
370
201k
     directory_entry->creation_time );
371
372
201k
    byte_stream_copy_to_uint64_little_endian(
373
201k
     ( (olecf_directory_entry_t *) data )->modification_time,
374
201k
     directory_entry->modification_time );
375
376
201k
    byte_stream_copy_to_uint32_little_endian(
377
201k
     ( (olecf_directory_entry_t *) data )->sector_identifier,
378
201k
     directory_entry->sector_identifier );
379
380
201k
    byte_stream_copy_to_uint32_little_endian(
381
201k
     ( (olecf_directory_entry_t *) data )->size,
382
201k
     directory_entry->size );
383
201k
  }
384
1.99k
  else if( byte_order == LIBOLECF_ENDIAN_BIG )
385
1.99k
  {
386
1.99k
    byte_stream_copy_to_uint32_big_endian(
387
1.99k
     ( (olecf_directory_entry_t *) data )->previous_directory_identifier,
388
1.99k
     directory_entry->previous_directory_identifier );
389
390
1.99k
    byte_stream_copy_to_uint32_big_endian(
391
1.99k
     ( (olecf_directory_entry_t *) data )->next_directory_identifier,
392
1.99k
     directory_entry->next_directory_identifier );
393
394
1.99k
    byte_stream_copy_to_uint32_big_endian(
395
1.99k
     ( (olecf_directory_entry_t *) data )->sub_directory_identifier,
396
1.99k
     directory_entry->sub_directory_identifier );
397
398
1.99k
    byte_stream_copy_to_uint64_big_endian(
399
1.99k
     ( (olecf_directory_entry_t *) data )->creation_time,
400
1.99k
     directory_entry->creation_time );
401
402
1.99k
    byte_stream_copy_to_uint64_big_endian(
403
1.99k
     ( (olecf_directory_entry_t *) data )->modification_time,
404
1.99k
     directory_entry->modification_time );
405
406
1.99k
    byte_stream_copy_to_uint32_big_endian(
407
1.99k
     ( (olecf_directory_entry_t *) data )->sector_identifier,
408
1.99k
     directory_entry->sector_identifier );
409
410
1.99k
    byte_stream_copy_to_uint32_big_endian(
411
1.99k
     ( (olecf_directory_entry_t *) data )->size,
412
1.99k
     directory_entry->size );
413
1.99k
  }
414
#if defined( HAVE_DEBUG_OUTPUT )
415
  if( libcnotify_verbose != 0 )
416
  {
417
    libcnotify_printf(
418
     "%s: identifier\t\t\t\t: 0x%08" PRIx32 "\n",
419
     function,
420
     directory_entry->directory_identifier );
421
422
    if( libolecf_debug_print_utf16_string_value(
423
         function,
424
         "name\t\t\t\t",
425
         directory_entry->name,
426
         directory_entry->name_size,
427
         byte_order,
428
         error ) != 1 )
429
    {
430
      libcerror_error_set(
431
       error,
432
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
433
       LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
434
       "%s: unable to print UTF-16 string value.",
435
       function );
436
437
      goto on_error;
438
    }
439
    libcnotify_printf(
440
     "\n" );
441
442
    libcnotify_printf(
443
     "%s: name data size\t\t\t: %" PRIu16 "\n",
444
     function,
445
     name_data_size );
446
447
    libcnotify_printf(
448
     "%s: type\t\t\t\t: 0x%02" PRIx8 " (%s)\n",
449
     function,
450
     directory_entry->type,
451
     libolecf_debug_print_item_type(
452
      directory_entry->type ) );
453
454
    libcnotify_printf(
455
     "%s: node color\t\t\t\t: 0x%02" PRIx8 "\n",
456
     function,
457
     ( (olecf_directory_entry_t *) data )->node_color );
458
459
    libcnotify_printf(
460
     "%s: previous directory identifier\t: 0x%08" PRIx32 "\n",
461
     function,
462
     directory_entry->previous_directory_identifier );
463
464
    libcnotify_printf(
465
     "%s: next directory identifier\t\t: 0x%08" PRIx32 "\n",
466
     function,
467
     directory_entry->next_directory_identifier );
468
469
    libcnotify_printf(
470
     "%s: sub directory identifier\t\t: 0x%08" PRIx32 "\n",
471
     function,
472
     directory_entry->sub_directory_identifier );
473
474
    if( libolecf_debug_print_guid_value(
475
         function,
476
         "class identifier\t\t\t",
477
         ( (olecf_directory_entry_t *) data )->class_identifier,
478
         16,
479
         byte_order,
480
         LIBFGUID_STRING_FORMAT_FLAG_USE_LOWER_CASE,
481
         error ) != 1 )
482
    {
483
      libcerror_error_set(
484
       error,
485
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
486
       LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
487
       "%s: unable to print GUID value.",
488
       function );
489
490
      goto on_error;
491
    }
492
    if( byte_order == LIBOLECF_ENDIAN_LITTLE )
493
    {
494
      byte_stream_copy_to_uint32_little_endian(
495
       ( (olecf_directory_entry_t *) data )->user_flags,
496
       value_32bit );
497
    }
498
    else if( byte_order == LIBOLECF_ENDIAN_BIG )
499
    {
500
      byte_stream_copy_to_uint32_big_endian(
501
       ( (olecf_directory_entry_t *) data )->user_flags,
502
       value_32bit );
503
    }
504
    libcnotify_printf(
505
     "%s: user flags\t\t\t\t: 0x%08" PRIx32 "\n",
506
     function,
507
     value_32bit );
508
509
    if( libolecf_debug_print_filetime_value(
510
         function,
511
         "directory entry creation time\t",
512
         ( (olecf_directory_entry_t *) data )->creation_time,
513
         8,
514
         byte_order,
515
         LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME_NANO_SECONDS,
516
         error ) != 1 )
517
    {
518
      libcerror_error_set(
519
       error,
520
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
521
       LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
522
       "%s: unable to print filetime value.",
523
       function );
524
525
      goto on_error;
526
    }
527
    if( libolecf_debug_print_filetime_value(
528
         function,
529
         "directory entry modification time\t",
530
         ( (olecf_directory_entry_t *) data )->modification_time,
531
         8,
532
         byte_order,
533
         LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME_NANO_SECONDS,
534
         error ) != 1 )
535
    {
536
      libcerror_error_set(
537
       error,
538
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
539
       LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
540
       "%s: unable to print filetime value.",
541
       function );
542
543
      goto on_error;
544
    }
545
    libcnotify_printf(
546
     "%s: sector identifier\t\t\t: 0x%08" PRIx32 "\n",
547
     function,
548
     directory_entry->sector_identifier );
549
    libcnotify_printf(
550
     "%s: size\t\t\t\t: %" PRIu32 "\n",
551
     function,
552
     directory_entry->size );
553
554
    libcnotify_printf(
555
     "%s: reserved1:\n",
556
     function );
557
    libcnotify_print_data(
558
     ( (olecf_directory_entry_t *) data )->reserved1,
559
     4,
560
     0 );
561
  }
562
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
563
564
203k
  return( 1 );
565
566
51
on_error:
567
51
  if( directory_entry->name != NULL )
568
0
  {
569
0
    memory_free(
570
0
     directory_entry->name );
571
572
0
    directory_entry->name = NULL;
573
0
  }
574
51
  directory_entry->name_size = 0;
575
576
51
  return( -1 );
577
203k
}
578