Coverage Report

Created: 2026-01-20 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libfsext/libfsext/libfsext_directory.c
Line
Count
Source
1
/*
2
 * Directory functions
3
 *
4
 * Copyright (C) 2010-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 "libfsext_block.h"
28
#include "libfsext_block_vector.h"
29
#include "libfsext_definitions.h"
30
#include "libfsext_directory.h"
31
#include "libfsext_directory_entry.h"
32
#include "libfsext_inode.h"
33
#include "libfsext_io_handle.h"
34
#include "libfsext_libbfio.h"
35
#include "libfsext_libcdata.h"
36
#include "libfsext_libcerror.h"
37
#include "libfsext_libcnotify.h"
38
#include "libfsext_libfdata.h"
39
#include "libfsext_libfcache.h"
40
#include "libfsext_libuna.h"
41
42
/* Creates a directory
43
 * Make sure the value directory is referencing, is set to NULL
44
 * Returns 1 if successful or -1 on error
45
 */
46
int libfsext_directory_initialize(
47
     libfsext_directory_t **directory,
48
     libcerror_error_t **error )
49
2.44k
{
50
2.44k
  static char *function = "libfsext_directory_initialize";
51
52
2.44k
  if( directory == NULL )
53
0
  {
54
0
    libcerror_error_set(
55
0
     error,
56
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
57
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
58
0
     "%s: invalid directory.",
59
0
     function );
60
61
0
    return( -1 );
62
0
  }
63
2.44k
  if( *directory != NULL )
64
0
  {
65
0
    libcerror_error_set(
66
0
     error,
67
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
68
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
69
0
     "%s: invalid directory value already set.",
70
0
     function );
71
72
0
    return( -1 );
73
0
  }
74
2.44k
  *directory = memory_allocate_structure(
75
2.44k
                libfsext_directory_t );
76
77
2.44k
  if( *directory == NULL )
78
0
  {
79
0
    libcerror_error_set(
80
0
     error,
81
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
82
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
83
0
     "%s: unable to create directory.",
84
0
     function );
85
86
0
    goto on_error;
87
0
  }
88
2.44k
  if( memory_set(
89
2.44k
       *directory,
90
2.44k
       0,
91
2.44k
       sizeof( libfsext_directory_t ) ) == NULL )
92
0
  {
93
0
    libcerror_error_set(
94
0
     error,
95
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
96
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
97
0
     "%s: unable to clear directory.",
98
0
     function );
99
100
0
    memory_free(
101
0
     *directory );
102
103
0
    *directory = NULL;
104
105
0
    return( -1 );
106
0
  }
107
2.44k
  if( libcdata_array_initialize(
108
2.44k
       &( ( *directory )->entries_array ),
109
2.44k
       0,
110
2.44k
       error ) != 1 )
111
0
  {
112
0
    libcerror_error_set(
113
0
     error,
114
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
115
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
116
0
     "%s: unable to create entries array.",
117
0
     function );
118
119
0
    goto on_error;
120
0
  }
121
2.44k
  return( 1 );
122
123
0
on_error:
124
0
  if( *directory != NULL )
125
0
  {
126
0
    memory_free(
127
0
     *directory );
128
129
0
    *directory = NULL;
130
0
  }
131
0
  return( -1 );
132
2.44k
}
133
134
/* Frees a directory
135
 * Returns 1 if successful or -1 on error
136
 */
137
int libfsext_directory_free(
138
     libfsext_directory_t **directory,
139
     libcerror_error_t **error )
140
2.44k
{
141
2.44k
  static char *function = "libfsext_directory_free";
142
2.44k
  int result            = 1;
143
144
2.44k
  if( directory == NULL )
145
0
  {
146
0
    libcerror_error_set(
147
0
     error,
148
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
149
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
150
0
     "%s: invalid directory.",
151
0
     function );
152
153
0
    return( -1 );
154
0
  }
155
2.44k
  if( *directory != NULL )
156
2.44k
  {
157
2.44k
    if( libcdata_array_free(
158
2.44k
         &( ( *directory )->entries_array ),
159
2.44k
         (int (*)(intptr_t **, libcerror_error_t **)) &libfsext_directory_entry_free,
160
2.44k
         error ) != 1 )
161
0
    {
162
0
      libcerror_error_set(
163
0
       error,
164
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
165
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
166
0
       "%s: unable to free entries array.",
167
0
       function );
168
169
0
      result = -1;
170
0
    }
171
2.44k
    memory_free(
172
2.44k
     *directory );
173
174
2.44k
    *directory = NULL;
175
2.44k
  }
176
2.44k
  return( result );
177
2.44k
}
178
179
/* Reads the directory entries from block data
180
 * Returns 1 if successful or -1 on error
181
 */
