Coverage Report

Created: 2025-06-22 07:35

/src/libfsfat/libfsfat/libfsfat_block_tree.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Block tree functions
3
 *
4
 * Copyright (C) 2021-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 <memory.h>
24
#include <types.h>
25
26
#include "libfsfat_block_descriptor.h"
27
#include "libfsfat_block_tree.h"
28
#include "libfsfat_block_tree_node.h"
29
#include "libfsfat_definitions.h"
30
#include "libfsfat_libcdata.h"
31
#include "libfsfat_libcerror.h"
32
#include "libfsfat_libcnotify.h"
33
#include "libfsfat_unused.h"
34
35
/* Creates a block tree
36
 * Make sure the value block_tree is referencing, is set to NULL
37
 * Returns 1 if successful or -1 on error
38
 */
39
int libfsfat_block_tree_initialize(
40
     libfsfat_block_tree_t **block_tree,
41
     size64_t size,
42
     size64_t leaf_value_size,
43
     libcerror_error_t **error )
44
1.27k
{
45
1.27k
  static char *function = "libfsfat_block_tree_initialize";
46
47
1.27k
  if( block_tree == NULL )
48
0
  {
49
0
    libcerror_error_set(
50
0
     error,
51
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
52
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
53
0
     "%s: invalid block tree.",
54
0
     function );
55
56
0
    return( -1 );
57
0
  }
58
1.27k
  if( *block_tree != NULL )
59
0
  {
60
0
    libcerror_error_set(
61
0
     error,
62
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
63
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
64
0
     "%s: invalid block tree value already set.",
65
0
     function );
66
67
0
    return( -1 );
68
0
  }
69
1.27k
  *block_tree = memory_allocate_structure(
70
1.27k
                 libfsfat_block_tree_t );
71
72
1.27k
  if( *block_tree == NULL )
73
0
  {
74
0
    libcerror_error_set(
75
0
     error,
76
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
77
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
78
0
     "%s: unable to create block tree.",
79
0
     function );
80
81
0
    goto on_error;
82
0
  }
83
1.27k
  if( memory_set(
84
1.27k
       *block_tree,
85
1.27k
       0,
86
1.27k
       sizeof( libfsfat_block_tree_t ) ) == NULL )
87
0
  {
88
0
    libcerror_error_set(
89
0
     error,
90
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
91
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
92
0
     "%s: unable to clear block tree.",
93
0
     function );
94
95
0
    memory_free(
96
0
     *block_tree );
97
98
0
    *block_tree = NULL;
99
100
0
    return( -1 );
101
0
  }
102
1.27k
  if( libfsfat_block_tree_node_initialize(
103
1.27k
       &( ( *block_tree )->root_node ),
104
1.27k
       0,
105
1.27k
       size,
106
1.27k
       leaf_value_size,
107
1.27k
       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 root node.",
114
0
     function );
115
116
0
    goto on_error;
117
0
  }
118
1.27k
  ( *block_tree )->leaf_value_size = leaf_value_size;
119
120
1.27k
  return( 1 );
121
122
0
on_error:
123
0
  if( *block_tree != NULL )
124
0
  {
125
0
    memory_free(
126
0
     *block_tree );
127
128
0
    *block_tree = NULL;
129
0
  }
130
0
  return( -1 );
131
1.27k
}
132
133
/* Frees a block tree
134
 * Returns 1 if successful or -1 on error
135
 */
136
int libfsfat_block_tree_free(
137
     libfsfat_block_tree_t **block_tree,
138
     int (*value_free_function)(
139
            intptr_t **value,
140
            libcerror_error_t **error ),
141
     libcerror_error_t **error )
142
1.27k
{
143
1.27k
  static char *function = "libfsfat_block_tree_free";
144
1.27k
  int result            = 1;
145
146
1.27k
  if( block_tree == NULL )
147
0
  {
148
0
    libcerror_error_set(
149
0
     error,
150
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
151
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
152
0
     "%s: invalid block tree.",
153
0
     function );
154
155
0
    return( -1 );
156
0
  }
157
1.27k
  if( *block_tree != NULL )
158
1.27k
  {
159
1.27k
    if( ( *block_tree )->root_node != NULL )
160
1.27k
    {
161
1.27k
      if( libfsfat_block_tree_node_free(
162
1.27k
           &( ( *block_tree )->root_node ),
163
1.27k
           value_free_function,
164
1.27k
           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 root node.",
171
0
         function );
172
173
0
        result = -1;
174
0
      }
175
1.27k
    }
176
1.27k
    memory_free(
177
1.27k
     *block_tree );
178
179
1.27k
    *block_tree = NULL;
180
1.27k
  }
181
1.27k
  return( result );
182
1.27k
}
183
184
/* Retrieves the block descriptor for a specific offset
185
 * Returns 1 if successful, 0 if not available or -1 on error
186
 */
