Coverage Report

Created: 2026-01-13 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libfsapfs/libfsapfs/libfsapfs_file_system.c
Line
Count
Source
1
/*
2
 * The file system functions
3
 *
4
 * Copyright (C) 2018-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 "libfsapfs_directory_record.h"
27
#include "libfsapfs_encryption_context.h"
28
#include "libfsapfs_file_entry.h"
29
#include "libfsapfs_file_system.h"
30
#include "libfsapfs_file_system_btree.h"
31
#include "libfsapfs_io_handle.h"
32
#include "libfsapfs_libbfio.h"
33
#include "libfsapfs_libcerror.h"
34
#include "libfsapfs_libcthreads.h"
35
#include "libfsapfs_types.h"
36
37
/* Creates file system
38
 * Make sure the value file_system is referencing, is set to NULL
39
 * Returns 1 if successful or -1 on error
40
 */
41
int libfsapfs_file_system_initialize(
42
     libfsapfs_file_system_t **file_system,
43
     libfsapfs_io_handle_t *io_handle,
44
     libfsapfs_encryption_context_t *encryption_context,
45
     libfsapfs_file_system_btree_t *file_system_btree,
46
     libcerror_error_t **error )
47
1.32k
{
48
1.32k
  static char *function = "libfsapfs_file_system_initialize";
49
50
1.32k
  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
1.32k
  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
1.32k
  *file_system = memory_allocate_structure(
73
1.32k
                  libfsapfs_file_system_t );
74
75
1.32k
  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
1.32k
  if( memory_set(
87
1.32k
       *file_system,
88
1.32k
       0,
89
1.32k
       sizeof( libfsapfs_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
1.32k
#if defined( HAVE_MULTI_THREAD_SUPPORT ) && !defined( HAVE_LOCAL_LIBFSAPFS )
106
1.32k
  if( libcthreads_read_write_lock_initialize(
107
1.32k
       &( ( *file_system )->read_write_lock ),
108
1.32k
       error ) != 1 )
109
0
  {
110
0
    libcerror_error_set(
111
0
     error,
112
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
113
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
114
0
     "%s: unable to initialize read/write lock.",
115
0
     function );
116
117
0
    goto on_error;
118
0
  }
119
1.32k
#endif
120
1.32k
  ( *file_system )->io_handle          = io_handle;
121
1.32k
  ( *file_system )->encryption_context = encryption_context;
122
1.32k
  ( *file_system )->file_system_btree  = file_system_btree;
123
124
1.32k
  return( 1 );
125
126
0
on_error:
127
0
  if( *file_system != NULL )
128
0
  {
129
0
    memory_free(
130
0
     *file_system );
131
132
0
    *file_system = NULL;
133
0
  }
134
0
  return( -1 );
135
1.32k
}
136
137
/* Frees file system
138
 * Returns 1 if successful or -1 on error
139
 */
140
int libfsapfs_file_system_free(
141
     libfsapfs_file_system_t **file_system,
142
     libcerror_error_t **error )
143
1.32k
{
144
1.32k
  static char *function = "libfsapfs_file_system_free";
145
1.32k
  int result            = 1;
146
147
1.32k
  if( file_system == NULL )
148
0
  {
149
0
    libcerror_error_set(
150
0
     error,
151
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
152
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
153
0
     "%s: invalid file system.",
154
0
     function );
155
156
0
    return( -1 );
157
0
  }
158
1.32k
  if( *file_system != NULL )
159
1.32k
  {
160
1.32k
    if( ( *file_system )->file_system_btree != NULL )
161
1.32k
    {
162
1.32k
      if( libfsapfs_file_system_btree_free(
163
1.32k
           &( ( *file_system )->file_system_btree ),
164
1.32k
           error ) != 1 )
165
0
      {
166
0
        libcerror_error_set(
167
0
         error,
168
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
169
0
         LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
170
0
         "%s: unable to free file system B-tree.",
171
0
         function );
172
173
0
        result = -1;
174
0
      }
175
1.32k
    }
176
1.32k
#if defined( HAVE_MULTI_THREAD_SUPPORT ) && !defined( HAVE_LOCAL_LIBFSAPFS )
177
1.32k
    if( libcthreads_read_write_lock_free(
178
1.32k
         &( ( *file_system )->read_write_lock ),
179
1.32k
         error ) != 1 )
180
0
    {
181
0
      libcerror_error_set(
182
0
       error,
183
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
184
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
185
0
       "%s: unable to free read/write lock.",
186
0
       function );
187
188
0
      result = -1;
189
0
    }
190
1.32k
#endif
191
1.32k
    memory_free(
192
1.32k
     *file_system );
193
194
1.32k
    *file_system = NULL;
195
1.32k
  }
196
1.32k
  return( result );
197
1.32k
}
198
199
/* Retrieves a file entry for a specific identifier from the file system B-tree
200
 * Returns 1 if successful, 0 if not found or -1 on error
201
 */
202
int libfsapfs_file_system_get_file_entry_by_identifier(
203
     libfsapfs_file_system_t *file_system,
204
     libbfio_handle_t *file_io_handle,
205
     uint64_t identifier,
206
     uint64_t transaction_identifier,
207
     libfsapfs_file_entry_t **file_entry,
208
     libcerror_error_t **error )
209
1.32k
{
210
1.32k
  libfsapfs_inode_t *inode = NULL;
211
1.32k
  static char *function    = "libfsapfs_file_system_get_file_entry_by_identifier";
212
1.32k
  int result               = 0;
213
214
1.32k
  if( file_system == NULL )
215
0
  {
216
0
    libcerror_error_set(
217
0
     error,
218
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
219
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
220
0
     "%s: invalid file system.",
221
0
     function );
222
223
0
    return( -1 );
224
0
  }
225
1.32k
  if( file_entry == 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 entry.",
232
0
     function );
233
234
0
    return( -1 );
235
0
  }
236
1.32k
  if( *file_entry != NULL )
237
0
  {
238
0
    libcerror_error_set(
239
0
     error,
240
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
241
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
242
0
     "%s: invalid file entry value already set.",
243
0
     function );
244
245
0
    return( -1 );
246
0
  }
247
1.32k
  result = libfsapfs_file_system_btree_get_inode_by_identifier(
248
1.32k
            file_system->file_system_btree,
249
1.32k
            file_io_handle,
250
1.32k
            identifier,
251
1.32k
            transaction_identifier,
252
1.32k
            &inode,
253
1.32k
            error );
254
255
1.32k
  if( result == -1 )
256
474
  {
257
474
    libcerror_error_set(
258
474
     error,
259
474
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
260
474
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
261
474
     "%s: unable to retrieve inode: %" PRIu64 " from file system B-tree.",
262
474
     function,
263
474
     identifier );
264
265
474
    goto on_error;
266
474
  }
267
848
  else if( result != 0 )
268
806
  {
269
806
    if( libfsapfs_file_entry_initialize(
270
806
         file_entry,
271
806
         file_system->io_handle,
272
806
         file_io_handle,
273
806
         file_system->encryption_context,
274
806
         file_system->file_system_btree,
275
806
         inode,
276
806
         NULL,
277
806
         transaction_identifier,
278
806
         error ) != 1 )
279
0
    {
280
0
      libcerror_error_set(
281
0
       error,
282
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
283
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
284
0
       "%s: unable to create file entry.",
285
0
       function );
286
287
0
      goto on_error;
288
0
    }
289
806
  }
290
848
  return( result );
291
292
474
on_error:
293
474
  if( inode != NULL )
294
0
  {
295
0
    libfsapfs_inode_free(
296
0
     &inode,
297
0
     NULL );
298
0
  }
299
474
  return( -1 );
300
1.32k
}
301
302
/* Retrieves a file entry for an UTF-8 encoded path from the file system
303
 * Returns 1 if successful, 0 if not found or -1 on error
304
 */
305
int libfsapfs_file_system_get_file_entry_by_utf8_path(
306
     libfsapfs_file_system_t *file_system,
307
     libbfio_handle_t *file_io_handle,
308
     const uint8_t *utf8_string,
309
     size_t utf8_string_length,
310
     uint64_t transaction_identifier,
311
     libfsapfs_file_entry_t **file_entry,
312
     libcerror_error_t **error )
313
0
{
314
0
  libfsapfs_directory_record_t *directory_record = NULL;
315
0
  libfsapfs_inode_t *inode                       = NULL;
316
0
  static char *function                          = "libfsapfs_file_system_get_file_entry_by_utf8_path";
317
0
  int result                                     = 0;
318
319
0
  if( file_system == NULL )
320
0
  {
321
0
    libcerror_error_set(
322
0
     error,
323
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
324
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
325
0
     "%s: invalid file system.",
326
0
     function );
327
328
0
    return( -1 );
329
0
  }
330
0
  if( file_entry == NULL )
331
0
  {
332
0
    libcerror_error_set(
333
0
     error,
334
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
335
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
336
0
     "%s: invalid file entry.",
337
0
     function );
338
339
0
    return( -1 );
340
0
  }
341
0
  if( *file_entry != NULL )
342
0
  {
343
0
    libcerror_error_set(
344
0
     error,
345
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
346
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
347
0
     "%s: invalid file entry value already set.",
348
0
     function );
349
350
0
    return( -1 );
351
0
  }
352
0
  result = libfsapfs_file_system_btree_get_inode_by_utf8_path(
353
0
            file_system->file_system_btree,
354
0
            file_io_handle,
355
0
            2,
356
0
            utf8_string,
357
0
            utf8_string_length,
358
0
            transaction_identifier,
359
0
            &inode,
360
0
            &directory_record,
361
0
            error );
362
363
0
  if( result == -1 )
364
0
  {
365
0
    libcerror_error_set(
366
0
     error,
367
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
368
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
369
0
     "%s: unable to retrieve inode from file system B-tree.",
370
0
     function );
371
372
0
    goto on_error;
373
0
  }
374
0
  else if( result != 0 )
375
0
  {
376
0
    if( libfsapfs_file_entry_initialize(
377
0
         file_entry,
378
0
         file_system->io_handle,
379
0
         file_io_handle,
380
0
         file_system->encryption_context,
381
0
         file_system->file_system_btree,
382
0
         inode,
383
0
         directory_record,
384
0
         transaction_identifier,
385
0
         error ) != 1 )
386
0
    {
387
0
      libcerror_error_set(
388
0
       error,
389
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
390
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
391
0
       "%s: unable to create file entry.",
392
0
       function );
393
394
0
      goto on_error;
395
0
    }
396
0
    inode            = NULL;
397
0
    directory_record = NULL;
398
0
  }
399
0
  return( result );
400
401
0
on_error:
402
0
  if( directory_record != NULL )
403
0
  {
404
0
    libfsapfs_directory_record_free(
405
0
     &directory_record,
406
0
     NULL );
407
0
  }
408
0
  if( inode != NULL )
409
0
  {
410
0
    libfsapfs_inode_free(
411
0
     &inode,
412
0
     NULL );
413
0
  }
414
0
  return( -1 );
415
0
}
416
417
/* Retrieves a file entry for an UTF-16 encoded path from the file system
418
 * Returns 1 if successful, 0 if not found or -1 on error
419
 */
420
int libfsapfs_file_system_get_file_entry_by_utf16_path(
421
     libfsapfs_file_system_t *file_system,
422
     libbfio_handle_t *file_io_handle,
423
     const uint16_t *utf16_string,
424
     size_t utf16_string_length,
425
     uint64_t transaction_identifier,
426
     libfsapfs_file_entry_t **file_entry,
427
     libcerror_error_t **error )
428
0
{
429
0
  libfsapfs_directory_record_t *directory_record = NULL;
430
0
  libfsapfs_inode_t *inode                       = NULL;
431
0
  static char *function                          = "libfsapfs_file_system_get_file_entry_by_utf16_path";
432
0
  int result                                     = 0;
433
434
0
  if( file_system == NULL )
435
0
  {
436
0
    libcerror_error_set(
437
0
     error,
438
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
439
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
440
0
     "%s: invalid file system.",
441
0
     function );
442
443
0
    return( -1 );
444
0
  }
445
0
  if( file_entry == NULL )
446
0
  {
447
0
    libcerror_error_set(
448
0
     error,
449
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
450
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
451
0
     "%s: invalid file entry.",
452
0
     function );
453
454
0
    return( -1 );
455
0
  }
456
0
  if( *file_entry != NULL )
457
0
  {
458
0
    libcerror_error_set(
459
0
     error,
460
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
461
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
462
0
     "%s: invalid file entry value already set.",
463
0
     function );
464
465
0
    return( -1 );
466
0
  }
467
0
  result = libfsapfs_file_system_btree_get_inode_by_utf16_path(
468
0
            file_system->file_system_btree,
469
0
            file_io_handle,
470
0
            2,
471
0
            utf16_string,
472
0
            utf16_string_length,
473
0
            transaction_identifier,
474
0
            &inode,
475
0
            &directory_record,
476
0
            error );
477
478
0
  if( result == -1 )
479
0
  {
480
0
    libcerror_error_set(
481
0
     error,
482
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
483
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
484
0
     "%s: unable to retrieve inode from file system B-tree.",
485
0
     function );
486
487
0
    goto on_error;
488
0
  }
489
0
  else if( result != 0 )
490
0
  {
491
0
    if( libfsapfs_file_entry_initialize(
492
0
         file_entry,
493
0
         file_system->io_handle,
494
0
         file_io_handle,
495
0
         file_system->encryption_context,
496
0
         file_system->file_system_btree,
497
0
         inode,
498
0
         directory_record,
499
0
         transaction_identifier,
500
0
         error ) != 1 )
501
0
    {
502
0
      libcerror_error_set(
503
0
       error,
504
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
505
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
506
0
       "%s: unable to create file entry.",
507
0
       function );
508
509
0
      goto on_error;
510
0
    }
511
0
    inode            = NULL;
512
0
    directory_record = NULL;
513
0
  }
514
0
  return( result );
515
516
0
on_error:
517
0
  if( directory_record != NULL )
518
0
  {
519
0
    libfsapfs_directory_record_free(
520
0
     &directory_record,
521
0
     NULL );
522
0
  }
523
0
  if( inode != NULL )
524
0
  {
525
0
    libfsapfs_inode_free(
526
0
     &inode,
527
     NULL );
528
0
  }
529
0
  return( -1 );
530
0
}
531