Coverage Report

Created: 2024-06-12 07:07

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