187
int libfsfat_block_tree_get_block_descriptor_by_offset(
188
     libfsfat_block_tree_t *block_tree,
189
     off64_t offset,
190
     libfsfat_block_descriptor_t **block_descriptor,
191
     off64_t *block_offset,
192
     libcerror_error_t **error )
193
0
{
194
0
  libfsfat_block_descriptor_t *safe_block_descriptor = NULL;
195
0
  libfsfat_block_tree_node_t *block_tree_node        = NULL;
196
0
  static char *function                              = "libfsfat_block_tree_get_block_descriptor_by_offset";
197
0
  off64_t safe_block_offset                          = 0;
198
199
0
  if( block_tree == NULL )
200
0
  {
201
0
    libcerror_error_set(
202
0
     error,
203
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
204
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
205
0
     "%s: invalid block tree.",
206
0
     function );
207
208
0
    return( -1 );
209
0
  }
210
0
  if( block_descriptor == NULL )
211
0
  {
212
0
    libcerror_error_set(
213
0
     error,
214
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
215
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
216
0
     "%s: invalid block descriptor.",
217
0
     function );
218
219
0
    return( -1 );
220
0
  }
221
0
  if( block_offset == NULL )
222
0
  {
223
0
    libcerror_error_set(
224
0
     error,
225
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
226
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
227
0
     "%s: invalid block offset.",
228
0
     function );
229
230
0
    return( -1 );
231
0
  }
232
0
  block_tree_node = block_tree->root_node;
233
234
0
  while( block_tree_node->is_leaf_node == 0 )
235
0
  {
236
0
    if( libfsfat_block_tree_node_get_sub_node_at_offset(
237
0
         block_tree_node,
238
0
         offset,
239
0
         &block_tree_node,
240
0
         error ) != 1 )
241
0
    {
242
0
      libcerror_error_set(
243
0
       error,
244
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
245
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
246
0
       "%s: unable to retrieve sub node at offset: %" PRIi64 " (0x%08" PRIx64 ").",
247
0
       function,
248
0
       offset,
249
0
       offset );
250
251
0
      return( -1 );
252
0
    }
253
0
    if( block_tree_node == NULL )
254
0
    {
255
0
      return( 0 );
256
0
    }
257
0
  }
258
0
  if( libfsfat_block_tree_node_get_leaf_value_at_offset(
259
0
       block_tree_node,
260
0
       offset,
261
0
       &safe_block_descriptor,
262
0
       &safe_block_offset,
263
0
       error ) != 1 )
264
0
  {
265
0
    libcerror_error_set(
266
0
     error,
267
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
268
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
269
0
     "%s: unable to retrieve leaf value at offset: %" PRIi64 " (0x%08" PRIx64 ").",
270
0
     function,
271
0
     offset,
272
0
     offset );
273
274
0
    return( -1 );
275
0
  }
276
0
  *block_descriptor = safe_block_descriptor;
277
0
  *block_offset     = safe_block_offset;
278
279
0
  if( safe_block_descriptor == NULL )
280
0
  {
281
0
    return( 0 );
282
0
  }
283
0
  return( 1 );
284
0
}
285
286
/* Inserts the block descriptor for a specific offset
287
 * Returns 1 if successful, 0 if already set or -1 on error
288
 */
289
int libfsfat_block_tree_insert_block_descriptor_by_offset(
290
     libfsfat_block_tree_t *block_tree,
291
     off64_t offset,
292
     libfsfat_block_descriptor_t *block_descriptor,
293
     int *leaf_value_index,
294
     libfsfat_block_tree_node_t **leaf_block_tree_node,
295
     libfsfat_block_descriptor_t **existing_block_descriptor,
296
     libcerror_error_t **error )
