Coverage Report

Created: 2026-08-31 07:43

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.50k
{
50
2.50k
  static char *function = "libfsext_directory_initialize";
51
52
2.50k
  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.50k
  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.50k
  *directory = memory_allocate_structure(
75
2.50k
                libfsext_directory_t );
76
77
2.50k
  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.50k
  if( memory_set(
89
2.50k
       *directory,
90
2.50k
       0,
91
2.50k
       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.50k
  if( libcdata_array_initialize(
108
2.50k
       &( ( *directory )->entries_array ),
109
2.50k
       0,
110
2.50k
       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.50k
  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.50k
}
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.50k
{
141
2.50k
  static char *function = "libfsext_directory_free";
142
2.50k
  int result            = 1;
143
144
2.50k
  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.50k
  if( *directory != NULL )
156
2.50k
  {
157
2.50k
    if( libcdata_array_free(
158
2.50k
         &( ( *directory )->entries_array ),
159
2.50k
         (int (*)(intptr_t **, libcerror_error_t **)) &libfsext_directory_entry_free,
160
2.50k
         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.50k
    memory_free(
172
2.50k
     *directory );
173
174
2.50k
    *directory = NULL;
175
2.50k
  }
176
2.50k
  return( result );
177
2.50k
}
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
13.3k
{
189
13.3k
  libfsext_directory_entry_t *directory_entry = NULL;
190
13.3k
  static char *function                       = "libfsext_directory_read_block_data";
191
13.3k
  size_t data_offset                          = 0;
192
13.3k
  uint32_t safe_directory_entry_index         = 0;
193
13.3k
  int entry_index                             = 0;
194
195
13.3k
  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
13.3k
  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
13.3k
  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
13.3k
  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
13.3k
  safe_directory_entry_index = *directory_entry_index;
240
241
147k
  while( data_offset < data_size )
242
145k
  {
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
145k
    if( libfsext_directory_entry_initialize(
254
145k
         &directory_entry,
255
145k
         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
145k
    if( libfsext_directory_entry_read_data(
268
145k
         directory_entry,
269
145k
         &( data[ data_offset ] ),
270
145k
         data_size - data_offset,
271
145k
         error ) != 1 )
272
56
    {
273
56
      libcerror_error_set(
274
56
       error,
275
56
       LIBCERROR_ERROR_DOMAIN_IO,
276
56
       LIBCERROR_IO_ERROR_READ_FAILED,
277
56
       "%s: unable to read directory entry: %" PRIu32 " at offset: %" PRIzd " (0x%08" PRIzx ").",
278
56
       function,
279
56
       safe_directory_entry_index,
280
56
       data_offset,
281
56
       data_offset );
282
283
56
      goto on_error;
284
56
    }
285
145k
    if( directory_entry->size == 0 )
286
11.0k
    {
287
11.0k
      if( libfsext_directory_entry_free(
288
11.0k
           &directory_entry,
289
11.0k
           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
11.0k
      break;
302
11.0k
    }
303
134k
    data_offset += directory_entry->size;
304
305
/* TODO lost+found has directory entries with size but no values */
306
134k
    if( ( ( directory_entry->name_size == 2 )
307
31.0k
      && ( directory_entry->name[ 0 ] == '.' ) )
308
127k
     || ( ( directory_entry->name_size == 3 )
309
11.6k
      && ( directory_entry->name[ 0 ] == '.' )
310
6.36k
      && ( directory_entry->name[ 1 ] == '.' ) )
311
125k
     || ( directory_entry->inode_number == 0 ) )
312
41.0k
    {
313
41.0k
      if( libfsext_directory_entry_free(
314
41.0k
           &directory_entry,
315
41.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
41.0k
    }
328
93.0k
    else
329
93.0k
    {
330
93.0k
      if( libcdata_array_append_entry(
331
93.0k
           directory->entries_array,
332
93.0k
           &entry_index,
333
93.0k
           (intptr_t *) directory_entry,
334
93.0k
           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
93.0k
      directory_entry = NULL;
347
93.0k
    }
348
134k
    safe_directory_entry_index++;
349
134k
  }
350
13.2k
  *directory_entry_index = safe_directory_entry_index;
351
352
13.2k
  return( 1 );
353
354
56
on_error:
355
56
  if( directory_entry != NULL )
356
56
  {
357
56
    libfsext_directory_entry_free(
358
56
     &directory_entry,
359
56
     NULL );
360
56
  }
361
56
  return( -1 );
362
13.3k
}
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.12k
{
373
1.12k
  libfsext_directory_entry_t *directory_entry = NULL;
374
1.12k
  static char *function                       = "libfsext_directory_read_inline_data";
375
1.12k
  size_t data_offset                          = 0;
376
1.12k
  uint32_t directory_entry_index              = 0;
377
1.12k
  int entry_index                             = 0;
378
379
#if defined( HAVE_DEBUG_OUTPUT )
380
  uint32_t value_32bit                        = 0;
381
#endif
382
383
1.12k
  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.12k
  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.12k
  if( ( data_size < 4 )
406
1.11k
   || ( data_size > (size_t) SSIZE_MAX ) )
407
6
  {
408
6
    libcerror_error_set(
409
6
     error,
410
6
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
411
6
     LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
412
6
     "%s: invalid data size value exceeds maximum.",
413
6
     function );
414
415
6
    return( -1 );
416
6
  }
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.11k
  data_offset += 4;
434
435
3.06k
  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
37
    {
467
37
      libcerror_error_set(
468
37
       error,
469
37
       LIBCERROR_ERROR_DOMAIN_IO,
470
37
       LIBCERROR_IO_ERROR_READ_FAILED,
471
37
       "%s: unable to read directory entry: %" PRIu32 " at offset: %" PRIzd " (0x%08" PRIzx ").",
472
37
       function,
473
37
       directory_entry_index,
474
37
       data_offset,
475
37
       data_offset );
476
477
37
      goto on_error;
478
37
    }
479
2.66k
    if( directory_entry->size == 0 )
480
713
    {
481
713
      if( libfsext_directory_entry_free(
482
713
           &directory_entry,
483
713
           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
713
      break;
496
713
    }
497
1.95k
    data_offset += directory_entry->size;
498
499
/* TODO lost+found has directory entries with size but no values */
500
1.95k
    if( ( ( directory_entry->name_size == 2 )
501
229
      && ( directory_entry->name[ 0 ] == '.' ) )
502
1.91k
     || ( ( directory_entry->name_size == 3 )
503
455
      && ( directory_entry->name[ 0 ] == '.' )
504
155
      && ( directory_entry->name[ 1 ] == '.' ) )
505
1.86k
     || ( directory_entry->inode_number == 0 ) )
506
150
    {
507
150
      if( libfsext_directory_entry_free(
508
150
           &directory_entry,
509
150
           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
150
    }
522
1.80k
    else
523
1.80k
    {
524
1.80k
      if( libcdata_array_append_entry(
525
1.80k
           directory->entries_array,
526
1.80k
           &entry_index,
527
1.80k
           (intptr_t *) directory_entry,
528
1.80k
           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.80k
      directory_entry = NULL;
541
1.80k
    }
542
1.95k
    directory_entry_index++;
543
1.95k
  }
544
1.08k
  return( 1 );
545
546
37
on_error:
547
37
  if( directory_entry != NULL )
548
37
  {
549
37
    libfsext_directory_entry_free(
550
37
     &directory_entry,
551
37
     NULL );
552
37
  }
553
37
  return( -1 );
554
1.11k
}
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.50k
{
566
2.50k
  libfcache_cache_t *block_cache  = NULL;
567
2.50k
  libfdata_vector_t *block_vector = NULL;
568
2.50k
  libfsext_block_t *block         = NULL;
569
2.50k
  static char *function           = "libfsext_directory_read_file_io_handle";
570
2.50k
  size_t inline_data_size         = 0;
571
2.50k
  uint32_t directory_entry_index  = 0;
572
2.50k
  int block_index                 = 0;
573
2.50k
  int number_of_blocks            = 0;
574
575
2.50k
  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.50k
  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.50k
  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.50k
  if( ( inode->file_mode & 0xf000 ) != LIBFSEXT_FILE_TYPE_DIRECTORY )
609
104
  {
610
104
    libcerror_error_set(
611
104
     error,
612
104
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
613
104
     LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
614
104
     "%s: invalid inode - unsupported file type.",
615
104
     function );
616
617
104
    return( -1 );
618
104
  }
619
2.40k
  if( ( io_handle->format_version == 4 )
620
1.69k
   && ( ( inode->flags & LIBFSEXT_INODE_FLAG_INLINE_DATA ) != 0 ) )
621
1.12k
  {
622
    /* Note that inode->data_size can be larger than 60
623
     * but inode->data_reference only holds 60 bytes
624
     */
625
1.12k
    if( inode->data_size < 60 )
626
68
    {
627
68
      inline_data_size = inode->data_size;
628
68
    }
629
1.05k
    else
630
1.05k
    {
631
1.05k
      inline_data_size = 60;
632
1.05k
    }
633
1.12k
    if( libfsext_directory_read_inline_data(
634
1.12k
         directory,
635
1.12k
         inode->data_reference,
636
1.12k
         inline_data_size,
637
1.12k
         error ) != 1 )
638
43
    {
639
43
      libcerror_error_set(
640
43
       error,
641
43
       LIBCERROR_ERROR_DOMAIN_IO,
642
43
       LIBCERROR_IO_ERROR_READ_FAILED,
643
43
       "%s: unable to read directory inline data.",
644
43
       function );
645
646
43
      goto on_error;
647
43
    }
648
1.12k
  }
649
1.27k
  else
650
1.27k
  {
651
1.27k
    if( libfsext_block_vector_initialize(
652
1.27k
         &block_vector,
653
1.27k
         io_handle,
654
1.27k
         inode,
655
1.27k
         error ) != 1 )
656
88
    {
657
88
      libcerror_error_set(
658
88
       error,
659
88
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
660
88
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
661
88
       "%s: unable to create block vector.",
662
88
       function );
663
664
88
      goto on_error;
665
88
    }
666
1.19k
    if( libfcache_cache_initialize(
667
1.19k
         &block_cache,
668
1.19k
         LIBFSEXT_MAXIMUM_CACHE_ENTRIES_BLOCKS,
669
1.19k
         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.19k
    if( libfdata_vector_get_number_of_elements(
681
1.19k
         block_vector,
682
1.19k
         &number_of_blocks,
683
1.19k
         error ) != 1 )
684
4
    {
685
4
      libcerror_error_set(
686
4
       error,
687
4
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
688
4
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
689
4
       "%s: unable to retrieve number of blocks.",
690
4
       function );
691
692
4
      goto on_error;
693
4
    }
694
1.18k
    for( block_index = 0;
695
14.4k
         block_index < number_of_blocks;
696
13.2k
         block_index++ )
697
13.5k
    {
698
13.5k
      if( libfdata_vector_get_element_value_by_index(
699
13.5k
           block_vector,
700
13.5k
           (intptr_t *) file_io_handle,
701
13.5k
           (libfdata_cache_t *) block_cache,
702
13.5k
           block_index,
703
13.5k
           (intptr_t **) &block,
704
13.5k
           0,
705
13.5k
           error ) != 1 )
706
250
      {
707
250
        libcerror_error_set(
708
250
         error,
709
250
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
710
250
         LIBCERROR_RUNTIME_ERROR_GET_FAILED,
711
250
         "%s: unable to retrieve block: %d.",
712
250
         function,
713
250
         block_index );
714
715
250
        goto on_error;
716
250
      }
717
13.3k
      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
13.3k
      if( libfsext_directory_read_block_data(
729
13.3k
           directory,
730
13.3k
           block->data,
731
13.3k
           (size_t) block->data_size,
732
13.3k
           &directory_entry_index,
733
13.3k
           error ) != 1 )
734
56
      {
735
56
        libcerror_error_set(
736
56
         error,
737
56
         LIBCERROR_ERROR_DOMAIN_IO,
738
56
         LIBCERROR_IO_ERROR_READ_FAILED,
739
56
         "%s: unable to read directory block: %d.",
740
56
         function,
741
56
         block_index );
742
743
56
        goto on_error;
744
56
      }
745
13.3k
    }
746
881
    if( libfcache_cache_free(
747
881
         &block_cache,
748
881
         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
881
    if( libfdata_vector_free(
760
881
         &block_vector,
761
881
         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
881
  }
773
1.96k
  return( 1 );
774
775
441
on_error:
776
441
  if( block_cache != NULL )
777
310
  {
778
310
    libfcache_cache_free(
779
310
     &block_cache,
780
310
     NULL );
781
310
  }
782
441
  if( block_vector != NULL )
783
310
  {
784
310
    libfdata_vector_free(
785
310
     &block_vector,
786
310
     NULL );
787
310
  }
788
441
  return( -1 );
789
2.40k
}
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
759
{
799
759
  static char *function = "libfsext_directory_get_number_of_entries";
800
801
759
  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
759
  if( libcdata_array_get_number_of_entries(
813
759
       directory->entries_array,
814
759
       number_of_entries,
815
759
       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
759
  return( 1 );
827
759
}
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
742
{
838
742
  static char *function = "libfsext_directory_get_entry_by_index";
839
840
742
  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
742
  if( libcdata_array_get_entry_by_index(
852
742
       directory->entries_array,
853
742
       entry_index,
854
742
       (intptr_t **) directory_entry,
855
742
       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
742
  return( 1 );
868
742
}
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.20k
{
880
1.20k
  libfsext_directory_entry_t *safe_directory_entry = NULL;
881
1.20k
  static char *function                            = "libfsext_directory_get_entry_by_utf8_name";
882
1.20k
  int entry_index                                  = 0;
883
1.20k
  int number_of_entries                            = 0;
884
1.20k
  int result                                       = 0;
885
886
1.20k
  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.20k
  if( libcdata_array_get_number_of_entries(
898
1.20k
       directory->entries_array,
899
1.20k
       &number_of_entries,
900
1.20k
       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.20k
  for( entry_index = 0;
912
29.7k
       entry_index < number_of_entries;
913
28.5k
       entry_index++ )
914
29.6k
  {
915
29.6k
    if( libcdata_array_get_entry_by_index(
916
29.6k
         directory->entries_array,
917
29.6k
         entry_index,
918
29.6k
         (intptr_t **) &safe_directory_entry,
919
29.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
29.6k
    result = libfsext_directory_entry_compare_with_utf8_string(
932
29.6k
              safe_directory_entry,
933
29.6k
              utf8_string,
934
29.6k
              utf8_string_length,
935
29.6k
              error );
936
937
29.6k
    if( result == -1 )
938
64
    {
939
64
      libcerror_error_set(
940
64
       error,
941
64
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
942
64
       LIBCERROR_RUNTIME_ERROR_GENERIC,
943
64
       "%s: unable to compare UTF-8 string with directory entry: %d.",
944
64
       function,
945
64
       entry_index );
946
947
64
      return( -1 );
948
64
    }
949
29.5k
    else if( result == LIBUNA_COMPARE_EQUAL )
950
1.02k
    {
951
1.02k
      *directory_entry = safe_directory_entry;
952
953
1.02k
      return( 1 );
954
1.02k
    }
955
29.6k
  }
956
117
  *directory_entry = NULL;
957
958
117
  return( 0 );
959
1.20k
}
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