182
int libfsext_directory_read_block_data(
183
     libfsext_directory_t *directory,
184
     const uint8_t *data,
185
     size_t data_size,
186
     uint32_t *directory_entry_index,
187
     libcerror_error_t **error )
188
12.8k
{
189
12.8k
  libfsext_directory_entry_t *directory_entry = NULL;
190
12.8k
  static char *function                       = "libfsext_directory_read_block_data";
191
12.8k
  size_t data_offset                          = 0;
192
12.8k
  uint32_t safe_directory_entry_index         = 0;
193
12.8k
  int entry_index                             = 0;
194
195
12.8k
  if( directory == NULL )
196
0
  {
197
0
    libcerror_error_set(
198
0
     error,
199
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
200
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
201
0
     "%s: invalid directory.",
202
0
     function );
203
204
0
    return( -1 );
205
0
  }
206
12.8k
  if( data == NULL )
207
0
  {
208
0
    libcerror_error_set(
209
0
     error,
210
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
211
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
212
0
     "%s: invalid data.",
213
0
     function );
214
215
0
    return( -1 );
216
0
  }
217
12.8k
  if( data_size > (size_t) SSIZE_MAX )
218
0
  {
219
0
    libcerror_error_set(
220
0
     error,
221
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
222
0
     LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
223
0
     "%s: invalid data size value exceeds maximum.",
224
0
     function );
225
226
0
    return( -1 );
227
0
  }
228
12.8k
  if( directory_entry_index == NULL )
229
0
  {
230
0
    libcerror_error_set(
231
0
     error,
232
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
233
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
234
0
     "%s: invalid directory entry index.",
235
0
     function );
236
237
0
    return( -1 );
238
0
  }
239
12.8k
  safe_directory_entry_index = *directory_entry_index;
240
241
127k
  while( data_offset < data_size )
242
125k
  {
243
#if defined( HAVE_DEBUG_OUTPUT )
244
    if( libcnotify_verbose != 0 )
245
    {
246
      libcnotify_printf(
247
       "Reading directory entry: %" PRIu32 " at offset: %" PRIzd " (0x%08" PRIzx ")\n",
248
       safe_directory_entry_index,
249
       data_offset,
250
       data_offset );
251
    }
252
#endif
253
125k
    if( libfsext_directory_entry_initialize(
254
125k
         &directory_entry,
255
125k
         error ) != 1 )
256
0
    {
257
0
      libcerror_error_set(
258
0
       error,
259
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
260
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
261
0
       "%s: unable to create directory entry: %" PRIu32 ".",
262
0
       function,
263
0
       safe_directory_entry_index );
264
265
0
      goto on_error;
266
0
    }
267
125k
    if( libfsext_directory_entry_read_data(
268
125k
         directory_entry,
269
125k
         &( data[ data_offset ] ),
270
125k
         data_size - data_offset,
271
125k
         error ) != 1 )
272
59
    {
273
59
      libcerror_error_set(
274
59
       error,
275
59
       LIBCERROR_ERROR_DOMAIN_IO,
276
59
       LIBCERROR_IO_ERROR_READ_FAILED,
277
59
       "%s: unable to read directory entry: %" PRIu32 " at offset: %" PRIzd " (0x%08" PRIzx ").",
278
59
       function,
279
59
       safe_directory_entry_index,
280
59
       data_offset,
281
59
       data_offset );
282
283
59
      goto on_error;
284
59
    }
285
125k
    if( directory_entry->size == 0 )
286
10.6k
    {
287
10.6k
      if( libfsext_directory_entry_free(
288
10.6k
           &directory_entry,
289
10.6k
           error ) != 1 )
290
0
      {
291
0
        libcerror_error_set(
292
0
         error,
293
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
294
0
         LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
295
0
         "%s: unable to free directory entry: %" PRIu32 ".",
296
0
         function,
297
0
         safe_directory_entry_index );
298
299
0
        goto on_error;
300
0
      }
301
10.6k
      break;
302
10.6k
    }
303
114k
    data_offset += directory_entry->size;
304
305
/* TODO lost+found has directory entries with size but no values */
306
114k
    if( ( ( directory_entry->name_size == 2 )
307
23.1k
      && ( directory_entry->name[ 0 ] == '.' ) )
308
107k
     || ( ( directory_entry->name_size == 3 )
309
12.5k
      && ( directory_entry->name[ 0 ] == '.' )
310
5.95k
      && ( directory_entry->name[ 1 ] == '.' ) )
311
104k
     || ( directory_entry->inode_number == 0 ) )
312
33.0k
    {
313
33.0k
      if( libfsext_directory_entry_free(
314
33.0k
           &directory_entry,
315
33.0k
           error ) != 1 )
316
0
      {
317
0
        libcerror_error_set(
318
0
         error,
319
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
320
0
         LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
321
0
         "%s: unable to free directory entry: %" PRIu32 ".",
322
0
         function,
323
0
         safe_directory_entry_index );
324
325
0
        goto on_error;
326
0
      }
327
33.0k
    }
328
81.4k
    else
329
81.4k
    {
330
81.4k
      if( libcdata_array_append_entry(
331
81.4k
           directory->entries_array,
332
81.4k
           &entry_index,
333
81.4k
           (intptr_t *) directory_entry,
334
81.4k
           error ) != 1 )
335
0
      {
336
0
        libcerror_error_set(
337
0
         error,
338
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
339
0
         LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
340
0
         "%s: unable to append directory entry: %" PRIu32 " to array.",
341
0
         function,
342
0
         safe_directory_entry_index );
343
344
0
        goto on_error;
345
0
      }
346
81.4k
      directory_entry = NULL;
347
81.4k
    }
348
114k
    safe_directory_entry_index++;
349
114k
  }
350
12.7k
  *directory_entry_index = safe_directory_entry_index;
351
352
12.7k
  return( 1 );
353
354
59
on_error:
355
59
  if( directory_entry != NULL )
356
59
  {
357
59
    libfsext_directory_entry_free(
358
59
     &directory_entry,
359
59
     NULL );
360
59
  }
361
59
  return( -1 );
362
12.8k
}
363
364
/* Reads the directory entries from inline data
365
 * Returns 1 if successful or -1 on error
366
 */