297
1.64k
{
298
1.64k
  libfsfat_block_descriptor_t *safe_block_descriptor = NULL;
299
1.64k
  libfsfat_block_tree_node_t *block_tree_node        = NULL;
300
1.64k
  libfsfat_block_tree_node_t *safe_block_tree_node   = NULL;
301
1.64k
  libfsfat_block_tree_node_t *sub_block_tree_node    = NULL;
302
1.64k
  static char *function                              = "libfsfat_block_tree_insert_block_descriptor_by_offset";
303
1.64k
  off64_t block_offset                               = 0;
304
1.64k
  off64_t sub_node_index                             = 0;
305
1.64k
  off64_t sub_node_offset                            = 0;
306
307
1.64k
  if( block_tree == NULL )
308
0
  {
309
0
    libcerror_error_set(
310
0
     error,
311
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
312
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
313
0
     "%s: invalid block tree.",
314
0
     function );
315
316
0
    return( -1 );
317
0
  }
318
1.64k
  if( leaf_value_index == NULL )
319
0
  {
320
0
    libcerror_error_set(
321
0
     error,
322
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
323
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
324
0
     "%s: invalid leaf value index.",
325
0
     function );
326
327
0
    return( -1 );
328
0
  }
329
1.64k
  if( leaf_block_tree_node == NULL )
330
0
  {
331
0
    libcerror_error_set(
332
0
     error,
333
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
334
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
335
0
     "%s: invalid leaf block tree node.",
336
0
     function );
337
338
0
    return( -1 );
339
0
  }
340
1.64k
  if( existing_block_descriptor == NULL )
341
0
  {
342
0
    libcerror_error_set(
343
0
     error,
344
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
345
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
346
0
     "%s: invalid existing block descriptor.",
347
0
     function );
348
349
0
    return( -1 );
350
0
  }
351
1.64k
  safe_block_tree_node = block_tree->root_node;
352
353
1.94k
  while( safe_block_tree_node->is_leaf_node == 0 )
354
392
  {
355
392
    if( libfsfat_block_tree_node_get_sub_node_at_offset(
356
392
         safe_block_tree_node,
357
392
         offset,
358
392
         &block_tree_node,
359
392
         error ) != 1 )
360
96
    {
361
96
      libcerror_error_set(
362
96
       error,
363
96
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
364
96
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
365
96
       "%s: unable to retrieve sub node at offset: %" PRIi64 " (0x%08" PRIx64 ").",
366
96
       function,
367
96
       offset,
368
96
       offset );
369
370
96
      goto on_error;
371
96
    }
372
296
    if( block_tree_node == NULL )
373
171
    {
374
171
      sub_node_offset = offset - safe_block_tree_node->start_offset;
375
376
171
      sub_node_index  = sub_node_offset / safe_block_tree_node->sub_node_size;
377
171
      sub_node_offset = safe_block_tree_node->start_offset + ( sub_node_index * safe_block_tree_node->sub_node_size );
378
379
171
      if( libfsfat_block_tree_node_initialize(
380
171
           &sub_block_tree_node,
381
171
           sub_node_offset,
382
171
           safe_block_tree_node->sub_node_size,
383
171
           block_tree->leaf_value_size,
384
171
           error ) != 1 )
385
0
      {
386
0
        libcerror_error_set(
387
0
         error,
388
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
389
0
         LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
390
0
         "%s: unable to create sub node.",
391
0
         function );
392
393
0
        goto on_error;
394
0
      }
395
171
      if( libfsfat_block_tree_node_set_sub_node_at_offset(
396
171
           safe_block_tree_node,
397
171
           offset,
398
171
           sub_block_tree_node,
399
171
           error ) != 1 )
400
0
      {
401
0
        libcerror_error_set(
402
0
         error,
403
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
404
0
         LIBCERROR_RUNTIME_ERROR_GET_FAILED,
405
0
         "%s: unable to set sub node at offset: %" PRIi64 " (0x%08" PRIx64 ").",
406
0
         function,
407
0
         offset,
408
0
         offset );
409
410
0
        goto on_error;
411
0
      }
412
171
      block_tree_node     = sub_block_tree_node;
413
171
      sub_block_tree_node = NULL;
414
171
    }
415
296
    safe_block_tree_node = block_tree_node;
416
296
  }
417
1.55k
  *leaf_block_tree_node = safe_block_tree_node;
418
419
1.55k
  if( libfsfat_block_tree_node_get_leaf_value_at_offset(
420
1.55k
       safe_block_tree_node,
421
1.55k
       offset,
422
1.55k
       &safe_block_descriptor,
423
1.55k
       &block_offset,
424
1.55k
       error ) != 1 )
425
310
  {
426
310
    libcerror_error_set(
427
310
     error,
428
310
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
429
310
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
430
310
     "%s: unable to retrieve leaf value at offset: %" PRIi64 " (0x%08" PRIx64 ").",
431
310
     function,
432
310
     offset,
433
310
     offset );
434
435
310
    goto on_error;
436
310
  }
437
1.24k
  if( safe_block_descriptor != NULL )
438
12
  {
439
12
    *existing_block_descriptor = safe_block_descriptor;
440
441
12
    return( 0 );
442
12
  }
443
1.23k
  if( libfsfat_block_tree_node_set_leaf_value_at_offset(
444
1.23k
       safe_block_tree_node,
445
1.23k
       offset,
446
1.23k
       block_descriptor,
447
1.23k
       error ) != 1 )
448
0
  {
449
0
    libcerror_error_set(
450
0
     error,
451
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
452
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
453
0
     "%s: unable to set leaf value at offset: %" PRIi64 " (0x%08" PRIx64 ").",
454
0
     function,
455
0
     offset,
456
0
     offset );
457
458
0
    goto on_error;
459
0
  }
460
1.23k
  *leaf_value_index = (int) ( offset / block_tree->leaf_value_size );
461
462
1.23k
  return( 1 );
463
464
406
on_error:
465
406
  if( sub_block_tree_node != NULL )
466
0
  {
467
0
    libfsfat_block_tree_node_free(
468
0
     &sub_block_tree_node,
469
0
     NULL,
470
0
     NULL );
471
0
  }
472
406
  return( -1 );
473
1.23k
}
474