Coverage Report

Created: 2025-06-24 07:14

/src/libpff/libpff/libpff_block_tree.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Block tree functions
3
 *
4
 * Copyright (C) 2008-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 "libpff_block_descriptor.h"
27
#include "libpff_block_tree.h"
28
#include "libpff_block_tree_node.h"
29
#include "libpff_definitions.h"
30
#include "libpff_libcdata.h"
31
#include "libpff_libcerror.h"
32
#include "libpff_libcnotify.h"
33
#include "libpff_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 libpff_block_tree_initialize(
40
     libpff_block_tree_t **block_tree,
41
     size64_t size,
42
     size64_t leaf_value_size,
43
     libcerror_error_t **error )
44
751k
{
45
751k
  static char *function = "libpff_block_tree_initialize";
46
47
751k
  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
751k
  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
751k
  *block_tree = memory_allocate_structure(
70
751k
                 libpff_block_tree_t );
71
72
751k
  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
751k
  if( memory_set(
84
751k
       *block_tree,
85
751k
       0,
86
751k
       sizeof( libpff_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
751k
  if( libpff_block_tree_node_initialize(
103
751k
       &( ( *block_tree )->root_node ),
104
751k
       0,
105
751k
       size,
106
751k
       leaf_value_size,
107
751k
       error ) != 1 )
108
23
  {
109
23
    libcerror_error_set(
110
23
     error,
111
23
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
112
23
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
113
23
     "%s: unable to create root node.",
114
23
     function );
115
116
23
    goto on_error;
117
23
  }
118
751k
  ( *block_tree )->leaf_value_size = leaf_value_size;
119
120
751k
  return( 1 );
121
122
23
on_error:
123
23
  if( *block_tree != NULL )
124
23
  {
125
23
    memory_free(
126
23
     *block_tree );
127
128
23
    *block_tree = NULL;
129
23
  }
130
23
  return( -1 );
131
751k
}
132
133
/* Frees a block tree
134
 * Returns 1 if successful or -1 on error
135
 */
136
int libpff_block_tree_free(
137
     libpff_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
751k
{
143
751k
  static char *function = "libpff_block_tree_free";
144
751k
  int result            = 1;
145
146
751k
  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
751k
  if( *block_tree != NULL )
158
751k
  {
159
751k
    if( ( *block_tree )->root_node != NULL )
160
751k
    {
161
751k
      if( libpff_block_tree_node_free(
162
751k
           &( ( *block_tree )->root_node ),
163
751k
           value_free_function,
164
751k
           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
751k
    }
176
751k
    memory_free(
177
751k
     *block_tree );
178
179
751k
    *block_tree = NULL;
180
751k
  }
181
751k
  return( result );
182
751k
}
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 libpff_block_tree_get_block_descriptor_by_offset(
188
     libpff_block_tree_t *block_tree,
189
     off64_t offset,
190
     libpff_block_descriptor_t **block_descriptor,
191
     off64_t *block_offset,
192
     libcerror_error_t **error )
193
0
{
194
0
  libpff_block_descriptor_t *safe_block_descriptor = NULL;
195
0
  libpff_block_tree_node_t *block_tree_node        = NULL;
196
0
  static char *function                            = "libpff_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( libpff_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( libpff_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 libpff_block_tree_insert_block_descriptor_by_offset(
290
     libpff_block_tree_t *block_tree,
291
     off64_t offset,
292
     libpff_block_descriptor_t *block_descriptor,
293
     int *leaf_value_index,
294
     libpff_block_tree_node_t **leaf_block_tree_node,
295
     libpff_block_descriptor_t **existing_block_descriptor,
296
     libcerror_error_t **error )
297
1.37M
{
298
1.37M
  libpff_block_descriptor_t *safe_block_descriptor = NULL;
299
1.37M
  libpff_block_tree_node_t *block_tree_node        = NULL;
300
1.37M
  libpff_block_tree_node_t *safe_block_tree_node   = NULL;
301
1.37M
  libpff_block_tree_node_t *sub_block_tree_node    = NULL;
302
1.37M
  static char *function                            = "libpff_block_tree_insert_block_descriptor_by_offset";
303
1.37M
  off64_t block_offset                             = 0;
304
1.37M
  off64_t sub_node_index                           = 0;
305
1.37M
  off64_t sub_node_offset                          = 0;
306
307
1.37M
  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.37M
  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.37M
  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.37M
  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.37M
  safe_block_tree_node = block_tree->root_node;
352
353
3.30M
  while( safe_block_tree_node->is_leaf_node == 0 )
354
1.92M
  {
355
1.92M
    if( libpff_block_tree_node_get_sub_node_at_offset(
356
1.92M
         safe_block_tree_node,
357
1.92M
         offset,
358
1.92M
         &block_tree_node,
359
1.92M
         error ) != 1 )
360
605
    {
361
605
      libcerror_error_set(
362
605
       error,
363
605
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
364
605
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
365
605
       "%s: unable to retrieve sub node at offset: %" PRIi64 " (0x%08" PRIx64 ").",
366
605
       function,
367
605
       offset,
368
605
       offset );
369
370
605
      goto on_error;
371
605
    }
372
1.92M
    if( block_tree_node == NULL )
373
1.07M
    {
374
1.07M
      sub_node_offset = offset - safe_block_tree_node->start_offset;
375
376
1.07M
      sub_node_index  = sub_node_offset / safe_block_tree_node->sub_node_size;
377
1.07M
      sub_node_offset = safe_block_tree_node->start_offset + ( sub_node_index * safe_block_tree_node->sub_node_size );
378
379
1.07M
      if( libpff_block_tree_node_initialize(
380
1.07M
           &sub_block_tree_node,
381
1.07M
           sub_node_offset,
382
1.07M
           safe_block_tree_node->sub_node_size,
383
1.07M
           block_tree->leaf_value_size,
384
1.07M
           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
1.07M
      if( libpff_block_tree_node_set_sub_node_at_offset(
396
1.07M
           safe_block_tree_node,
397
1.07M
           offset,
398
1.07M
           sub_block_tree_node,
399
1.07M
           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
1.07M
      block_tree_node     = sub_block_tree_node;
413
1.07M
      sub_block_tree_node = NULL;
414
1.07M
    }
415
1.92M
    safe_block_tree_node = block_tree_node;
416
1.92M
  }
417
1.37M
  *leaf_block_tree_node = safe_block_tree_node;
418
419
1.37M
  if( libpff_block_tree_node_get_leaf_value_at_offset(
420
1.37M
       safe_block_tree_node,
421
1.37M
       offset,
422
1.37M
       &safe_block_descriptor,
423
1.37M
       &block_offset,
424
1.37M
       error ) != 1 )
425
121
  {
426
121
    libcerror_error_set(
427
121
     error,
428
121
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
429
121
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
430
121
     "%s: unable to retrieve leaf value at offset: %" PRIi64 " (0x%08" PRIx64 ").",
431
121
     function,
432
121
     offset,
433
121
     offset );
434
435
121
    goto on_error;
436
121
  }
437
1.37M
  if( safe_block_descriptor != NULL )
438
367
  {
439
367
    *existing_block_descriptor = safe_block_descriptor;
440
441
367
    return( 0 );
442
367
  }
443
1.37M
  if( libpff_block_tree_node_set_leaf_value_at_offset(
444
1.37M
       safe_block_tree_node,
445
1.37M
       offset,
446
1.37M
       block_descriptor,
447
1.37M
       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.37M
  *leaf_value_index = (int) ( offset / block_tree->leaf_value_size );
461
462
1.37M
  return( 1 );
463
464
726
on_error:
465
726
  if( sub_block_tree_node != NULL )
466
0
  {
467
0
    libpff_block_tree_node_free(
468
0
     &sub_block_tree_node,
469
0
     NULL,
470
0
     NULL );
471
0
  }
472
726
  return( -1 );
473
1.37M
}
474