367
int libfsext_directory_read_inline_data(
368
     libfsext_directory_t *directory,
369
     const uint8_t *data,
370
     size_t data_size,
371
     libcerror_error_t **error )
372
989
{
373
989
  libfsext_directory_entry_t *directory_entry = NULL;
374
989
  static char *function                       = "libfsext_directory_read_inline_data";
375
989
  size_t data_offset                          = 0;
376
989
  uint32_t directory_entry_index              = 0;
377
989
  uint32_t parent_inode_number                = 0;
378
989
  int entry_index                             = 0;
379
380
989
  if( directory == NULL )
381
0
  {
382
0
    libcerror_error_set(
383
0
     error,
384
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
385
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
386
0
     "%s: invalid directory.",
387
0
     function );
388
389
0
    return( -1 );
390
0
  }
391
989
  if( data == NULL )
392
0
  {
393
0
    libcerror_error_set(
394
0
     error,
395
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
396
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
397
0
     "%s: invalid data.",
398
0
     function );
399
400
0
    return( -1 );
401
0
  }
402
989
  if( ( data_size < 4 )
403
985
   || ( data_size > (size_t) SSIZE_MAX ) )
404
4
  {
405
4
    libcerror_error_set(
406
4
     error,
407
4
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
408
4
     LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
409
4
     "%s: invalid data size value exceeds maximum.",
410
4
     function );
411
412
4
    return( -1 );
413
4
  }
414
985
  byte_stream_copy_to_uint32_little_endian(
415
985
   data,
416
985
   parent_inode_number );
417
418
#if defined( HAVE_DEBUG_OUTPUT )
419
  if( libcnotify_verbose != 0 )
420
  {
421
    libcnotify_printf(
422
     "%s: parent inode number\t\t: %" PRIu32 "\n",
423
     function,
424
     parent_inode_number );
425
426
    libcnotify_printf(
427
     "\n" );
428
  }
429
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
430
431
985
  data_offset += 4;
432
433
2.62k
  while( data_offset < data_size )
434
2.27k
  {
435
#if defined( HAVE_DEBUG_OUTPUT )
436
    if( libcnotify_verbose != 0 )
437
    {
438
      libcnotify_printf(
439
       "Reading directory entry: %" PRIu32 " at offset: %" PRIzd " (0x%08" PRIzx ")\n",
440
       directory_entry_index,
441
       data_offset,
442
       data_offset );
443
    }
444
#endif
445
2.27k
    if( libfsext_directory_entry_initialize(
446
2.27k
         &directory_entry,
447
2.27k
         error ) != 1 )
448
0
    {
449
0
      libcerror_error_set(
450
0
       error,
451
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
452
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
453
0
       "%s: unable to create directory entry: %" PRIu32 ".",
454
0
       function,
455
0
       directory_entry_index );
456
457
0
      goto on_error;
458
0
    }
459
2.27k
    if( libfsext_directory_entry_read_data(
460
2.27k
         directory_entry,
461
2.27k
         &( data[ data_offset ] ),
462
2.27k
         data_size - data_offset,
463
2.27k
         error ) != 1 )
464
42
    {
465
42
      libcerror_error_set(
466
42
       error,
467
42
       LIBCERROR_ERROR_DOMAIN_IO,
468
42
       LIBCERROR_IO_ERROR_READ_FAILED,
469
42
       "%s: unable to read directory entry: %" PRIu32 " at offset: %" PRIzd " (0x%08" PRIzx ").",
470
42
       function,
471
42
       directory_entry_index,
472
42
       data_offset,
473
42
       data_offset );
474
475
42
      goto on_error;
476
42
    }
477
2.23k
    if( directory_entry->size == 0 )
478
592
    {
479
592
      if( libfsext_directory_entry_free(
480
592
           &directory_entry,
481
592
           error ) != 1 )
482
0
      {
483
0
        libcerror_error_set(
484
0
         error,
485
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
486
0
         LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
487
0
         "%s: unable to free directory entry: %" PRIu32 ".",
488
0
         function,
489
0
         directory_entry_index );
490
491
0
        goto on_error;
492
0
      }
493
592
      break;
494
592
    }
495
1.64k
    data_offset += directory_entry->size;
496
497
/* TODO lost+found has directory entries with size but no values */
498
1.64k
    if( ( ( directory_entry->name_size == 2 )
499
164
      && ( directory_entry->name[ 0 ] == '.' ) )
500
1.61k
     || ( ( directory_entry->name_size == 3 )
501
379
      && ( directory_entry->name[ 0 ] == '.' )
502
182
      && ( directory_entry->name[ 1 ] == '.' ) )
503
1.59k
     || ( directory_entry->inode_number == 0 ) )
504
100
    {
505
100
      if( libfsext_directory_entry_free(
506
100
           &directory_entry,
507
100
           error ) != 1 )
508
0
      {
509
0
        libcerror_error_set(
510
0
         error,
511
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
512
0
         LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
513
0
         "%s: unable to free directory entry: %" PRIu32 ".",
514
0
         function,
515
0
         directory_entry_index );
516
517
0
        goto on_error;
518
0
      }
519
100
    }
520
1.54k
    else
521
1.54k
    {
522
1.54k
      if( libcdata_array_append_entry(
523
1.54k
           directory->entries_array,
524
1.54k
           &entry_index,
525
1.54k
           (intptr_t *) directory_entry,
526
1.54k
           error ) != 1 )
527
0
      {
528
0
        libcerror_error_set(
529
0
         error,
530
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
531
0
         LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
532
0
         "%s: unable to append directory entry: %" PRIu32 " to array.",
533
0
         function,
534
0
         directory_entry_index );
535
536
0
        goto on_error;
537
0
      }
538
1.54k
      directory_entry = NULL;
539
1.54k
    }
540
1.64k
    directory_entry_index++;
541
1.64k
  }
542
943
  return( 1 );
543
544
42
on_error:
545
42
  if( directory_entry != NULL )
546
42
  {
547
42
    libfsext_directory_entry_free(
548
42
     &directory_entry,
549
42
     NULL );
550
42
  }
551
42
  return( -1 );
552
985
}
553
554
/* Reads the directory entries
555
 * Returns 1 if successful or -1 on error
556
 */
