Coverage Report

Created: 2025-06-13 07:22

/src/libfshfs/libfshfs/libfshfs_btree_file.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * B-tree file functions
3
 *
4
 * Copyright (C) 2009-2024, 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 "libfshfs_btree_file.h"
28
#include "libfshfs_btree_header.h"
29
#include "libfshfs_btree_node.h"
30
#include "libfshfs_btree_node_cache.h"
31
#include "libfshfs_btree_node_descriptor.h"
32
#include "libfshfs_btree_node_vector.h"
33
#include "libfshfs_debug.h"
34
#include "libfshfs_definitions.h"
35
#include "libfshfs_extent.h"
36
#include "libfshfs_libcdata.h"
37
#include "libfshfs_libcerror.h"
38
#include "libfshfs_libcnotify.h"
39
#include "libfshfs_libfcache.h"
40
#include "libfshfs_libfdata.h"
41
42
#include "fshfs_btree.h"
43
44
/* Creates a B-tree file
45
 * Make sure the value btree_file is referencing, is set to NULL
46
 * Returns 1 if successful or -1 on error
47
 */
48
int libfshfs_btree_file_initialize(
49
     libfshfs_btree_file_t **btree_file,
50
     libcerror_error_t **error )
51
12.5k
{
52
12.5k
  static char *function = "libfshfs_btree_file_initialize";
53
54
12.5k
  if( btree_file == NULL )
55
0
  {
56
0
    libcerror_error_set(
57
0
     error,
58
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
59
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
60
0
     "%s: invalid B-tree file.",
61
0
     function );
62
63
0
    return( -1 );
64
0
  }
65
12.5k
  if( *btree_file != NULL )
66
0
  {
67
0
    libcerror_error_set(
68
0
     error,
69
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
70
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
71
0
     "%s: invalid B-tree file value already set.",
72
0
     function );
73
74
0
    return( -1 );
75
0
  }
76
12.5k
  *btree_file = memory_allocate_structure(
77
12.5k
                 libfshfs_btree_file_t );
78
79
12.5k
  if( *btree_file == NULL )
80
0
  {
81
0
    libcerror_error_set(
82
0
     error,
83
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
84
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
85
0
     "%s: unable to create B-tree file.",
86
0
     function );
87
88
0
    goto on_error;
89
0
  }
90
12.5k
  if( memory_set(
91
12.5k
       *btree_file,
92
12.5k
       0,
93
12.5k
       sizeof( libfshfs_btree_file_t ) ) == NULL )
94
0
  {
95
0
    libcerror_error_set(
96
0
     error,
97
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
98
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
99
0
     "%s: unable to clear B-tree file.",
100
0
     function );
101
102
0
    memory_free(
103
0
     *btree_file );
104
105
0
    *btree_file = NULL;
106
107
0
    return( -1 );
108
0
  }
109
12.5k
  if( libcdata_array_initialize(
110
12.5k
       &( ( *btree_file )->extents ),
111
12.5k
       0,
112
12.5k
       error ) != 1 )
113
0
  {
114
0
    libcerror_error_set(
115
0
     error,
116
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
117
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
118
0
     "%s: unable to create extents array.",
119
0
     function );
120
121
0
    goto on_error;
122
0
  }
123
12.5k
  if( libfshfs_btree_header_initialize(
124
12.5k
       &( ( *btree_file )->header ),
125
12.5k
       error ) != 1 )
126
0
  {
127
0
    libcerror_error_set(
128
0
     error,
129
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
130
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
131
0
     "%s: unable to create header.",
132
0
     function );
133
134
0
    goto on_error;
135
0
  }
136
12.5k
  return( 1 );
137
138
0
on_error:
139
0
  if( *btree_file != NULL )
140
0
  {
141
0
    if( ( *btree_file )->extents != NULL )
142
0
    {
143
0
      libcdata_array_free(
144
0
       &( ( *btree_file )->extents ),
145
0
       NULL,
146
0
       NULL );
147
0
    }
148
0
    memory_free(
149
0
     *btree_file );
150
151
0
    *btree_file = NULL;
152
0
  }
153
0
  return( -1 );
154
12.5k
}
155
156
/* Frees B-tree file
157
 * Returns 1 if successful or -1 on error
158
 */
159
int libfshfs_btree_file_free(
160
     libfshfs_btree_file_t **btree_file,
161
     libcerror_error_t **error )
