Coverage Report

Created: 2025-06-24 07:14

/src/libolecf/libolecf/libolecf_directory_entry.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * The directory entry functions
3
 *
4
 * Copyright (C) 2008-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 "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
200k
{
47
200k
  static char *function = "libolecf_directory_entry_initialize";
48
49
200k
  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
200k
  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
200k
  *directory_entry = memory_allocate_structure(
72
200k
                      libolecf_directory_entry_t );
73
74
200k
  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
200k
  if( memory_set(
86
200k
       *directory_entry,
87
200k
       0,
88
200k
       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
200k
  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
200k
}
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
193k
{
119
193k
  static char *function = "libolecf_directory_entry_free";
120
121
193k
  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
193k
  if( *directory_entry != NULL )
133
193k
  {
134
193k
    if( ( *directory_entry )->name != NULL )
135
165k
    {
136
165k
      memory_free(
137
165k
       ( *directory_entry )->name );
138
165k
    }
139
193k
    memory_free(
140
193k
     *directory_entry );
141
142
193k
    *directory_entry = NULL;
143
193k
  }
144
193k
  return( 1 );
145
193k
}
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
23.5k
{
154
23.5k
  static char *function = "libolecf_directory_entry_free_not_in_tree";
155
156
23.5k
  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
23.5k
  if( ( *directory_entry != NULL )
168
23.5k
   && ( ( *directory_entry )->set_in_tree == 0 ) )
169
7.28k
  {
170
7.28k
    if( ( *directory_entry )->name != NULL )
171
5.85k
    {
172
5.85k
      memory_free(
173
5.85k
       ( *directory_entry )->name );
174
5.85k
    }
175
7.28k
    memory_free(
176
7.28k
     *directory_entry );
177
178
7.28k
    *directory_entry = NULL;
179
7.28k
  }
180
23.5k
  return( 1 );
181
23.5k
}
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.0M
{
191
19.0M
  static char *function = "libolecf_directory_entry_compare";
192
193
19.0M
  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.0M
  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.0M
  if( first_directory_entry->directory_identifier < second_directory_entry->directory_identifier )
216
49.0k
  {
217
49.0k
    return( LIBCDATA_COMPARE_LESS );
218
49.0k
  }
219
19.0M
  if( first_directory_entry->directory_identifier > second_directory_entry->directory_identifier )
220
19.0M
  {
221
19.0M
    return( LIBCDATA_COMPARE_GREATER );
222
19.0M
  }
223
0
  return( LIBCDATA_COMPARE_EQUAL );
224
19.0M
}
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
200k
{
237
200k
  static char *function   = "libolecf_directory_entry_read_data";
238
200k
  uint16_t name_data_size = 0;
239
240
#if defined( HAVE_DEBUG_OUTPUT )
241
  uint32_t value_32bit  = 0;
242
#endif
243
244
200k
  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
200k
  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
200k
  if( ( data_size < sizeof( olecf_directory_entry_t ) )
267
200k
   || ( 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
200k
  if( ( byte_order != LIBOLECF_ENDIAN_BIG )
279
200k
   && ( 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
200k
  directory_entry->type = ( (olecf_directory_entry_t *) data )->type;
291
292
/* TODO use memory compare */
293
200k
  if( directory_entry->type == LIBOLECF_ITEM_TYPE_EMPTY )
294
23.9k
  {
295
23.9k
    return( 0 );
296
23.9k
  }
297
176k
  if( byte_order == LIBOLECF_ENDIAN_LITTLE )
298
174k
  {
299
174k
    byte_stream_copy_to_uint16_little_endian(
300
174k
     ( (olecf_directory_entry_t *) data )->name_data_size,
301
174k
     name_data_size );
302
174k
  }
303
1.97k
  else if( byte_order == LIBOLECF_ENDIAN_BIG )
304
1.97k
  {
305
1.97k
    byte_stream_copy_to_uint16_big_endian(
306
1.97k
     ( (olecf_directory_entry_t *) data )->name_data_size,
307
1.97k
     name_data_size );
308
1.97k
  }
309
176k
  if( name_data_size > 0 )
310
171k
  {
311
171k
    if( (size_t) name_data_size > sizeof( olecf_directory_entry_t ) )
312
53
    {
313
53
      libcerror_error_set(
314
53
       error,
315
53
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
316
53
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
317
53
       "%s: name byte size value out of bounds.",
318
53
       function );
319
320
53
      goto on_error;
321
53
    }
322
171k
    directory_entry->name = (uint8_t *) memory_allocate(
323
171k
                                         sizeof( uint8_t ) * name_data_size );
324
325
171k
    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
171k
    if( memory_copy(
337
171k
         directory_entry->name,
338
171k
         ( (olecf_directory_entry_t *) data )->name,
339
171k
         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
171k
  }
351
176k
  directory_entry->directory_identifier = (uint32_t) directory_entry_index;
352
176k
  directory_entry->name_size            = (size_t) name_data_size;
353
354
176k
  if( byte_order == LIBOLECF_ENDIAN_LITTLE )
355
174k
  {
356
174k
    byte_stream_copy_to_uint32_little_endian(
357
174k
     ( (olecf_directory_entry_t *) data )->previous_directory_identifier,
358
174k
     directory_entry->previous_directory_identifier );
359
360
174k
    byte_stream_copy_to_uint32_little_endian(
361
174k
     ( (olecf_directory_entry_t *) data )->next_directory_identifier,
362
174k
     directory_entry->next_directory_identifier );
363
364
174k
    byte_stream_copy_to_uint32_little_endian(
365
174k
     ( (olecf_directory_entry_t *) data )->sub_directory_identifier,
366
174k
     directory_entry->sub_directory_identifier );
367
368
174k
    byte_stream_copy_to_uint64_little_endian(
369
174k
     ( (olecf_directory_entry_t *) data )->creation_time,
370
174k
     directory_entry->creation_time );
371
372
174k
    byte_stream_copy_to_uint64_little_endian(
373
174k
     ( (olecf_directory_entry_t *) data )->modification_time,
374
174k
     directory_entry->modification_time );
375
376
174k
    byte_stream_copy_to_uint32_little_endian(
377
174k
     ( (olecf_directory_entry_t *) data )->sector_identifier,
378
174k
     directory_entry->sector_identifier );
379
380
174k
    byte_stream_copy_to_uint32_little_endian(
381
174k
     ( (olecf_directory_entry_t *) data )->size,
382
174k
     directory_entry->size );
383
174k
  }
384
1.94k
  else if( byte_order == LIBOLECF_ENDIAN_BIG )
385
1.94k
  {
386
1.94k
    byte_stream_copy_to_uint32_big_endian(
387
1.94k
     ( (olecf_directory_entry_t *) data )->previous_directory_identifier,
388
1.94k
     directory_entry->previous_directory_identifier );
389
390
1.94k
    byte_stream_copy_to_uint32_big_endian(
391
1.94k
     ( (olecf_directory_entry_t *) data )->next_directory_identifier,
392
1.94k
     directory_entry->next_directory_identifier );
393
394
1.94k
    byte_stream_copy_to_uint32_big_endian(
395
1.94k
     ( (olecf_directory_entry_t *) data )->sub_directory_identifier,
396
1.94k
     directory_entry->sub_directory_identifier );
397
398
1.94k
    byte_stream_copy_to_uint64_big_endian(
399
1.94k
     ( (olecf_directory_entry_t *) data )->creation_time,
400
1.94k
     directory_entry->creation_time );
401
402
1.94k
    byte_stream_copy_to_uint64_big_endian(
403
1.94k
     ( (olecf_directory_entry_t *) data )->modification_time,
404
1.94k
     directory_entry->modification_time );
405
406
1.94k
    byte_stream_copy_to_uint32_big_endian(
407
1.94k
     ( (olecf_directory_entry_t *) data )->sector_identifier,
408
1.94k
     directory_entry->sector_identifier );
409
410
1.94k
    byte_stream_copy_to_uint32_big_endian(
411
1.94k
     ( (olecf_directory_entry_t *) data )->size,
412
1.94k
     directory_entry->size );
413
1.94k
  }
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
176k
  return( 1 );
565
566
53
on_error:
567
53
  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
53
  directory_entry->name_size = 0;
575
576
53
  return( -1 );
577
176k
}
578