557
int libfsext_directory_read_file_io_handle(
558
     libfsext_directory_t *directory,
559
     libfsext_io_handle_t *io_handle,
560
     libbfio_handle_t *file_io_handle,
561
     libfsext_inode_t *inode,
562
     libcerror_error_t **error )
563
2.44k
{
564
2.44k
  libfcache_cache_t *block_cache  = NULL;
565
2.44k
  libfdata_vector_t *block_vector = NULL;
566
2.44k
  libfsext_block_t *block         = NULL;
567
2.44k
  static char *function           = "libfsext_directory_read_file_io_handle";
568
2.44k
  size_t inline_data_size         = 0;
569
2.44k
  uint32_t directory_entry_index  = 0;
570
2.44k
  int block_index                 = 0;
571
2.44k
  int number_of_blocks            = 0;
572
573
2.44k
  if( directory == NULL )
574
0
  {
575
0
    libcerror_error_set(
576
0
     error,
577
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
578
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
579
0
     "%s: invalid directory.",
580
0
     function );
581
582
0
    return( -1 );
583
0
  }
584
2.44k
  if( io_handle == NULL )
585
0
  {
586
0
    libcerror_error_set(
587
0
     error,
588
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
589
0
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
590
0
     "%s: invalid IO handle.",
591
0
     function );
592
593
0
    return( -1 );
594
0
  }
595
2.44k
  if( inode == NULL )
596
0
  {
597
0
    libcerror_error_set(
598
0
     error,
599
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
600
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
601
0
     "%s: invalid inode.",
602
0
     function );
603
604
0
    return( -1 );
605
0
  }
606
2.44k
  if( ( inode->file_mode & 0xf000 ) != LIBFSEXT_FILE_TYPE_DIRECTORY )
607
130
  {
608
130
    libcerror_error_set(
609
130
     error,
610
130
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
611
130
     LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
612
130
     "%s: invalid inode - unsupported file type.",
613
130
     function );
614
615
130
    return( -1 );
616
130
  }
617
2.31k
  if( ( io_handle->format_version == 4 )
618
1.42k
   && ( ( inode->flags & LIBFSEXT_INODE_FLAG_INLINE_DATA ) != 0 ) )
619
989
  {
620
    /* Note that inode->data_size can be larger than 60
621
     * but inode->data_reference only holds 60 bytes
622
     */
623
989
    if( inode->data_size < 60 )
624
24
    {
625
24
      inline_data_size = inode->data_size;
626
24
    }
627
965
    else
628
965
    {
629
965
      inline_data_size = 60;
630
965
    }
631
989
    if( libfsext_directory_read_inline_data(
632
989
         directory,
633
989
         inode->data_reference,
634
989
         inline_data_size,
635
989
         error ) != 1 )
636
46
    {
637
46
      libcerror_error_set(
638
46
       error,
639
46
       LIBCERROR_ERROR_DOMAIN_IO,
640
46
       LIBCERROR_IO_ERROR_READ_FAILED,
641
46
       "%s: unable to read directory inline data.",
642
46
       function );
643
644
46
      goto on_error;
645
46
    }
646
989
  }
647
1.32k
  else
648
1.32k
  {
649
1.32k
    if( libfsext_block_vector_initialize(
650
1.32k
         &block_vector,
651
1.32k
         io_handle,
652
1.32k
         inode,
653
1.32k
         error ) != 1 )
654
54
    {
655
54
      libcerror_error_set(
656
54
       error,
657
54
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
658
54
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
659
54
       "%s: unable to create block vector.",
660
54
       function );
661
662
54
      goto on_error;
663
54
    }
664
1.27k
    if( libfcache_cache_initialize(
665
1.27k
         &block_cache,
666
1.27k
         LIBFSEXT_MAXIMUM_CACHE_ENTRIES_BLOCKS,
667
1.27k
         error ) != 1 )
668
0
    {
669
0
      libcerror_error_set(
670
0
       error,
671
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
672
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
673
0
       "%s: unable to create block cache.",
674
0
       function );
675
676
0
      goto on_error;
677
0
    }
678
1.27k
    if( libfdata_vector_get_number_of_elements(
679
1.27k
         block_vector,
680
1.27k
         &number_of_blocks,
681
1.27k
         error ) != 1 )
682
3
    {
683
3
      libcerror_error_set(
684
3
       error,
685
3
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
686
3
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
687
3
       "%s: unable to retrieve number of blocks.",
688
3
       function );
689
690
3
      goto on_error;
691
3
    }
692
1.26k
    for( block_index = 0;
693
14.0k
         block_index < number_of_blocks;
694
12.7k
         block_index++ )
695
13.0k
    {
696
13.0k
      if( libfdata_vector_get_element_value_by_index(
697
13.0k
           block_vector,
698
13.0k
           (intptr_t *) file_io_handle,
699
13.0k
           (libfdata_cache_t *) block_cache,
700
13.0k
           block_index,
701
13.0k
           (intptr_t **) &block,
702
13.0k
           0,
703
13.0k
           error ) != 1 )
704
282
      {
705
282
        libcerror_error_set(
706
282
         error,
707
282
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
708
282
         LIBCERROR_RUNTIME_ERROR_GET_FAILED,
709
282
         "%s: unable to retrieve block: %d.",
710
282
         function,
711
282
         block_index );
712
713
282
        goto on_error;
714
282
      }
715
12.8k
      if( block == NULL )
716
0
      {
717
0
        libcerror_error_set(
718
0
         error,
719
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
720
0
         LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
721
0
         "%s: invalid block.",
722
0
         function );
723
724
0
        goto on_error;
725
0
      }
726
12.8k
      if( libfsext_directory_read_block_data(
727
12.8k
           directory,
728
12.8k
           block->data,
729
12.8k
           (size_t) block->data_size,
730
12.8k
           &directory_entry_index,
731
12.8k
           error ) != 1 )
732
59
      {
733
59
        libcerror_error_set(
734
59
         error,
735
59
         LIBCERROR_ERROR_DOMAIN_IO,
736
59
         LIBCERROR_IO_ERROR_READ_FAILED,
737
59
         "%s: unable to read directory block: %d.",
738
59
         function,
739
59
         block_index );
740
741
59
        goto on_error;
742
59
      }
743
12.8k
    }
744
927
    if( libfcache_cache_free(
745
927
         &block_cache,
746
927
         error ) != 1 )
747
0
    {
748
0
      libcerror_error_set(
749
0
       error,
750
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
751
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
752
0
       "%s: unable to free block cache.",
753
0
       function );
754
755
0
      goto on_error;
756
0
    }
757
927
    if( libfdata_vector_free(
758
927
         &block_vector,
759
927
         error ) != 1 )
760
0
    {
761
0
      libcerror_error_set(
762
0
       error,
763
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
764
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
765
0
       "%s: unable to free block vector.",
766
0
       function );
767
768
0
      goto on_error;
769
0
    }
770
927
  }
771
1.87k
  return( 1 );
772
773
444
on_error:
774
444
  if( block_cache != NULL )
775
344
  {
776
344
    libfcache_cache_free(
777
344
     &block_cache,
778
344
     NULL );
779
344
  }
780
444
  if( block_vector != NULL )
781
344
  {
782
344
    libfdata_vector_free(
783
344
     &block_vector,
784
344
     NULL );
785
344
  }
786
444
  return( -1 );
787
2.31k
}
788
789
/* Retrieves the number of entries
790
 * Returns 1 if successful or -1 on error
791
 */
