Coverage Report

Created: 2025-06-13 07:22

/src/libfsxfs/libfsxfs/libfsxfs_directory_table.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Short-form directory table functions
3
 *
4
 * Copyright (C) 2020-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 "libfsxfs_debug.h"
28
#include "libfsxfs_definitions.h"
29
#include "libfsxfs_directory_entry.h"
30
#include "libfsxfs_directory_table.h"
31
#include "libfsxfs_directory_table_header.h"
32
#include "libfsxfs_io_handle.h"
33
#include "libfsxfs_libbfio.h"
34
#include "libfsxfs_libcdata.h"
35
#include "libfsxfs_libcerror.h"
36
#include "libfsxfs_libcnotify.h"
37
38
/* Creates directory table
39
 * Make sure the value directory_table is referencing, is set to NULL
40
 * Returns 1 if successful or -1 on error
41
 */
42
int libfsxfs_directory_table_initialize(
43
     libfsxfs_directory_table_t **directory_table,
44
     libcerror_error_t **error )
45
597
{
46
597
  static char *function = "libfsxfs_directory_table_initialize";
47
48
597
  if( directory_table == NULL )
49
0
  {
50
0
    libcerror_error_set(
51
0
     error,
52
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
53
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
54
0
     "%s: invalid directory table.",
55
0
     function );
56
57
0
    return( -1 );
58
0
  }
59
597
  if( *directory_table != NULL )
60
0
  {
61
0
    libcerror_error_set(
62
0
     error,
63
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
64
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
65
0
     "%s: invalid directory table value already set.",
66
0
     function );
67
68
0
    return( -1 );
69
0
  }
70
597
  *directory_table = memory_allocate_structure(
71
597
                      libfsxfs_directory_table_t );
72
73
597
  if( *directory_table == NULL )
74
0
  {
75
0
    libcerror_error_set(
76
0
     error,
77
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
78
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
79
0
     "%s: unable to create directory table.",
80
0
     function );
81
82
0
    goto on_error;
83
0
  }
84
597
  if( memory_set(
85
597
       *directory_table,
86
597
       0,
87
597
       sizeof( libfsxfs_directory_table_t ) ) == NULL )
88
0
  {
89
0
    libcerror_error_set(
90
0
     error,
91
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
92
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
93
0
     "%s: unable to clear directory table.",
94
0
     function );
95
96
0
    goto on_error;
97
0
  }
98
597
  return( 1 );
99
100
0
on_error:
101
0
  if( *directory_table != NULL )
102
0
  {
103
0
    memory_free(
104
0
     *directory_table );
105
106
0
    *directory_table = NULL;
107
0
  }
108
0
  return( -1 );
109
597
}
110
111
/* Frees directory table
112
 * Returns 1 if successful or -1 on error
113
 */
114
int libfsxfs_directory_table_free(
115
     libfsxfs_directory_table_t **directory_table,
116
     libcerror_error_t **error )
117
597
{
118
597
  static char *function = "libfsxfs_directory_table_free";
119
597
  int result            = 1;
120
121
597
  if( directory_table == 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 table.",
128
0
     function );
129
130
0
    return( -1 );
131
0
  }
132
597
  if( *directory_table != NULL )
133
597
  {
134
597
    if( ( *directory_table )->header != NULL )
135
522
    {
136
522
      if( libfsxfs_directory_table_header_free(
137
522
           &( ( *directory_table )->header ),
138
522
           error ) != 1 )
139
0
      {
140
0
        libcerror_error_set(
141
0
         error,
142
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
143
0
         LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
144
0
         "%s: unable to free header.",
145
0
         function );
146
147
0
        result = -1;
148
0
      }
149
522
    }
150
597
    memory_free(
151
597
     *directory_table );
152
153
597
    *directory_table = NULL;
154
597
  }
155
597
  return( result );
156
597
}
157
158
/* Reads the directory table
159
 * Returns 1 if successful or -1 on error
160
 */
161
int libfsxfs_directory_table_read_data(
162
     libfsxfs_directory_table_t *directory_table,
163
     libfsxfs_io_handle_t *io_handle,
164
     const uint8_t *data,
165
     size_t data_size,
166
     libcdata_array_t *entries_array,
167
     libcerror_error_t **error )