162
12.5k
{
163
12.5k
  static char *function = "libfshfs_btree_file_free";
164
12.5k
  int result            = 1;
165
166
12.5k
  if( btree_file == NULL )
167
0
  {
168
0
    libcerror_error_set(
169
0
     error,
170
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
171
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
172
0
     "%s: invalid B-tree file.",
173
0
     function );
174
175
0
    return( -1 );
176
0
  }
177
12.5k
  if( *btree_file != NULL )
178
12.5k
  {
179
12.5k
    if( libcdata_array_free(
180
12.5k
         &( ( *btree_file )->extents ),
181
12.5k
         (int (*)(intptr_t **, libcerror_error_t **)) &libfshfs_extent_free,
182
12.5k
         error ) != 1 )
183
0
    {
184
0
      libcerror_error_set(
185
0
       error,
186
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
187
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
188
0
       "%s: unable to free extents array.",
189
0
       function );
190
191
0
      result = -1;
192
0
    }
193
12.5k
    if( libfshfs_btree_header_free(
194
12.5k
         &( ( *btree_file )->header ),
195
12.5k
         error ) != 1 )
196
0
    {
197
0
      libcerror_error_set(
198
0
       error,
199
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
200
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
201
0
       "%s: unable to free header.",
202
0
       function );
203
204
0
      result = -1;
205
0
    }
206
12.5k
    if( ( *btree_file )->node_vector != NULL )
207
11.5k
    {
208
11.5k
      if( libfshfs_btree_node_vector_free(
209
11.5k
           &( ( *btree_file )->node_vector ),
210
11.5k
           error ) != 1 )
211
0
      {
212
0
        libcerror_error_set(
213
0
         error,
214
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
215
0
         LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
216
0
         "%s: unable to free B-tree node vector.",
217
0
         function );
218
219
0
        result = -1;
220
0
      }
221
11.5k
    }
222
12.5k
    memory_free(
223
12.5k
     *btree_file );
224
225
12.5k
    *btree_file = NULL;
226
12.5k
  }
227
12.5k
  return( result );
228
12.5k
}
229
230
/* Reads the B-tree file
231
 * Returns 1 if successful or -1 on error
232
 */
233
int libfshfs_btree_file_read_file_io_handle(
234
     libfshfs_btree_file_t *btree_file,
235
     libfshfs_io_handle_t *io_handle,
236
     libbfio_handle_t *file_io_handle,
237
     libcerror_error_t **error )