792
int libfsext_directory_get_number_of_entries(
793
     libfsext_directory_t *directory,
794
     int *number_of_entries,
795
     libcerror_error_t **error )
796
818
{
797
818
  static char *function = "libfsext_directory_get_number_of_entries";
798
799
818
  if( directory == NULL )
800
0
  {
801
0
    libcerror_error_set(
802
0
     error,
803
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
804
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
805
0
     "%s: invalid directory.",
806
0
     function );
807
808
0
    return( -1 );
809
0
  }
810
818
  if( libcdata_array_get_number_of_entries(
811
818
       directory->entries_array,
812
818
       number_of_entries,
813
818
       error ) != 1 )
814
0
  {
815
0
    libcerror_error_set(
816
0
     error,
817
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
818
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
819
0
     "%s: unable to retrieve number of entries.",
820
0
     function );
821
822
0
    return( -1 );
823
0
  }
824
818
  return( 1 );
825
818
}
826
827
/* Retrieves a specific entry
828
 * Returns 1 if successful or -1 on error
829
 */
830
int libfsext_directory_get_entry_by_index(
831
     libfsext_directory_t *directory,
832
     int entry_index,
833
     libfsext_directory_entry_t **directory_entry,
834
     libcerror_error_t **error )
835
802
{
836
802
  static char *function = "libfsext_directory_get_entry_by_index";
837
838
802
  if( directory == NULL )
839
0
  {
840
0
    libcerror_error_set(
841
0
     error,
842
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
843
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
844
0
     "%s: invalid directory.",
845
0
     function );
846
847
0
    return( -1 );
848
0
  }
849
802
  if( libcdata_array_get_entry_by_index(
850
802
       directory->entries_array,
851
802
       entry_index,
852
802
       (intptr_t **) directory_entry,
853
802
       error ) != 1 )
854
0
  {
855
0
    libcerror_error_set(
856
0
     error,
857
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
858
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
859
0
     "%s: unable to retrieve entry: %d.",
860
0
     function,
861
0
     entry_index );
862
863
0
    return( -1 );
864
0
  }
865
802
  return( 1 );
866
802
}
867
868
/* Retrieves the directory entry for an UTF-8 encoded name
869
 * Returns 1 if successful, 0 if not found or -1 on error
870
 */
