Coverage Report

Created: 2026-04-10 07:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libfsxfs/libfsxfs/libfsxfs_file_system.c
Line
Count
Source
1
/*
2
 * File system functions
3
 *
4
 * Copyright (C) 2020-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 <memory.h>
24
#include <types.h>
25
26
#include "libfsxfs_definitions.h"
27
#include "libfsxfs_directory.h"
28
#include "libfsxfs_directory_entry.h"
29
#include "libfsxfs_file_system.h"
30
#include "libfsxfs_inode.h"
31
#include "libfsxfs_inode_btree.h"
32
#include "libfsxfs_inode_information.h"
33
#include "libfsxfs_libbfio.h"
34
#include "libfsxfs_libcerror.h"
35
#include "libfsxfs_libcnotify.h"
36
#include "libfsxfs_libcthreads.h"
37
#include "libfsxfs_libuna.h"
38
39
/* Creates a file system
40
 * Make sure the value file_system is referencing, is set to NULL
41
 * Returns 1 if successful or -1 on error
42
 */
43
int libfsxfs_file_system_initialize(
44
     libfsxfs_file_system_t **file_system,
45
     uint64_t root_directory_inode_number,
46
     libcerror_error_t **error )
47
4.24k
{
48
4.24k
  static char *function = "libfsxfs_file_system_initialize";
49
50
4.24k
  if( file_system == NULL )
51
0
  {
52
0
    libcerror_error_set(
53
0
     error,
54
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
55
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
56
0
     "%s: invalid file system.",
57
0
     function );
58
59
0
    return( -1 );
60
0
  }
61
4.24k
  if( *file_system != NULL )
62
0
  {
63
0
    libcerror_error_set(
64
0
     error,
65
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
66
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
67
0
     "%s: invalid file system value already set.",
68
0
     function );
69
70
0
    return( -1 );
71
0
  }
72
4.24k
  *file_system = memory_allocate_structure(
73
4.24k
                  libfsxfs_file_system_t );
74
75
4.24k
  if( *file_system == NULL )
76
0
  {
77
0
    libcerror_error_set(
78
0
     error,
79
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
80
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
81
0
     "%s: unable to create file system.",
82
0
     function );
83
84
0
    goto on_error;
85
0
  }
86
4.24k
  if( memory_set(
87
4.24k
       *file_system,
88
4.24k
       0,
89
4.24k
       sizeof( libfsxfs_file_system_t ) ) == NULL )
90
0
  {
91
0
    libcerror_error_set(
92
0
     error,
93
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
94
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
95
0
     "%s: unable to clear file system.",
96
0
     function );
97
98
0
    memory_free(
99
0
     *file_system );
100
101
0
    *file_system = NULL;
102
103
0
    return( -1 );
104
0
  }
105
4.24k
  if( libfsxfs_inode_btree_initialize(
106
4.24k
       &( ( *file_system )->inode_btree ),
107
4.24k
       error ) != 1 )
108
0
  {
109
0
    libcerror_error_set(
110
0
     error,
111
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
112
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
113
0
     "%s: unable to create inode B+ tree.",
114
0
     function );
115
116
0
    goto on_error;
117
0
  }
118
4.24k
#if defined( HAVE_LIBFSXFS_MULTI_THREAD_SUPPORT )
119
4.24k
  if( libcthreads_read_write_lock_initialize(
120
4.24k
       &( ( *file_system )->read_write_lock ),
121
4.24k
       error ) != 1 )
122
0
  {
123
0
    libcerror_error_set(
124
0
     error,
125
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
126
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
127
0
     "%s: unable to initialize read/write lock.",
128
0
     function );
129
130
0
    goto on_error;
131
0
  }
132
4.24k
#endif
133
4.24k
  ( *file_system )->root_directory_inode_number = root_directory_inode_number;
134
135
4.24k
  return( 1 );
136
137
0
on_error:
138
0
  if( *file_system != NULL )
139
0
  {
140
0
    if( ( *file_system )->inode_btree != NULL )
141
0
    {
142
0
      libfsxfs_inode_btree_free(
143
0
       &( ( *file_system )->inode_btree ),
144
0
       NULL );
145
0
    }
146
0
    memory_free(
147
0
     *file_system );
148
149
0
    *file_system = NULL;
150
0
  }
151
0
  return( -1 );
152
4.24k
}
153
154
/* Frees a file system
155
 * Returns 1 if successful or -1 on error
156
 */