238
11.8k
{
239
11.8k
  uint8_t header_node_data[ 512 ];
240
241
11.8k
  libfshfs_btree_node_descriptor_t *header_node_descriptor = NULL;
242
11.8k
  libfshfs_extent_t *extent                                = NULL;
243
11.8k
  static char *function                                    = "libfshfs_btree_file_read_file_io_handle";
244
11.8k
  ssize_t read_count                                       = 0;
245
11.8k
  off64_t file_offset                                      = 0;
246
247
11.8k
  if( btree_file == NULL )
248
0
  {
249
0
    libcerror_error_set(
250
0
     error,
251
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
252
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
253
0
     "%s: invalid B-tree file.",
254
0
     function );
255
256
0
    return( -1 );
257
0
  }
258
11.8k
  if( btree_file->node_vector != NULL )
259
0
  {
260
0
    libcerror_error_set(
261
0
     error,
262
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
263
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
264
0
     "%s: invalid B-tree file - node vector already set.",
265
0
     function );
266
267
0
    return( -1 );
268
0
  }
269
11.8k
  if( io_handle == NULL )
270
0
  {
271
0
    libcerror_error_set(
272
0
     error,
273
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
274
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
275
0
     "%s: invalid IO handle.",
276
0
     function );
277
278
0
    return( -1 );
279
0
  }
280
11.8k
  if( io_handle->block_size == 0 )
281
3
  {
282
3
    libcerror_error_set(
283
3
     error,
284
3
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
285
3
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
286
3
     "%s: invalid IO handle - block size value out of bounds.",
287
3
     function );
288
289
3
    return( -1 );
290
3
  }
291
  /* Read the header record first to determine the B-tree node size.
292
   */
293
11.8k
  if( libcdata_array_get_entry_by_index(
294
11.8k
       btree_file->extents,
295
11.8k
       0,
296
11.8k
       (intptr_t **) &extent,
297
11.8k
       error ) != 1 )
298
21
  {
299
21
    libcerror_error_set(
300
21
     error,
301
21
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
302
21
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
303
21
     "%s: unable to retrieve extent: 0.",
304
21
     function );
305
306
21
    goto on_error;
307
21
  }
308
11.8k
  if( extent == NULL )
309
0
  {
310
0
    libcerror_error_set(
311
0
     error,
312
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
313
0
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
314
0
     "%s: missing extent: 0.",
315
0
     function );
316
317
0
    goto on_error;
318
0
  }
319
11.8k
  file_offset = extent->block_number * io_handle->block_size;
320
321
#if defined( HAVE_DEBUG_OUTPUT )
322
  if( libcnotify_verbose != 0 )
323
  {
324
    libcnotify_printf(
325
     "%s: reading B-tree header node at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
326
     function,
327
     file_offset,
328
     file_offset );
329
  }
330
#endif
331
11.8k
  read_count = libbfio_handle_read_buffer_at_offset(
332
11.8k
                file_io_handle,
333
11.8k
                header_node_data,
334
11.8k
                512,
335
11.8k
                file_offset,
336
11.8k
                error );
337
338
11.8k
  if( read_count != (ssize_t) 512 )
339
159
  {
340
159
    libcerror_error_set(
341
159
     error,
342
159
     LIBCERROR_ERROR_DOMAIN_IO,
343
159
     LIBCERROR_IO_ERROR_READ_FAILED,
344
159
     "%s: unable to read B-tree header node data at offset: %" PRIi64 " (0x%08" PRIx64 ").",
345
159
     function,
346
159
     file_offset,
347
159
     file_offset );
348
349
159
    goto on_error;
350
159
  }
351
11.7k
  if( libfshfs_btree_node_descriptor_initialize(
352
11.7k
       &header_node_descriptor,
353
11.7k
       error ) != 1 )
354
0
  {
355
0
    libcerror_error_set(
356
0
     error,
357
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
358
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
359
0
     "%s: unable to create B-tree header node descriptor.",
360
0
     function );
361
362
0
    goto on_error;
363
0
  }
364
11.7k
  if( libfshfs_btree_node_descriptor_read_data(
365
11.7k
       header_node_descriptor,
366
11.7k
       header_node_data,
367
11.7k
       512,
368
11.7k
       error ) != 1 )
369
7
  {
370
7
    libcerror_error_set(
371
7
     error,
372
7
     LIBCERROR_ERROR_DOMAIN_IO,
373
7
     LIBCERROR_IO_ERROR_READ_FAILED,
374
7
     "%s: unable to read B-tree header node descriptor.",
375
7
     function );
376
377
7
    goto on_error;
378
7
  }
379
11.7k
  if( header_node_descriptor->type != LIBFSHFS_BTREE_NODE_TYPE_HEADER_NODE )
380
14
  {
381
14
    libcerror_error_set(
382
14
     error,
383
14
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
384
14
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
385
14
     "%s: unuspported B-tree header node type.",
386
14
     function );
387
388
14
    goto on_error;
389
14
  }
390
11.6k
  if( libfshfs_btree_node_descriptor_free(
391
11.6k
       &header_node_descriptor,
392
11.6k
       error ) != 1 )
393
0
  {
394
0
    libcerror_error_set(
395
0
     error,
396
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
397
0
     LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
398
0
     "%s: unable to free B-tree header node descriptor.",
399
0
     function );
400
401
0
    goto on_error;
402
0
  }
403
11.6k
  if( libfshfs_btree_header_read_data(
404
11.6k
       btree_file->header,
405
11.6k
       &( header_node_data[ sizeof( fshfs_btree_node_descriptor_t ) ] ),
406
11.6k
       512 - sizeof( fshfs_btree_node_descriptor_t ),
407
11.6k
       error ) != 1 )
408
0
  {
409
0
    libcerror_error_set(
410
0
     error,
411
0
     LIBCERROR_ERROR_DOMAIN_IO,
412
0
     LIBCERROR_IO_ERROR_READ_FAILED,
413
0
     "%s: unable to read B-tree header.",
414
0
     function );
415
416
0
    goto on_error;
417
0
  }
418
  /* Read the root node using the node vector
419
   */
420
11.6k
  if( libfshfs_btree_node_vector_initialize(
421
11.6k
       &( btree_file->node_vector ),
422
11.6k
       io_handle,
423
11.6k
       btree_file->size,
424
11.6k
       btree_file->header->node_size,
425
11.6k
       btree_file->extents,
426
11.6k
       error ) != 1 )
427
117
  {
428
117
    libcerror_error_set(
429
117
     error,
430
117
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
431
117
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
432
117
     "%s: unable to create B-tree node vector.",
433
117
     function );
434
435
117
    goto on_error;
436
117
  }
437
11.5k
  return( 1 );
438
439
318
on_error:
440
318
  if( btree_file->node_vector != NULL )
441
0
  {
442
0
    libfshfs_btree_node_vector_free(
443
0
     &( btree_file->node_vector ),
444
0
     NULL );
445
0
  }
446
318
  if( header_node_descriptor != NULL )
447
21
  {
448
21
    libfshfs_btree_node_descriptor_free(
449
21
     &header_node_descriptor,
450
21
     NULL );
451
21
  }
452
318
  return( -1 );
453
11.6k
}
454
455
/* Retrieves a specific B-tree node
456
 * Returns 1 if successful or -1 on error
457
 */