871
int libfsext_directory_get_entry_by_utf8_name(
872
     libfsext_directory_t *directory,
873
     const uint8_t *utf8_string,
874
     size_t utf8_string_length,
875
     libfsext_directory_entry_t **directory_entry,
876
     libcerror_error_t **error )
877
1.05k
{
878
1.05k
  libfsext_directory_entry_t *safe_directory_entry = NULL;
879
1.05k
  static char *function                            = "libfsext_directory_get_entry_by_utf8_name";
880
1.05k
  int entry_index                                  = 0;
881
1.05k
  int number_of_entries                            = 0;
882
1.05k
  int result                                       = 0;
883
884
1.05k
  if( directory == NULL )
885
0
  {
886
0
    libcerror_error_set(
887
0
     error,
888
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
889
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
890
0
     "%s: invalid directory.",
891
0
     function );
892
893
0
    return( -1 );
894
0
  }
895
1.05k
  if( libcdata_array_get_number_of_entries(
896
1.05k
       directory->entries_array,
897
1.05k
       &number_of_entries,
898
1.05k
       error ) != 1 )
899
0
  {
900
0
    libcerror_error_set(
901
0
     error,
902
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
903
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
904
0
     "%s: unable to retrieve number of entries.",
905
0
     function );
906
907
0
    return( -1 );
908
0
  }
909
1.05k
  for( entry_index = 0;
910
23.7k
       entry_index < number_of_entries;
911
22.7k
       entry_index++ )
912
23.6k
  {
913
23.6k
    if( libcdata_array_get_entry_by_index(
914
23.6k
         directory->entries_array,
915
23.6k
         entry_index,
916
23.6k
         (intptr_t **) &safe_directory_entry,
917
23.6k
         error ) != 1 )
918
0
    {
919
0
      libcerror_error_set(
920
0
       error,
921
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
922
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
923
0
       "%s: unable to retrieve entry: %d.",
924
0
       function,
925
0
       entry_index );
926
927
0
      return( -1 );
928
0
    }
929
23.6k
    result = libfsext_directory_entry_compare_with_utf8_string(
930
23.6k
              safe_directory_entry,
931
23.6k
              utf8_string,
932
23.6k
              utf8_string_length,
933
23.6k
              error );
934
935
23.6k
    if( result == -1 )
936
54
    {
937
54
      libcerror_error_set(
938
54
       error,
939
54
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
940
54
       LIBCERROR_RUNTIME_ERROR_GENERIC,
941
54
       "%s: unable to compare UTF-8 string with directory entry: %d.",
942
54
       function,
943
54
       entry_index );
944
945
54
      return( -1 );
946
54
    }
947
23.6k
    else if( result == LIBUNA_COMPARE_EQUAL )
948
886
    {
949
886
      *directory_entry = safe_directory_entry;
950
951
886
      return( 1 );
952
886
    }
953
23.6k
  }
954
112
  *directory_entry = NULL;
955
956
112
  return( 0 );
957
1.05k
}
958
959
/* Retrieves the directory entry for an UTF-16 encoded name
960
 * Returns 1 if successful, 0 if not found or -1 on error
961
 */