157
int libfsxfs_file_system_free(
158
     libfsxfs_file_system_t **file_system,
159
     libcerror_error_t **error )
160
4.24k
{
161
4.24k
  static char *function = "libfsxfs_file_system_free";
162
4.24k
  int result            = 1;
163
164
4.24k
  if( file_system == NULL )
165
0
  {
166
0
    libcerror_error_set(
167
0
     error,
168
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
169
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
170
0
     "%s: invalid file system.",
171
0
     function );
172
173
0
    return( -1 );
174
0
  }
175
4.24k
  if( *file_system != NULL )
176
4.24k
  {
177
4.24k
#if defined( HAVE_LIBFSXFS_MULTI_THREAD_SUPPORT )
178
4.24k
    if( libcthreads_read_write_lock_free(
179
4.24k
         &( ( *file_system )->read_write_lock ),
180
4.24k
         error ) != 1 )
181
0
    {
182
0
      libcerror_error_set(
183
0
       error,
184
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
185
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
186
0
       "%s: unable to free read/write lock.",
187
0
       function );
188
189
0
      result = -1;
190
0
    }
191
4.24k
#endif
192
4.24k
    if( libfsxfs_inode_btree_free(
193
4.24k
         &( ( *file_system )->inode_btree ),
194
4.24k
         error ) != 1 )
195
0
    {
196
0
      libcerror_error_set(
197
0
       error,
198
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
199
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
200
0
       "%s: unable to free inode B+ tree.",
201
0
       function );
202
203
0
      result = -1;
204
0
    }
205
4.24k
    memory_free(
206
4.24k
     *file_system );
207
208
4.24k
    *file_system = NULL;
209
4.24k
  }
210
4.24k
  return( result );
211
4.24k
}
212
213
/* Reads the inode information
214
 * Returns 1 if successful or -1 on error
215
 */
216
int libfsxfs_file_system_read_inode_information(
217
     libfsxfs_file_system_t *file_system,
218
     libfsxfs_io_handle_t *io_handle,
219
     libbfio_handle_t *file_io_handle,
220
     off64_t file_offset,
221
     libcerror_error_t **error )
222
15.6k
{
223
15.6k
  static char *function = "libfsxfs_file_system_read_inode_information";
224
225
15.6k
  if( file_system == NULL )
226
0
  {
227
0
    libcerror_error_set(
228
0
     error,
229
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
230
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
231
0
     "%s: invalid file system.",
232
0
     function );
233
234
0
    return( -1 );
235
0
  }
236
15.6k
  if( libfsxfs_inode_btree_read_inode_information(
237
15.6k
       file_system->inode_btree,
238
15.6k
       io_handle,
239
15.6k
       file_io_handle,
240
15.6k
       file_offset,
241
15.6k
       error ) != 1 )
242
9.03k
  {
243
9.03k
    libcerror_error_set(
244
9.03k
     error,
245
9.03k
     LIBCERROR_ERROR_DOMAIN_IO,
246
9.03k
     LIBCERROR_IO_ERROR_READ_FAILED,
247
9.03k
     "%s: unable to read inode information at offset: %" PRIi64 " (0x%08" PRIx64 ").",
248
9.03k
     function,
249
9.03k
     file_offset,
250
9.03k
     file_offset );
251
252
9.03k
    return( 1 );
253
9.03k
  }
254
6.61k
  return( 1 );
255
15.6k
}
256
257
/* Retrieves a specific inode
258
 * Returns 1 if successful, 0 if no such value or -1 on error
259
 */
260
int libfsxfs_file_system_get_inode_by_number(
261
     libfsxfs_file_system_t *file_system,
262
     libfsxfs_io_handle_t *io_handle,
263
     libbfio_handle_t *file_io_handle,
264
     uint64_t inode_number,
265
     libfsxfs_inode_t **inode,
266
     libcerror_error_t **error )