458
int libfshfs_btree_file_get_node_by_number(
459
     libfshfs_btree_file_t *btree_file,
460
     libbfio_handle_t *file_io_handle,
461
     libfshfs_btree_node_cache_t *node_cache,
462
     int depth,
463
     uint32_t node_number,
464
     libfshfs_btree_node_t **node,
465
     libcerror_error_t **error )
466
58.6k
{
467
58.6k
  static char *function = "libfshfs_btree_file_get_node_by_number";
468
469
58.6k
  if( btree_file == NULL )
470
0
  {
471
0
    libcerror_error_set(
472
0
     error,
473
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
474
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
475
0
     "%s: invalid B-tree file.",
476
0
     function );
477
478
0
    return( -1 );
479
0
  }
480
58.6k
  if( ( depth <= 0 )
481
58.6k
   || ( depth >= 9 ) )
482
1.03k
  {
483
1.03k
    libcerror_error_set(
484
1.03k
     error,
485
1.03k
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
486
1.03k
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
487
1.03k
     "%s: invalid depth value out of bounds.",
488
1.03k
     function );
489
490
1.03k
    return( -1 );
491
1.03k
  }
492
57.6k
  if( libfshfs_btree_node_vector_get_node_by_number(
493
57.6k
       btree_file->node_vector,
494
57.6k
       file_io_handle,
495
57.6k
       node_cache,
496
57.6k
       depth,
497
57.6k
       node_number,
498
57.6k
       node,
499
57.6k
       error ) != 1 )
500
309
  {
501
309
    libcerror_error_set(
502
309
     error,
503
309
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
504
309
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
505
309
     "%s: unable to retrieve B-tree node: %" PRIu32 " at depth: %d.",
506
309
     function,
507
309
     node_number,
508
309
     depth );
509
510
309
    return( -1 );
511
309
  }
512
57.3k
  return( 1 );
513
57.6k
}
514
515
/* Retrieves the B-tree root node
516
 * Returns 1 if successful or -1 on error
517
 */
518
int libfshfs_btree_file_get_root_node(
519
     libfshfs_btree_file_t *btree_file,
520
     libbfio_handle_t *file_io_handle,
521
     libfshfs_btree_node_cache_t *node_cache,
522
     libfshfs_btree_node_t **root_node,
523
     libcerror_error_t **error )
524
14.3k
{
525
14.3k
  static char *function = "libfshfs_btree_file_get_root_node";
526
527
14.3k
  if( btree_file == NULL )
528
0
  {
529
0
    libcerror_error_set(
530
0
     error,
531
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
532
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
533
0
     "%s: invalid B-tree file.",
534
0
     function );
535
536
0
    return( -1 );
537
0
  }
538
14.3k
  if( libfshfs_btree_node_vector_get_node_by_number(
539
14.3k
       btree_file->node_vector,
540
14.3k
       file_io_handle,
541
14.3k
       node_cache,
542
14.3k
       0,
543
14.3k
       btree_file->header->root_node_number,
544
14.3k
       root_node,
545
14.3k
       error ) != 1 )
546
895
  {
547
895
    libcerror_error_set(
548
895
     error,
549
895
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
550
895
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
551
895
     "%s: unable to retrieve B-tree root node: %" PRIu32 " at depth: 0.",
552
895
     function,
553
895
     btree_file->header->root_node_number );
554
555
895
    return( -1 );
556
895
  }
557
13.4k
  return( 1 );
558
14.3k
}
559