168
597
{
169
597
  libfsxfs_directory_entry_t *directory_entry = NULL;
170
597
  static char *function                       = "libfsxfs_directory_table_read_data";
171
597
  size_t data_offset                          = 0;
172
597
  size_t entry_data_size                      = 0;
173
597
  uint32_t directory_entry_index              = 0;
174
597
  uint8_t name_size                           = 0;
175
597
  int entry_index                             = 0;
176
177
#if defined( HAVE_DEBUG_OUTPUT )
178
  uint16_t value_16bit                        = 0;
179
#endif
180
181
597
  if( directory_table == NULL )
182
0
  {
183
0
    libcerror_error_set(
184
0
     error,
185
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
186
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
187
0
     "%s: invalid directory table.",
188
0
     function );
189
190
0
    return( -1 );
191
0
  }
192
597
  if( directory_table->header != NULL )
193
0
  {
194
0
    libcerror_error_set(
195
0
     error,
196
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
197
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
198
0
     "%s: invalid directory table - header already set.",
199
0
     function );
200
201
0
    return( -1 );
202
0
  }
203
597
  if( io_handle == NULL )
204
0
  {
205
0
    libcerror_error_set(
206
0
     error,
207
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
208
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
209
0
     "%s: invalid IO handle.",
210
0
     function );
211
212
0
    return( -1 );
213
0
  }
214
597
  if( data == NULL )
215
0
  {
216
0
    libcerror_error_set(
217
0
     error,
218
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
219
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
220
0
     "%s: invalid data.",
221
0
     function );
222
223
0
    return( -1 );
224
0
  }
225
597
  if( ( data_size < 2 )
226
597
   || ( data_size > (size_t) SSIZE_MAX ) )
227
2
  {
228
2
    libcerror_error_set(
229
2
     error,
230
2
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
231
2
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
232
2
     "%s: invalid data size value out of bounds.",
233
2
     function );
234
235
2
    return( -1 );
236
2
  }
237
595
  if( libfsxfs_directory_table_header_initialize(
238
595
       &( directory_table->header ),
239
595
       error ) != 1 )
240
0
  {
241
0
    libcerror_error_set(
242
0
     error,
243
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
244
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
245
0
     "%s: unable to create header.",
246
0
     function );
247
248
0
    goto on_error;
249
0
  }
250
595
  if( libfsxfs_directory_table_header_read_data(
251
595
       directory_table->header,
252
595
       data,
253
595
       data_size,
254
595
       error ) != 1 )
255
17
  {
256
17
    libcerror_error_set(
257
17
     error,
258
17
     LIBCERROR_ERROR_DOMAIN_IO,
259
17
     LIBCERROR_IO_ERROR_READ_FAILED,
260
17
     "%s: unable to read directory table header.",
261
17
     function );
262
263
17
    goto on_error;
264
17
  }
265
578
  if( directory_table->header->inode_number_data_size == 4 )
266
148
  {
267
148
    data_offset = 6;
268
148
  }
269
430
  else
270
430
  {
271
430
    data_offset = 10;
272
430
  }
273
578
  for( directory_entry_index = 0;
274
4.33k
       directory_entry_index < directory_table->header->number_of_entries;
275
3.75k
       directory_entry_index++ )
276
3.80k
  {
277
3.80k
    if( ( data_size - data_offset ) < 1 )
278
6
    {
279
6
      libcerror_error_set(
280
6
       error,
281
6
       LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
282
6
       LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
283
6
       "%s: invalid directory entry: %d data size value out of bounds.",
284
6
       function,
285
6
       directory_entry_index );
286
287
6
      goto on_error;
288
6
    }
289
3.80k
    name_size = data[ data_offset ];
290
291
3.80k
    entry_data_size = 3 + name_size;
292
293
3.80k
    if( ( io_handle->format_version == 5 )
294
3.80k
     || ( ( io_handle->secondary_feature_flags & LIBFSXFS_SECONDARY_FEATURE_FLAG_FILE_TYPE ) != 0 ) )
295
2.28k
    {
296
2.28k
      entry_data_size++;
297
2.28k
    }
298
3.80k
    entry_data_size += directory_table->header->inode_number_data_size;
299
300
3.80k
    if( entry_data_size > ( data_size - data_offset ) )
301
50
    {
302
50
      libcerror_error_set(
303
50
       error,
304
50
       LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
305
50
       LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
306
50
       "%s: invalid directory entry: %d data size value out of bounds.",
307
50
       function,
308
50
       directory_entry_index );
309
310
50
      goto on_error;
311
50
    }
312
#if defined( HAVE_DEBUG_OUTPUT )
313
    if( libcnotify_verbose != 0 )
314
    {
315
      libcnotify_printf(
316
       "%s: directory entry: %d data:\n",
317
       function,
318
       directory_entry_index );
319
      libcnotify_print_data(
320
       &( data[ data_offset ] ),
321
       entry_data_size,
322
       LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
323
    }
324
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
325
326
3.75k
    data_offset++;
327
328
#if defined( HAVE_DEBUG_OUTPUT )
329
    if( libcnotify_verbose != 0 )
330
    {
331
      libcnotify_printf(
332
       "%s: name size\t\t\t\t: %" PRIu8 "\n",
333
       function,
334
       name_size );
335
336
      byte_stream_copy_to_uint16_big_endian(
337
       &( data[ data_offset ] ),
338
       value_16bit );
339
      libcnotify_printf(
340
       "%s: tag offset\t\t\t\t: %" PRIu16 "\n",
341
       function,
342
       value_16bit );
343
    }
344
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
345
346
3.75k
    data_offset += 2;
347
348
#if defined( HAVE_DEBUG_OUTPUT )
349
    if( libcnotify_verbose != 0 )
350
    {
351
      if( libfsxfs_debug_print_utf8_string_value(
352
           function,
353
           "name\t\t\t\t",
354
           &( data[ data_offset ] ),
355
           name_size,
356
           error ) != 1 )
357
      {
358
        libcerror_error_set(
359
         error,
360
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
361
         LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
362
         "%s: unable to print UTF-8 string value.",
363
         function );
364
365
        goto on_error;
366
      }
367
    }
368
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
369
370
3.75k
    if( libfsxfs_directory_entry_initialize(
371
3.75k
         &directory_entry,
372
3.75k
         error ) != 1 )
373
0
    {
374
0
      libcerror_error_set(
375
0
       error,
376
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
377
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
378
0
       "%s: unable to create entry.",
379
0
       function );
380
381
0
      goto on_error;
382
0
    }
383
3.75k
    if( memory_copy(
384
3.75k
         directory_entry->name,
385
3.75k
         &( data[ data_offset ] ),
386
3.75k
         (size_t) name_size ) == NULL )
387
0
    {
388
0
      libcerror_error_set(
389
0
       error,
390
0
       LIBCERROR_ERROR_DOMAIN_MEMORY,
391
0
       LIBCERROR_MEMORY_ERROR_COPY_FAILED,
392
0
       "%s: unable to copy name.",
393
0
       function );
394
395
0
      goto on_error;
396
0
    }
397
3.75k
    directory_entry->name_size = name_size;
398
399
3.75k
    data_offset += name_size;
400
401
3.75k
    if( ( io_handle->format_version == 5 )
402
3.75k
     || ( ( io_handle->secondary_feature_flags & LIBFSXFS_SECONDARY_FEATURE_FLAG_FILE_TYPE ) != 0 ) )
403
2.25k
    {
404
#if defined( HAVE_DEBUG_OUTPUT )
405
      if( libcnotify_verbose != 0 )
406
      {
407
        libcnotify_printf(
408
         "%s: file type\t\t\t\t: %" PRIu8 "\n",
409
         function,
410
         data[ data_offset ] );
411
      }
412
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
413
414
2.25k
      data_offset++;
415
2.25k
    }
416
3.75k
    if( directory_table->header->inode_number_data_size == 4 )
417
2.38k
    {
418
2.38k
      byte_stream_copy_to_uint32_big_endian(
419
2.38k
       &( data[ data_offset ] ),
420
2.38k
       directory_entry->inode_number );
421
422
2.38k
      data_offset += 4;
423
2.38k
    }
424
1.37k
    else
425
1.37k
    {
426
1.37k
      byte_stream_copy_to_uint64_big_endian(
427
1.37k
       &( data[ data_offset ] ),
428
1.37k
       directory_entry->inode_number );
429
430
1.37k
      data_offset += 8;
431
1.37k
    }
432
#if defined( HAVE_DEBUG_OUTPUT )
433
    if( libcnotify_verbose != 0 )
434
    {
435
      libcnotify_printf(
436
       "%s: inode number\t\t\t: %" PRIu64 "\n",
437
       function,
438
       directory_entry->inode_number );
439
440
      libcnotify_printf(
441
       "\n" );
442
    }
443
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
444
445
3.75k
    if( libcdata_array_append_entry(
446
3.75k
         entries_array,
447
3.75k
         &entry_index,
448
3.75k
         (intptr_t *) directory_entry,
449
3.75k
         error ) != 1 )
450
0
    {
451
0
      libcerror_error_set(
452
0
       error,
453
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
454
0
       LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
455
0
       "%s: unable to append directory entry to entries array.",
456
0
       function );
457
458
0
      goto on_error;
459
0
    }
460
3.75k
    directory_entry = NULL;
461
3.75k
  }
462
522
  return( 1 );
463
464
73
on_error:
465
73
  if( directory_entry != NULL )
466
0
  {
467
0
    libfsxfs_directory_entry_free(
468
0
     &directory_entry,
469
0
     NULL );
470
0
  }
471
73
  if( directory_table->header != NULL )
472
73
  {
473
73
    libfsxfs_directory_table_header_free(
474
73
     &( directory_table->header ),
475
73
     NULL );
476
73
  }
477
73
  libcdata_array_empty(
478
73
   entries_array,
479
73
   (int (*)(intptr_t **, libcerror_error_t **)) &libfsxfs_directory_entry_free,
480
73
   NULL );
481
482
73
  return( -1 );
483
578
}
484