267
4.16k
{
268
4.16k
  libfsxfs_inode_t *safe_inode = NULL;
269
4.16k
  static char *function        = "libfsxfs_file_system_get_inode_by_number";
270
4.16k
  off64_t file_offset          = 0;
271
4.16k
  int result                   = 0;
272
273
4.16k
  if( file_system == NULL )
274
0
  {
275
0
    libcerror_error_set(
276
0
     error,
277
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
278
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
279
0
     "%s: invalid file system.",
280
0
     function );
281
282
0
    return( -1 );
283
0
  }
284
4.16k
  if( io_handle == NULL )
285
0
  {
286
0
    libcerror_error_set(
287
0
     error,
288
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
289
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
290
0
     "%s: invalid IO handle.",
291
0
     function );
292
293
0
    return( -1 );
294
0
  }
295
4.16k
  if( io_handle->inode_size == 0 )
296
0
  {
297
0
    libcerror_error_set(
298
0
     error,
299
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
300
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
301
0
     "%s: invalid IO handle - inode size value out of bounds.",
302
0
     function );
303
304
0
    return( -1 );
305
0
  }
306
4.16k
  if( ( inode_number == 0 )
307
4.16k
   || ( inode_number > (uint64_t) UINT32_MAX ) )
308
198
  {
309
198
    libcerror_error_set(
310
198
     error,
311
198
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
312
198
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
313
198
     "%s: invalid inode number value out of bounds.",
314
198
     function );
315
316
198
    return( -1 );
317
198
  }
318
3.97k
  result = libfsxfs_inode_btree_get_inode_by_number(
319
3.97k
            file_system->inode_btree,
320
3.97k
            io_handle,
321
3.97k
            file_io_handle,
322
3.97k
            inode_number,
323
3.97k
            &file_offset,
324
3.97k
            error );
325
326
3.97k
  if( result == -1 )
327
584
  {
328
584
    libcerror_error_set(
329
584
     error,
330
584
     LIBCERROR_ERROR_DOMAIN_IO,
331
584
     LIBCERROR_IO_ERROR_READ_FAILED,
332
584
     "%s: unable to retrieve inode: %" PRIu64 "\n",
333
584
     function,
334
584
     inode_number );
335
336
584
    goto on_error;
337
584
  }
338
3.38k
  else if( result != 0 )
339
3.27k
  {
340
3.27k
    if( libfsxfs_inode_initialize(
341
3.27k
         &safe_inode,
342
3.27k
         io_handle->inode_size,
343
3.27k
         error ) != 1 )
344
61
    {
345
61
      libcerror_error_set(
346
61
       error,
347
61
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
348
61
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
349
61
       "%s: unable to create inode.",
350
61
       function );
351
352
61
      goto on_error;
353
61
    }
354
#if defined( HAVE_DEBUG_OUTPUT )
355
    if( libcnotify_verbose != 0 )
356
    {
357
      libcnotify_printf(
358
       "Reading inode: %" PRIu64 " at offset: %" PRIi64 " (0x%08" PRIx64 ").\n",
359
       inode_number,
360
       file_offset,
361
       file_offset );
362
    }
363
#endif
364
3.21k
    if( libfsxfs_inode_read_file_io_handle(
365
3.21k
         safe_inode,
366
3.21k
         io_handle,
367
3.21k
         file_io_handle,
368
3.21k
         file_offset,
369
3.21k
         error ) != 1 )
370
732
    {
371
732
      libcerror_error_set(
372
732
       error,
373
732
       LIBCERROR_ERROR_DOMAIN_IO,
374
732
       LIBCERROR_IO_ERROR_READ_FAILED,
375
732
       "%s: unable to read inode: %" PRIu64 " at offset: %" PRIi64 " (0x%08" PRIx64 ").",
376
732
       function,
377
732
       inode_number,
378
732
       file_offset,
379
732
       file_offset );
380
381
732
      goto on_error;
382
732
    }
383
2.48k
    *inode = safe_inode;
384
2.48k
  }
385
2.59k
  return( result );
386
387
1.37k
on_error:
388
1.37k
  if( safe_inode != NULL )
389
732
  {
390
732
    libfsxfs_inode_free(
391
732
     &safe_inode,
392
732
     NULL );
393
732
  }
394
1.37k
  return( -1 );
395
3.97k
}
396
397
/* Retrieves a directory entry for a specific UTF-8 formatted path
398
 * Returns 1 if successful, 0 if not found or -1 on error
399
 */
400
int libfsxfs_file_system_get_directory_entry_by_utf8_path(
401
     libfsxfs_file_system_t *file_system,
402
     libfsxfs_io_handle_t *io_handle,
403
     libbfio_handle_t *file_io_handle,
404
     const uint8_t *utf8_string,
405
     size_t utf8_string_length,
406
     uint64_t *inode_number,
407
     libfsxfs_inode_t **inode,
408
     libfsxfs_directory_entry_t **directory_entry,
409
     libcerror_error_t **error )
