Coverage Report

Created: 2026-07-25 07:30

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-2026, 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.58k
{
50
2.58k
  static char *function = "libfsext_directory_initialize";
51
52
2.58k
  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.58k
  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.58k
  *directory = memory_allocate_structure(
75
2.58k
                libfsext_directory_t );
76
77
2.58k
  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.58k
  if( memory_set(
89
2.58k
       *directory,
90
2.58k
       0,
91
2.58k
       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.58k
  if( libcdata_array_initialize(
108
2.58k
       &( ( *directory )->entries_array ),
109
2.58k
       0,
110
2.58k
       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.58k
  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.58k
}
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.58k
{
141
2.58k
  static char *function = "libfsext_directory_free";
142
2.58k
  int result            = 1;
143
144
2.58k
  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.58k
  if( *directory != NULL )
156
2.58k
  {
157
2.58k
    if( libcdata_array_free(
158
2.58k
         &( ( *directory )->entries_array ),
159
2.58k
         (int (*)(intptr_t **, libcerror_error_t **)) &libfsext_directory_entry_free,
160
2.58k
         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.58k
    memory_free(
172
2.58k
     *directory );
173
174
2.58k
    *directory = NULL;
175
2.58k
  }
176
2.58k
  return( result );
177
2.58k
}
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
16.0k
{
189
16.0k
  libfsext_directory_entry_t *directory_entry = NULL;
190
16.0k
  static char *function                       = "libfsext_directory_read_block_data";
191
16.0k
  size_t data_offset                          = 0;
192
16.0k
  uint32_t safe_directory_entry_index         = 0;
193
16.0k
  int entry_index                             = 0;
194
195
16.0k
  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
16.0k
  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
16.0k
  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
16.0k
  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
16.0k
  safe_directory_entry_index = *directory_entry_index;
240
241
157k
  while( data_offset < data_size )
242
154k
  {
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
154k
    if( libfsext_directory_entry_initialize(
254
154k
         &directory_entry,
255
154k
         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
154k
    if( libfsext_directory_entry_read_data(
268
154k
         directory_entry,
269
154k
         &( data[ data_offset ] ),
270
154k
         data_size - data_offset,
271
154k
         error ) != 1 )
272
55
    {
273
55
      libcerror_error_set(
274
55
       error,
275
55
       LIBCERROR_ERROR_DOMAIN_IO,
276
55
       LIBCERROR_IO_ERROR_READ_FAILED,
277
55
       "%s: unable to read directory entry: %" PRIu32 " at offset: %" PRIzd " (0x%08" PRIzx ").",
278
55
       function,
279
55
       safe_directory_entry_index,
280
55
       data_offset,
281
55
       data_offset );
282
283
55
      goto on_error;
284
55
    }
285
154k
    if( directory_entry->size == 0 )
286
13.4k
    {
287
13.4k
      if( libfsext_directory_entry_free(
288
13.4k
           &directory_entry,
289
13.4k
           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
13.4k
      break;
302
13.4k
    }
303
141k
    data_offset += directory_entry->size;
304
305
/* TODO lost+found has directory entries with size but no values */
306
141k
    if( ( ( directory_entry->name_size == 2 )
307
33.5k
      && ( directory_entry->name[ 0 ] == '.' ) )
308
134k
     || ( ( directory_entry->name_size == 3 )
309
12.2k
      && ( directory_entry->name[ 0 ] == '.' )
310
6.14k
      && ( directory_entry->name[ 1 ] == '.' ) )
311
132k
     || ( directory_entry->inode_number == 0 ) )
312
40.2k
    {
313
40.2k
      if( libfsext_directory_entry_free(
314
40.2k
           &directory_entry,
315
40.2k
           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
40.2k
    }
328
101k
    else
329
101k
    {
330
101k
      if( libcdata_array_append_entry(
331
101k
           directory->entries_array,
332
101k
           &entry_index,
333
101k
           (intptr_t *) directory_entry,
334
101k
           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
101k
      directory_entry = NULL;
347
101k
    }
348
141k
    safe_directory_entry_index++;
349
141k
  }
350
15.9k
  *directory_entry_index = safe_directory_entry_index;
351
352
15.9k
  return( 1 );
353
354
55
on_error:
355
55
  if( directory_entry != NULL )
356
55
  {
357
55
    libfsext_directory_entry_free(
358
55
     &directory_entry,
359
55
     NULL );
360
55
  }
361
55
  return( -1 );
362
16.0k
}
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
1.17k
{
373
1.17k
  libfsext_directory_entry_t *directory_entry = NULL;
374
1.17k
  static char *function                       = "libfsext_directory_read_inline_data";
375
1.17k
  size_t data_offset                          = 0;
376
1.17k
  uint32_t directory_entry_index              = 0;
377
1.17k
  int entry_index                             = 0;
378
379
#if defined( HAVE_DEBUG_OUTPUT )
380
  uint32_t value_32bit                        = 0;
381
#endif
382
383
1.17k
  if( directory == NULL )
384
0
  {
385
0
    libcerror_error_set(
386
0
     error,
387
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
388
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
389
0
     "%s: invalid directory.",
390
0
     function );
391
392
0
    return( -1 );
393
0
  }
394
1.17k
  if( data == NULL )
395
0
  {
396
0
    libcerror_error_set(
397
0
     error,
398
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
399
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
400
0
     "%s: invalid data.",
401
0
     function );
402
403
0
    return( -1 );
404
0
  }
405
1.17k
  if( ( data_size < 4 )
406
1.17k
   || ( data_size > (size_t) SSIZE_MAX ) )
407
4
  {
408
4
    libcerror_error_set(
409
4
     error,
410
4
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
411
4
     LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
412
4
     "%s: invalid data size value exceeds maximum.",
413
4
     function );
414
415
4
    return( -1 );
416
4
  }
417
#if defined( HAVE_DEBUG_OUTPUT )
418
  if( libcnotify_verbose != 0 )
419
  {
420
    byte_stream_copy_to_uint32_little_endian(
421
     data,
422
     value_32bit );
423
    libcnotify_printf(
424
     "%s: parent inode number\t\t: %" PRIu32 "\n",
425
     function,
426
     value_32bit );
427
428
    libcnotify_printf(
429
     "\n" );
430
  }
431
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
432
433
1.17k
  data_offset += 4;
434
435
3.11k
  while( data_offset < data_size )
436
2.70k
  {
437
#if defined( HAVE_DEBUG_OUTPUT )
438
    if( libcnotify_verbose != 0 )
439
    {
440
      libcnotify_printf(
441
       "Reading directory entry: %" PRIu32 " at offset: %" PRIzd " (0x%08" PRIzx ")\n",
442
       directory_entry_index,
443
       data_offset,
444
       data_offset );
445
    }
446
#endif
447
2.70k
    if( libfsext_directory_entry_initialize(
448
2.70k
         &directory_entry,
449
2.70k
         error ) != 1 )
450
0
    {
451
0
      libcerror_error_set(
452
0
       error,
453
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
454
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
455
0
       "%s: unable to create directory entry: %" PRIu32 ".",
456
0
       function,
457
0
       directory_entry_index );
458
459
0
      goto on_error;
460
0
    }
461
2.70k
    if( libfsext_directory_entry_read_data(
462
2.70k
         directory_entry,
463
2.70k
         &( data[ data_offset ] ),
464
2.70k
         data_size - data_offset,
465
2.70k
         error ) != 1 )
466
40
    {
467
40
      libcerror_error_set(
468
40
       error,
469
40
       LIBCERROR_ERROR_DOMAIN_IO,
470
40
       LIBCERROR_IO_ERROR_READ_FAILED,
471
40
       "%s: unable to read directory entry: %" PRIu32 " at offset: %" PRIzd " (0x%08" PRIzx ").",
472
40
       function,
473
40
       directory_entry_index,
474
40
       data_offset,
475
40
       data_offset );
476
477
40
      goto on_error;
478
40
    }
479
2.66k
    if( directory_entry->size == 0 )
480
725
    {
481
725
      if( libfsext_directory_entry_free(
482
725
           &directory_entry,
483
725
           error ) != 1 )
484
0
      {
485
0
        libcerror_error_set(
486
0
         error,
487
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
488
0
         LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
489
0
         "%s: unable to free directory entry: %" PRIu32 ".",
490
0
         function,
491
0
         directory_entry_index );
492
493
0
        goto on_error;
494
0
      }
495
725
      break;
496
725
    }
497
1.94k
    data_offset += directory_entry->size;
498
499
/* TODO lost+found has directory entries with size but no values */
500
1.94k
    if( ( ( directory_entry->name_size == 2 )
501
212
      && ( directory_entry->name[ 0 ] == '.' ) )
502
1.90k
     || ( ( directory_entry->name_size == 3 )
503
469
      && ( directory_entry->name[ 0 ] == '.' )
504
165
      && ( directory_entry->name[ 1 ] == '.' ) )
505
1.86k
     || ( directory_entry->inode_number == 0 ) )
506
143
    {
507
143
      if( libfsext_directory_entry_free(
508
143
           &directory_entry,
509
143
           error ) != 1 )
510
0
      {
511
0
        libcerror_error_set(
512
0
         error,
513
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
514
0
         LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
515
0
         "%s: unable to free directory entry: %" PRIu32 ".",
516
0
         function,
517
0
         directory_entry_index );
518
519
0
        goto on_error;
520
0
      }
521
143
    }
522
1.79k
    else
523
1.79k
    {
524
1.79k
      if( libcdata_array_append_entry(
525
1.79k
           directory->entries_array,
526
1.79k
           &entry_index,
527
1.79k
           (intptr_t *) directory_entry,
528
1.79k
           error ) != 1 )
529
0
      {
530
0
        libcerror_error_set(
531
0
         error,
532
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
533
0
         LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
534
0
         "%s: unable to append directory entry: %" PRIu32 " to array.",
535
0
         function,
536
0
         directory_entry_index );
537
538
0
        goto on_error;
539
0
      }
540
1.79k
      directory_entry = NULL;
541
1.79k
    }
542
1.94k
    directory_entry_index++;
543
1.94k
  }
544
1.13k
  return( 1 );
545
546
40
on_error:
547
40
  if( directory_entry != NULL )
548
40
  {
549
40
    libfsext_directory_entry_free(
550
40
     &directory_entry,
551
40
     NULL );
552
40
  }
553
40
  return( -1 );
554
1.17k
}
555
556
/* Reads the directory entries
557
 * Returns 1 if successful or -1 on error
558
 */
559
int libfsext_directory_read_file_io_handle(
560
     libfsext_directory_t *directory,
561
     libfsext_io_handle_t *io_handle,
562
     libbfio_handle_t *file_io_handle,
563
     libfsext_inode_t *inode,
564
     libcerror_error_t **error )
565
2.58k
{
566
2.58k
  libfcache_cache_t *block_cache  = NULL;
567
2.58k
  libfdata_vector_t *block_vector = NULL;
568
2.58k
  libfsext_block_t *block         = NULL;
569
2.58k
  static char *function           = "libfsext_directory_read_file_io_handle";
570
2.58k
  size_t inline_data_size         = 0;
571
2.58k
  uint32_t directory_entry_index  = 0;
572
2.58k
  int block_index                 = 0;
573
2.58k
  int number_of_blocks            = 0;
574
575
2.58k
  if( directory == NULL )
576
0
  {
577
0
    libcerror_error_set(
578
0
     error,
579
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
580
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
581
0
     "%s: invalid directory.",
582
0
     function );
583
584
0
    return( -1 );
585
0
  }
586
2.58k
  if( io_handle == NULL )
587
0
  {
588
0
    libcerror_error_set(
589
0
     error,
590
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
591
0
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
592
0
     "%s: invalid IO handle.",
593
0
     function );
594
595
0
    return( -1 );
596
0
  }
597
2.58k
  if( inode == NULL )
598
0
  {
599
0
    libcerror_error_set(
600
0
     error,
601
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
602
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
603
0
     "%s: invalid inode.",
604
0
     function );
605
606
0
    return( -1 );
607
0
  }
608
2.58k
  if( ( inode->file_mode & 0xf000 ) != LIBFSEXT_FILE_TYPE_DIRECTORY )
609
109
  {
610
109
    libcerror_error_set(
611
109
     error,
612
109
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
613
109
     LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
614
109
     "%s: invalid inode - unsupported file type.",
615
109
     function );
616
617
109
    return( -1 );
618
109
  }
619
2.48k
  if( ( io_handle->format_version == 4 )
620
1.74k
   && ( ( inode->flags & LIBFSEXT_INODE_FLAG_INLINE_DATA ) != 0 ) )
621
1.17k
  {
622
    /* Note that inode->data_size can be larger than 60
623
     * but inode->data_reference only holds 60 bytes
624
     */
625
1.17k
    if( inode->data_size < 60 )
626
68
    {
627
68
      inline_data_size = inode->data_size;
628
68
    }
629
1.10k
    else
630
1.10k
    {
631
1.10k
      inline_data_size = 60;
632
1.10k
    }
633
1.17k
    if( libfsext_directory_read_inline_data(
634
1.17k
         directory,
635
1.17k
         inode->data_reference,
636
1.17k
         inline_data_size,
637
1.17k
         error ) != 1 )
638
44
    {
639
44
      libcerror_error_set(
640
44
       error,
641
44
       LIBCERROR_ERROR_DOMAIN_IO,
642
44
       LIBCERROR_IO_ERROR_READ_FAILED,
643
44
       "%s: unable to read directory inline data.",
644
44
       function );
645
646
44
      goto on_error;
647
44
    }
648
1.17k
  }
649
1.30k
  else
650
1.30k
  {
651
1.30k
    if( libfsext_block_vector_initialize(
652
1.30k
         &block_vector,
653
1.30k
         io_handle,
654
1.30k
         inode,
655
1.30k
         error ) != 1 )
656
79
    {
657
79
      libcerror_error_set(
658
79
       error,
659
79
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
660
79
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
661
79
       "%s: unable to create block vector.",
662
79
       function );
663
664
79
      goto on_error;
665
79
    }
666
1.22k
    if( libfcache_cache_initialize(
667
1.22k
         &block_cache,
668
1.22k
         LIBFSEXT_MAXIMUM_CACHE_ENTRIES_BLOCKS,
669
1.22k
         error ) != 1 )
670
0
    {
671
0
      libcerror_error_set(
672
0
       error,
673
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
674
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
675
0
       "%s: unable to create block cache.",
676
0
       function );
677
678
0
      goto on_error;
679
0
    }
680
1.22k
    if( libfdata_vector_get_number_of_elements(
681
1.22k
         block_vector,
682
1.22k
         &number_of_blocks,
683
1.22k
         error ) != 1 )
684
5
    {
685
5
      libcerror_error_set(
686
5
       error,
687
5
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
688
5
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
689
5
       "%s: unable to retrieve number of blocks.",
690
5
       function );
691
692
5
      goto on_error;
693
5
    }
694
1.21k
    for( block_index = 0;
695
17.1k
         block_index < number_of_blocks;
696
15.9k
         block_index++ )
697
16.2k
    {
698
16.2k
      if( libfdata_vector_get_element_value_by_index(
699
16.2k
           block_vector,
700
16.2k
           (intptr_t *) file_io_handle,
701
16.2k
           (libfdata_cache_t *) block_cache,
702
16.2k
           block_index,
703
16.2k
           (intptr_t **) &block,
704
16.2k
           0,
705
16.2k
           error ) != 1 )
706
261
      {
707
261
        libcerror_error_set(
708
261
         error,
709
261
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
710
261
         LIBCERROR_RUNTIME_ERROR_GET_FAILED,
711
261
         "%s: unable to retrieve block: %d.",
712
261
         function,
713
261
         block_index );
714
715
261
        goto on_error;
716
261
      }
717
16.0k
      if( block == NULL )
718
0
      {
719
0
        libcerror_error_set(
720
0
         error,
721
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
722
0
         LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
723
0
         "%s: invalid block.",
724
0
         function );
725
726
0
        goto on_error;
727
0
      }
728
16.0k
      if( libfsext_directory_read_block_data(
729
16.0k
           directory,
730
16.0k
           block->data,
731
16.0k
           (size_t) block->data_size,
732
16.0k
           &directory_entry_index,
733
16.0k
           error ) != 1 )
734
55
      {
735
55
        libcerror_error_set(
736
55
         error,
737
55
         LIBCERROR_ERROR_DOMAIN_IO,
738
55
         LIBCERROR_IO_ERROR_READ_FAILED,
739
55
         "%s: unable to read directory block: %d.",
740
55
         function,
741
55
         block_index );
742
743
55
        goto on_error;
744
55
      }
745
16.0k
    }
746
903
    if( libfcache_cache_free(
747
903
         &block_cache,
748
903
         error ) != 1 )
749
0
    {
750
0
      libcerror_error_set(
751
0
       error,
752
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
753
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
754
0
       "%s: unable to free block cache.",
755
0
       function );
756
757
0
      goto on_error;
758
0
    }
759
903
    if( libfdata_vector_free(
760
903
         &block_vector,
761
903
         error ) != 1 )
762
0
    {
763
0
      libcerror_error_set(
764
0
       error,
765
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
766
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
767
0
       "%s: unable to free block vector.",
768
0
       function );
769
770
0
      goto on_error;
771
0
    }
772
903
  }
773
2.03k
  return( 1 );
774
775
444
on_error:
776
444
  if( block_cache != NULL )
777
321
  {
778
321
    libfcache_cache_free(
779
321
     &block_cache,
780
321
     NULL );
781
321
  }
782
444
  if( block_vector != NULL )
783
321
  {
784
321
    libfdata_vector_free(
785
321
     &block_vector,
786
321
     NULL );
787
321
  }
788
444
  return( -1 );
789
2.48k
}
790
791
/* Retrieves the number of entries
792
 * Returns 1 if successful or -1 on error
793
 */
794
int libfsext_directory_get_number_of_entries(
795
     libfsext_directory_t *directory,
796
     int *number_of_entries,
797
     libcerror_error_t **error )
798
787
{
799
787
  static char *function = "libfsext_directory_get_number_of_entries";
800
801
787
  if( directory == NULL )
802
0
  {
803
0
    libcerror_error_set(
804
0
     error,
805
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
806
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
807
0
     "%s: invalid directory.",
808
0
     function );
809
810
0
    return( -1 );
811
0
  }
812
787
  if( libcdata_array_get_number_of_entries(
813
787
       directory->entries_array,
814
787
       number_of_entries,
815
787
       error ) != 1 )
816
0
  {
817
0
    libcerror_error_set(
818
0
     error,
819
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
820
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
821
0
     "%s: unable to retrieve number of entries.",
822
0
     function );
823
824
0
    return( -1 );
825
0
  }
826
787
  return( 1 );
827
787
}
828
829
/* Retrieves a specific entry
830
 * Returns 1 if successful or -1 on error
831
 */
832
int libfsext_directory_get_entry_by_index(
833
     libfsext_directory_t *directory,
834
     int entry_index,
835
     libfsext_directory_entry_t **directory_entry,
836
     libcerror_error_t **error )
837
768
{
838
768
  static char *function = "libfsext_directory_get_entry_by_index";
839
840
768
  if( directory == NULL )
841
0
  {
842
0
    libcerror_error_set(
843
0
     error,
844
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
845
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
846
0
     "%s: invalid directory.",
847
0
     function );
848
849
0
    return( -1 );
850
0
  }
851
768
  if( libcdata_array_get_entry_by_index(
852
768
       directory->entries_array,
853
768
       entry_index,
854
768
       (intptr_t **) directory_entry,
855
768
       error ) != 1 )
856
0
  {
857
0
    libcerror_error_set(
858
0
     error,
859
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
860
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
861
0
     "%s: unable to retrieve entry: %d.",
862
0
     function,
863
0
     entry_index );
864
865
0
    return( -1 );
866
0
  }
867
768
  return( 1 );
868
768
}
869
870
/* Retrieves the directory entry for an UTF-8 encoded name
871
 * Returns 1 if successful, 0 if not found or -1 on error
872
 */
873
int libfsext_directory_get_entry_by_utf8_name(
874
     libfsext_directory_t *directory,
875
     const uint8_t *utf8_string,
876
     size_t utf8_string_length,
877
     libfsext_directory_entry_t **directory_entry,
878
     libcerror_error_t **error )
879
1.24k
{
880
1.24k
  libfsext_directory_entry_t *safe_directory_entry = NULL;
881
1.24k
  static char *function                            = "libfsext_directory_get_entry_by_utf8_name";
882
1.24k
  int entry_index                                  = 0;
883
1.24k
  int number_of_entries                            = 0;
884
1.24k
  int result                                       = 0;
885
886
1.24k
  if( directory == NULL )
887
0
  {
888
0
    libcerror_error_set(
889
0
     error,
890
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
891
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
892
0
     "%s: invalid directory.",
893
0
     function );
894
895
0
    return( -1 );
896
0
  }
897
1.24k
  if( libcdata_array_get_number_of_entries(
898
1.24k
       directory->entries_array,
899
1.24k
       &number_of_entries,
900
1.24k
       error ) != 1 )
901
0
  {
902
0
    libcerror_error_set(
903
0
     error,
904
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
905
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
906
0
     "%s: unable to retrieve number of entries.",
907
0
     function );
908
909
0
    return( -1 );
910
0
  }
911
1.24k
  for( entry_index = 0;
912
30.7k
       entry_index < number_of_entries;
913
29.5k
       entry_index++ )
914
30.6k
  {
915
30.6k
    if( libcdata_array_get_entry_by_index(
916
30.6k
         directory->entries_array,
917
30.6k
         entry_index,
918
30.6k
         (intptr_t **) &safe_directory_entry,
919
30.6k
         error ) != 1 )
920
0
    {
921
0
      libcerror_error_set(
922
0
       error,
923
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
924
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
925
0
       "%s: unable to retrieve entry: %d.",
926
0
       function,
927
0
       entry_index );
928
929
0
      return( -1 );
930
0
    }
931
30.6k
    result = libfsext_directory_entry_compare_with_utf8_string(
932
30.6k
              safe_directory_entry,
933
30.6k
              utf8_string,
934
30.6k
              utf8_string_length,
935
30.6k
              error );
936
937
30.6k
    if( result == -1 )
938
61
    {
939
61
      libcerror_error_set(
940
61
       error,
941
61
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
942
61
       LIBCERROR_RUNTIME_ERROR_GENERIC,
943
61
       "%s: unable to compare UTF-8 string with directory entry: %d.",
944
61
       function,
945
61
       entry_index );
946
947
61
      return( -1 );
948
61
    }
949
30.5k
    else if( result == LIBUNA_COMPARE_EQUAL )
950
1.06k
    {
951
1.06k
      *directory_entry = safe_directory_entry;
952
953
1.06k
      return( 1 );
954
1.06k
    }
955
30.6k
  }
956
123
  *directory_entry = NULL;
957
958
123
  return( 0 );
959
1.24k
}
960
961
/* Retrieves the directory entry for an UTF-16 encoded name
962
 * Returns 1 if successful, 0 if not found or -1 on error
963
 */
964
int libfsext_directory_get_entry_by_utf16_name(
965
     libfsext_directory_t *directory,
966
     const uint16_t *utf16_string,
967
     size_t utf16_string_length,
968
     libfsext_directory_entry_t **directory_entry,
969
     libcerror_error_t **error )
970
0
{
971
0
  libfsext_directory_entry_t *safe_directory_entry = NULL;
972
0
  static char *function                            = "libfsext_directory_get_entry_by_utf16_name";
973
0
  int entry_index                                  = 0;
974
0
  int number_of_entries                            = 0;
975
0
  int result                                       = 0;
976
977
0
  if( directory == NULL )
978
0
  {
979
0
    libcerror_error_set(
980
0
     error,
981
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
982
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
983
0
     "%s: invalid directory.",
984
0
     function );
985
986
0
    return( -1 );
987
0
  }
988
0
  if( libcdata_array_get_number_of_entries(
989
0
       directory->entries_array,
990
0
       &number_of_entries,
991
0
       error ) != 1 )
992
0
  {
993
0
    libcerror_error_set(
994
0
     error,
995
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
996
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
997
0
     "%s: unable to retrieve number of entries.",
998
0
     function );
999
1000
0
    return( -1 );
1001
0
  }
1002
0
  for( entry_index = 0;
1003
0
       entry_index < number_of_entries;
1004
0
       entry_index++ )
1005
0
  {
1006
0
    if( libcdata_array_get_entry_by_index(
1007
0
         directory->entries_array,
1008
0
         entry_index,
1009
0
         (intptr_t **) &safe_directory_entry,
1010
0
         error ) != 1 )
1011
0
    {
1012
0
      libcerror_error_set(
1013
0
       error,
1014
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1015
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1016
0
       "%s: unable to retrieve entry: %d.",
1017
0
       function,
1018
0
       entry_index );
1019
1020
0
      return( -1 );
1021
0
    }
1022
0
    result = libfsext_directory_entry_compare_with_utf16_string(
1023
0
              safe_directory_entry,
1024
0
              utf16_string,
1025
0
              utf16_string_length,
1026
0
              error );
1027
1028
0
    if( result == -1 )
1029
0
    {
1030
0
      libcerror_error_set(
1031
0
       error,
1032
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1033
0
       LIBCERROR_RUNTIME_ERROR_GENERIC,
1034
0
       "%s: unable to compare UTF-16 string with directory entry: %d.",
1035
0
       function,
1036
0
       entry_index );
1037
1038
0
      return( -1 );
1039
0
    }
1040
0
    else if( result == LIBUNA_COMPARE_EQUAL )
1041
0
    {
1042
0
      *directory_entry = safe_directory_entry;
1043
1044
0
      return( 1 );
1045
0
    }
1046
0
  }
1047
0
  *directory_entry = NULL;
1048
1049
0
  return( 0 );
1050
0
}
1051