962
int libfsext_directory_get_entry_by_utf16_name(
963
     libfsext_directory_t *directory,
964
     const uint16_t *utf16_string,
965
     size_t utf16_string_length,
966
     libfsext_directory_entry_t **directory_entry,
967
     libcerror_error_t **error )
968
0
{
969
0
  libfsext_directory_entry_t *safe_directory_entry = NULL;
970
0
  static char *function                            = "libfsext_directory_get_entry_by_utf16_name";
971
0
  int entry_index                                  = 0;
972
0
  int number_of_entries                            = 0;
973
0
  int result                                       = 0;
974
975
0
  if( directory == NULL )
976
0
  {
977
0
    libcerror_error_set(
978
0
     error,
979
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
980
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
981
0
     "%s: invalid directory.",
982
0
     function );
983
984
0
    return( -1 );
985
0
  }
986
0
  if( libcdata_array_get_number_of_entries(
987
0
       directory->entries_array,
988
0
       &number_of_entries,
989
0
       error ) != 1 )
990
0
  {
991
0
    libcerror_error_set(
992
0
     error,
993
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
994
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
995
0
     "%s: unable to retrieve number of entries.",
996
0
     function );
997
998
0
    return( -1 );
999
0
  }
1000
0
  for( entry_index = 0;
1001
0
       entry_index < number_of_entries;
1002
0
       entry_index++ )
1003
0
  {
1004
0
    if( libcdata_array_get_entry_by_index(
1005
0
         directory->entries_array,
1006
0
         entry_index,
1007
0
         (intptr_t **) &safe_directory_entry,
1008
0
         error ) != 1 )
1009
0
    {
1010
0
      libcerror_error_set(
1011
0
       error,
1012
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1013
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1014
0
       "%s: unable to retrieve entry: %d.",
1015
0
       function,
1016
0
       entry_index );
1017
1018
0
      return( -1 );
1019
0
    }
1020
0
    result = libfsext_directory_entry_compare_with_utf16_string(
1021
0
              safe_directory_entry,
1022
0
              utf16_string,
1023
0
              utf16_string_length,
1024
0
              error );
1025
1026
0
    if( result == -1 )
1027
0
    {
1028
0
      libcerror_error_set(
1029
0
       error,
1030
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1031
0
       LIBCERROR_RUNTIME_ERROR_GENERIC,
1032
0
       "%s: unable to compare UTF-16 string with directory entry: %d.",
1033
0
       function,
1034
0
       entry_index );
1035
1036
0
      return( -1 );
1037
0
    }
1038
0
    else if( result == LIBUNA_COMPARE_EQUAL )
1039
0
    {
1040
0
      *directory_entry = safe_directory_entry;
1041
1042
0
      return( 1 );
1043
0
    }
1044
0
  }
1045
0
  *directory_entry = NULL;
1046
1047
0
  return( 0 );
1048
0
}
1049