410
1.67k
{
411
1.67k
  libfsxfs_directory_t *directory                  = NULL;
412
1.67k
  libfsxfs_directory_entry_t *safe_directory_entry = NULL;
413
1.67k
  libfsxfs_inode_t *safe_inode                     = NULL;
414
1.67k
  const uint8_t *utf8_string_segment               = NULL;
415
1.67k
  static char *function                            = "libfsxfs_file_system_get_directory_entry_by_utf8_path";
416
1.67k
  libuna_unicode_character_t unicode_character     = 0;
417
1.67k
  size_t utf8_string_index                         = 0;
418
1.67k
  size_t utf8_string_segment_length                = 0;
419
1.67k
  uint64_t safe_inode_number                       = 0;
420
1.67k
  int result                                       = 0;
421
422
1.67k
  if( file_system == NULL )
423
0
  {
424
0
    libcerror_error_set(
425
0
     error,
426
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
427
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
428
0
     "%s: invalid file system.",
429
0
     function );
430
431
0
    return( -1 );
432
0
  }
433
1.67k
  if( utf8_string == NULL )
434
0
  {
435
0
    libcerror_error_set(
436
0
     error,
437
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
438
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
439
0
     "%s: invalid UTF-8 string.",
440
0
     function );
441
442
0
    return( -1 );
443
0
  }
444
1.67k
  if( utf8_string_length > (size_t) SSIZE_MAX )
445
0
  {
446
0
    libcerror_error_set(
447
0
     error,
448
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
449
0
     LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
450
0
     "%s: invalid UTF-8 string length value exceeds maximum.",
451
0
     function );
452
453
0
    return( -1 );
454
0
  }
455
1.67k
  if( inode == NULL )
456
0
  {
457
0
    libcerror_error_set(
458
0
     error,
459
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
460
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
461
0
     "%s: invalid inode.",
462
0
     function );
463
464
0
    return( -1 );
465
0
  }
466
1.67k
  if( directory_entry == NULL )
467
0
  {
468
0
    libcerror_error_set(
469
0
     error,
470
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
471
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
472
0
     "%s: invalid directory entry.",
473
0
     function );
474
475
0
    return( -1 );
476
0
  }
477
1.67k
  if( utf8_string_length > 0 )
478
1.67k
  {
479
    /* Ignore a leading separator
480
     */
481
1.67k
    if( utf8_string[ utf8_string_index ] == (uint8_t) LIBFSXFS_SEPARATOR )
482
1.67k
    {
483
1.67k
      utf8_string_index++;
484
1.67k
    }
485
1.67k
  }
486
1.67k
  safe_inode_number = file_system->root_directory_inode_number;
487
488
1.67k
  if( libfsxfs_file_system_get_inode_by_number(
489
1.67k
       file_system,
490
1.67k
       io_handle,
491
1.67k
       file_io_handle,
492
1.67k
       safe_inode_number,
493
1.67k
       &safe_inode,
494
1.67k
       error ) != 1 )
495
914
  {
496
914
    libcerror_error_set(
497
914
     error,
498
914
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
499
914
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
500
914
     "%s: unable to retrieve inode: %" PRIu64 ".",
501
914
     function,
502
914
     safe_inode_number );
503
504
914
    goto on_error;
505
914
  }
506
756
  if( ( utf8_string_length == 0 )
507
756
   || ( utf8_string_length == 1 ) )
508
0
  {
509
0
    result = 1;
510
0
  }
511
800
  else while( utf8_string_index < utf8_string_length )
512
800
  {
513
800
    if( directory != NULL )
514
44
    {
515
44
      if( libfsxfs_directory_free(
516
44
           &directory,
517
44
           error ) != 1 )
518
0
      {
519
0
        libcerror_error_set(
520
0
         error,
521
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
522
0
         LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
523
0
         "%s: unable to free directory.",
524
0
         function );
525
526
0
        goto on_error;
527
0
      }
528
44
    }
529
800
    if( libfsxfs_directory_initialize(
530
800
         &directory,
531
800
         error ) != 1 )
532
0
    {
533
0
      libcerror_error_set(
534
0
       error,
535
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
536
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
537
0
       "%s: unable to create directory.",
538
0
       function );
539
540
0
      goto on_error;
541
0
    }
542
800
    if( libfsxfs_directory_read_file_io_handle(
543
800
         directory,
544
800
         io_handle,
545
800
         file_io_handle,
546
800
         safe_inode,
547
800
         error ) != 1 )
548
419
    {
549
419
      libcerror_error_set(
550
419
       error,
551
419
       LIBCERROR_ERROR_DOMAIN_IO,
552
419
       LIBCERROR_IO_ERROR_READ_FAILED,
553
419
       "%s: unable to read directory from inode: %" PRIu64 ".",
554
419
       function,
555
419
       safe_inode_number );
556
557
419
      goto on_error;
558
419
    }
559
381
    utf8_string_segment        = &( utf8_string[ utf8_string_index ] );
560
381
    utf8_string_segment_length = utf8_string_index;
561
562
4.35k
    while( utf8_string_index < utf8_string_length )
563
4.31k
    {
564
4.31k
      if( libuna_unicode_character_copy_from_utf8(
565
4.31k
           &unicode_character,
566
4.31k
           utf8_string,
567
4.31k
           utf8_string_length,
568
4.31k
           &utf8_string_index,
569
4.31k
           error ) != 1 )
570
0
      {
571
0
        libcerror_error_set(
572
0
         error,
573
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
574
0
         LIBCERROR_RUNTIME_ERROR_COPY_FAILED,
575
0
         "%s: unable to copy UTF-8 string to Unicode character.",
576
0
         function );
577
578
0
        goto on_error;
579
0
      }
580
4.31k
      if( ( unicode_character == (libuna_unicode_character_t) LIBFSXFS_SEPARATOR )
581
3.97k
       || ( unicode_character == 0 ) )
582
338
      {
583
338
        utf8_string_segment_length += 1;
584
585
338
        break;
586
338
      }
587
4.31k
    }
588
381
    utf8_string_segment_length = utf8_string_index - utf8_string_segment_length;
589
590
381
    if( utf8_string_segment_length == 0 )
591
0
    {
592
0
      result = 0;
593
0
    }
594
381
    else
595
381
    {
596
381
      result = libfsxfs_directory_get_entry_by_utf8_name(
597
381
                directory,
598
381
                utf8_string_segment,
599
381
                utf8_string_segment_length,
600
381
                &safe_directory_entry,
601
381
                error );
602
381
    }
603
381
    if( result == -1 )
604
146
    {
605
146
      libcerror_error_set(
606
146
       error,
607
146
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
608
146
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
609
146
       "%s: unable to retrieve directory entry by UTF-8 name.",
610
146
       function );
611
612
146
      goto on_error;
613
146
    }
614
235
    else if( result == 0 )
615
185
    {
616
185
      break;
617
185
    }
618
50
    if( libfsxfs_directory_entry_get_inode_number(
619
50
         safe_directory_entry,
620
50
         &safe_inode_number,
621
50
         error ) != 1 )
622
0
    {
623
0
      libcerror_error_set(
624
0
       error,
625
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
626
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
627
0
       "%s: unable to retrieve inode number from directory entry.",
628
0
       function );
629
630
0
      goto on_error;
631
0
    }
632
50
    if( safe_inode != NULL )
633
50
    {
634
50
      if( libfsxfs_inode_free(
635
50
           &safe_inode,
636
50
           error ) != 1 )
637
0
      {
638
0
        libcerror_error_set(
639
0
         error,
640
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
641
0
         LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
642
0
         "%s: unable to free inode.",
643
0
         function );
644
645
0
        goto on_error;
646
0
      }
647
50
    }
648
50
    if( libfsxfs_file_system_get_inode_by_number(
649
50
         file_system,
650
50
         io_handle,
651
50
         file_io_handle,
652
50
         safe_inode_number,
653
50
         &safe_inode,
654
50
         error ) != 1 )
655
6
    {
656
6
      libcerror_error_set(
657
6
       error,
658
6
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
659
6
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
660
6
       "%s: unable to retrieve inode: %" PRIu32 ".",
661
6
       function,
662
6
       safe_inode_number );
663
664
6
      goto on_error;
665
6
    }
666
50
  }
667
185
  if( result == 0 )
668
185
  {
669
185
    if( safe_inode != NULL )
670
185
    {
671
185
      if( libfsxfs_inode_free(
672
185
           &safe_inode,
673
185
           error ) != 1 )
674
0
      {
675
0
        libcerror_error_set(
676
0
         error,
677
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
678
0
         LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
679
0
         "%s: unable to free inode.",
680
0
         function );
681
682
0
        goto on_error;
683
0
      }
684
185
    }
685
185
  }
686
0
  else
687
0
  {
688
0
    if( libfsxfs_directory_entry_clone(
689
0
         directory_entry,
690
0
         safe_directory_entry,
691
0
         error ) != 1 )
692
0
    {
693
0
      libcerror_error_set(
694
0
       error,
695
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
696
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
697
0
       "%s: unable to create directory entry.",
698
0
       function );
699
700
0
      goto on_error;
701
0
    }
702
0
  }
703
  /* Directory needs to be freed after making a clone of directory_entry
704
   */
705
185
  if( directory != NULL )
706
185
  {
707
185
    if( libfsxfs_directory_free(
708
185
         &directory,
709
185
         error ) != 1 )
710
0
    {
711
0
      libcerror_error_set(
712
0
       error,
713
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
714
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
715
0
       "%s: unable to free directory.",
716
0
       function );
717
718
0
      goto on_error;
719
0
    }
720
185
  }
721
185
  *inode_number = safe_inode_number;
722
185
  *inode        = safe_inode;
723
724
185
  return( result );
725
726
1.48k
on_error:
727
1.48k
  if( directory != NULL )
728
571
  {
729
571
    libfsxfs_directory_free(
730
571
     &directory,
731
571
     NULL );
732
571
  }
733
1.48k
  if( safe_inode != NULL )
734
565
  {
735
565
    libfsxfs_inode_free(
736
565
     &safe_inode,
737
565
     NULL );
738
565
  }
739
1.48k
  if( *directory_entry != NULL )
740
0
  {
741
0
    libfsxfs_directory_entry_free(
742
0
     directory_entry,
743
0
     NULL );
744
0
  }
745
1.48k
  return( -1 );
746
185
}
747
748
/* Retrieves a directory entry for a specific UTF-16 formatted path
749
 * Returns 1 if successful, 0 if not found or -1 on error
750
 */
751
int libfsxfs_file_system_get_directory_entry_by_utf16_path(
752
     libfsxfs_file_system_t *file_system,
753
     libfsxfs_io_handle_t *io_handle,
754
     libbfio_handle_t *file_io_handle,
755
     const uint16_t *utf16_string,
756
     size_t utf16_string_length,
757
     uint64_t *inode_number,
758
     libfsxfs_inode_t **inode,
759
     libfsxfs_directory_entry_t **directory_entry,
760
     libcerror_error_t **error )
761
0
{
762
0
  libfsxfs_directory_t *directory                  = NULL;
763
0
  libfsxfs_directory_entry_t *safe_directory_entry = NULL;
764
0
  libfsxfs_inode_t *safe_inode                     = NULL;
765
0
  const uint16_t *utf16_string_segment             = NULL;
766
0
  static char *function                            = "libfsxfs_file_system_get_directory_entry_by_utf16_path";
767
0
  libuna_unicode_character_t unicode_character     = 0;
768
0
  size_t utf16_string_index                        = 0;
769
0
  size_t utf16_string_segment_length               = 0;
770
0
  uint64_t safe_inode_number                       = 0;
771
0
  int result                                       = 0;
772
773
0
  if( file_system == NULL )
774
0
  {
775
0
    libcerror_error_set(
776
0
     error,
777
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
778
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
779
0
     "%s: invalid file system.",
780
0
     function );
781
782
0
    return( -1 );
783
0
  }
784
0
  if( utf16_string == NULL )
785
0
  {
786
0
    libcerror_error_set(
787
0
     error,
788
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
789
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
790
0
     "%s: invalid UTF-16 string.",
791
0
     function );
792
793
0
    return( -1 );
794
0
  }
795
0
  if( utf16_string_length > (size_t) SSIZE_MAX )
796
0
  {
797
0
    libcerror_error_set(
798
0
     error,
799
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
800
0
     LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
801
0
     "%s: invalid UTF-16 string length value exceeds maximum.",
802
0
     function );
803
804
0
    return( -1 );
805
0
  }
806
0
  if( inode == NULL )
807
0
  {
808
0
    libcerror_error_set(
809
0
     error,
810
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
811
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
812
0
     "%s: invalid inode.",
813
0
     function );
814
815
0
    return( -1 );
816
0
  }
817
0
  if( directory_entry == NULL )
818
0
  {
819
0
    libcerror_error_set(
820
0
     error,
821
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
822
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
823
0
     "%s: invalid directory entry.",
824
0
     function );
825
826
0
    return( -1 );
827
0
  }
828
0
  if( utf16_string_length > 0 )
829
0
  {
830
    /* Ignore a leading separator
831
     */
832
0
    if( utf16_string[ utf16_string_index ] == (uint16_t) LIBFSXFS_SEPARATOR )
833
0
    {
834
0
      utf16_string_index++;
835
0
    }
836
0
  }
837
0
  safe_inode_number = file_system->root_directory_inode_number;
838
839
0
  if( libfsxfs_file_system_get_inode_by_number(
840
0
       file_system,
841
0
       io_handle,
842
0
       file_io_handle,
843
0
       safe_inode_number,
844
0
       &safe_inode,
845
0
       error ) != 1 )
846
0
  {
847
0
    libcerror_error_set(
848
0
     error,
849
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
850
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
851
0
     "%s: unable to retrieve inode: %" PRIu64 ".",
852
0
     function,
853
0
     safe_inode_number );
854
855
0
    goto on_error;
856
0
  }
857
0
  if( ( utf16_string_length == 0 )
858
0
   || ( utf16_string_length == 1 ) )
859
0
  {
860
0
    result = 1;
861
0
  }
862
0
  else while( utf16_string_index < utf16_string_length )
863
0
  {
864
0
    if( directory != NULL )
865
0
    {
866
0
      if( libfsxfs_directory_free(
867
0
           &directory,
868
0
           error ) != 1 )
869
0
      {
870
0
        libcerror_error_set(
871
0
         error,
872
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
873
0
         LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
874
0
         "%s: unable to free directory.",
875
0
         function );
876
877
0
        goto on_error;
878
0
      }
879
0
    }
880
0
    if( libfsxfs_directory_initialize(
881
0
         &directory,
882
0
         error ) != 1 )
883
0
    {
884
0
      libcerror_error_set(
885
0
       error,
886
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
887
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
888
0
       "%s: unable to create directory.",
889
0
       function );
890
891
0
      goto on_error;
892
0
    }
893
0
    if( libfsxfs_directory_read_file_io_handle(
894
0
         directory,
895
0
         io_handle,
896
0
         file_io_handle,
897
0
         safe_inode,
898
0
         error ) != 1 )
899
0
    {
900
0
      libcerror_error_set(
901
0
       error,
902
0
       LIBCERROR_ERROR_DOMAIN_IO,
903
0
       LIBCERROR_IO_ERROR_READ_FAILED,
904
0
       "%s: unable to read directory from inode: %" PRIu64 ".",
905
0
       function,
906
0
       safe_inode_number );
907
908
0
      goto on_error;
909
0
    }
910
0
    utf16_string_segment        = &( utf16_string[ utf16_string_index ] );
911
0
    utf16_string_segment_length = utf16_string_index;
912
913
0
    while( utf16_string_index < utf16_string_length )
914
0
    {
915
0
      if( libuna_unicode_character_copy_from_utf16(
916
0
           &unicode_character,
917
0
           utf16_string,
918
0
           utf16_string_length,
919
0
           &utf16_string_index,
920
0
           error ) != 1 )
921
0
      {
922
0
        libcerror_error_set(
923
0
         error,
924
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
925
0
         LIBCERROR_RUNTIME_ERROR_COPY_FAILED,
926
0
         "%s: unable to copy UTF-16 string to Unicode character.",
927
0
         function );
928
929
0
        goto on_error;
930
0
      }
931
0
      if( ( unicode_character == (libuna_unicode_character_t) LIBFSXFS_SEPARATOR )
932
0
       || ( unicode_character == 0 ) )
933
0
      {
934
0
        utf16_string_segment_length += 1;
935
936
0
        break;
937
0
      }
938
0
    }
939
0
    utf16_string_segment_length = utf16_string_index - utf16_string_segment_length;
940
941
0
    if( utf16_string_segment_length == 0 )
942
0
    {
943
0
      result = 0;
944
0
    }
945
0
    else
946
0
    {
947
0
      result = libfsxfs_directory_get_entry_by_utf16_name(
948
0
                directory,
949
0
                utf16_string_segment,
950
0
                utf16_string_segment_length,
951
0
                &safe_directory_entry,
952
0
                error );
953
0
    }
954
0
    if( result == -1 )
955
0
    {
956
0
      libcerror_error_set(
957
0
       error,
958
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
959
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
960
0
       "%s: unable to retrieve directory entry by UTF-16 name.",
961
0
       function );
962
963
0
      goto on_error;
964
0
    }
965
0
    else if( result == 0 )
966
0
    {
967
0
      break;
968
0
    }
969
0
    if( libfsxfs_directory_entry_get_inode_number(
970
0
         safe_directory_entry,
971
0
         &safe_inode_number,
972
0
         error ) != 1 )
973
0
    {
974
0
      libcerror_error_set(
975
0
       error,
976
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
977
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
978
0
       "%s: unable to retrieve inode number from directory entry.",
979
0
       function );
980
981
0
      goto on_error;
982
0
    }
983
0
    if( safe_inode != NULL )
984
0
    {
985
0
      if( libfsxfs_inode_free(
986
0
           &safe_inode,
987
0
           error ) != 1 )
988
0
      {
989
0
        libcerror_error_set(
990
0
         error,
991
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
992
0
         LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
993
0
         "%s: unable to free inode.",
994
0
         function );
995
996
0
        goto on_error;
997
0
      }
998
0
    }
999
0
    if( libfsxfs_file_system_get_inode_by_number(
1000
0
         file_system,
1001
0
         io_handle,
1002
0
         file_io_handle,
1003
0
         safe_inode_number,
1004
0
         &safe_inode,
1005
0
         error ) != 1 )
1006
0
    {
1007
0
      libcerror_error_set(
1008
0
       error,
1009
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1010
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1011
0
       "%s: unable to retrieve inode: %" PRIu32 ".",
1012
0
       function,
1013
0
       safe_inode_number );
1014
1015
0
      goto on_error;
1016
0
    }
1017
0
  }
1018
0
  if( result == 0 )
1019
0
  {
1020
0
    if( safe_inode != NULL )
1021
0
    {
1022
0
      if( libfsxfs_inode_free(
1023
0
           &safe_inode,
1024
0
           error ) != 1 )
1025
0
      {
1026
0
        libcerror_error_set(
1027
0
         error,
1028
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
1029
0
         LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
1030
0
         "%s: unable to free inode.",
1031
0
         function );
1032
1033
0
        goto on_error;
1034
0
      }
1035
0
    }
1036
0
  }
1037
0
  else
1038
0
  {
1039
0
    if( libfsxfs_directory_entry_clone(
1040
0
         directory_entry,
1041
0
         safe_directory_entry,
1042
0
         error ) != 1 )
1043
0
    {
1044
0
      libcerror_error_set(
1045
0
       error,
1046
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1047
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1048
0
       "%s: unable to create directory entry.",
1049
0
       function );
1050
1051
0
      goto on_error;
1052
0
    }
1053
0
  }
1054
  /* Directory needs to be freed after making a clone of directory_entry
1055
   */
1056
0
  if( directory != NULL )
1057
0
  {
1058
0
    if( libfsxfs_directory_free(
1059
0
         &directory,
1060
0
         error ) != 1 )
1061
0
    {
1062
0
      libcerror_error_set(
1063
0
       error,
1064
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1065
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
1066
0
       "%s: unable to free directory.",
1067
0
       function );
1068
1069
0
      goto on_error;
1070
0
    }
1071
0
  }
1072
0
  *inode_number = safe_inode_number;
1073
0
  *inode        = safe_inode;
1074
1075
0
  return( result );
1076
1077
0
on_error:
1078
0
  if( directory != NULL )
1079
0
  {
1080
0
    libfsxfs_directory_free(
1081
0
     &directory,
1082
0
     NULL );
1083
0
  }
1084
0
  if( safe_inode != NULL )
1085
0
  {
1086
0
    libfsxfs_inode_free(
1087
0
     &safe_inode,
1088
0
     NULL );
1089
0
  }
1090
0
  if( *directory_entry != NULL )
1091
0
  {
1092
0
    libfsxfs_directory_entry_free(
1093
0
     directory_entry,
1094
     NULL );
1095
0
  }
1096
0
  return( -1 );
1097
0
}
1098