Coverage Report

Created: 2026-07-10 07:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libphdi/libphdi/libphdi_block_tree.c
Line
Count
Source
1
/*
2
 * Block tree functions
3
 *
4
 * Copyright (C) 2015-2026, 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 "libphdi_block_descriptor.h"
27
#include "libphdi_block_tree.h"
28
#include "libphdi_block_tree_node.h"
29
#include "libphdi_definitions.h"
30
#include "libphdi_libcdata.h"
31
#include "libphdi_libcerror.h"
32
#include "libphdi_libcnotify.h"
33
#include "libphdi_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 libphdi_block_tree_initialize(
40
     libphdi_block_tree_t **block_tree,
41
     size64_t size,
42
     size64_t leaf_value_size,
43
     libcerror_error_t **error )
44
0
{
45
0
  static char *function = "libphdi_block_tree_initialize";
46
47
0
  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
0
  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
0
  *block_tree = memory_allocate_structure(
70
0
                 libphdi_block_tree_t );
71
72
0
  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
0
  if( memory_set(
84
0
       *block_tree,
85
0
       0,
86
0
       sizeof( libphdi_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
0
  if( libphdi_block_tree_node_initialize(
103
0
       &( ( *block_tree )->root_node ),
104
0
       0,
105
0
       size,
106
0
       leaf_value_size,
107
0
       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
0
  ( *block_tree )->leaf_value_size = leaf_value_size;
119
120
0
  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
0
}
132
133
/* Frees a block tree
134
 * Returns 1 if successful or -1 on error
135
 */
136
int libphdi_block_tree_free(
137
     libphdi_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
0
{
143
0
  static char *function = "libphdi_block_tree_free";
144
0
  int result            = 1;
145
146
0
  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
0
  if( *block_tree != NULL )
158
0
  {
159
0
    if( ( *block_tree )->root_node != NULL )
160
0
    {
161
0
      if( libphdi_block_tree_node_free(
162
0
           &( ( *block_tree )->root_node ),
163
0
           value_free_function,
164
0
           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
0
    }
176
0
    memory_free(
177
0
     *block_tree );
178
179
0
    *block_tree = NULL;
180
0
  }
181
0
  return( result );
182
0
}
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 libphdi_block_tree_get_block_descriptor_by_offset(
188
     libphdi_block_tree_t *block_tree,
189
     off64_t offset,
190
     libphdi_block_descriptor_t **block_descriptor,
191
     off64_t *block_offset,
192
     libcerror_error_t **error )
193
0
{
194
0
  libphdi_block_descriptor_t *safe_block_descriptor = NULL;
195
0
  libphdi_block_tree_node_t *block_tree_node        = NULL;
196
0
  static char *function                             = "libphdi_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( libphdi_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( libphdi_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 libphdi_block_tree_insert_block_descriptor_by_offset(
290
     libphdi_block_tree_t *block_tree,
291
     off64_t offset,
292
     libphdi_block_descriptor_t *block_descriptor,
293
     int *leaf_value_index,
294
     libphdi_block_tree_node_t **leaf_block_tree_node,
295
     libphdi_block_descriptor_t **existing_block_descriptor,
296
     libcerror_error_t **error )
297
0
{
298
0
  libphdi_block_descriptor_t *safe_block_descriptor = NULL;
299
0
  libphdi_block_tree_node_t *block_tree_node        = NULL;
300
0
  libphdi_block_tree_node_t *safe_block_tree_node   = NULL;
301
0
  libphdi_block_tree_node_t *sub_block_tree_node    = NULL;
302
0
  static char *function                             = "libphdi_block_tree_insert_block_descriptor_by_offset";
303
0
  off64_t block_offset                              = 0;
304
0
  off64_t sub_node_index                            = 0;
305
0
  off64_t sub_node_offset                           = 0;
306
307
0
  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
0
  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
0
  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
0
  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
0
  safe_block_tree_node = block_tree->root_node;
352
353
0
  while( safe_block_tree_node->is_leaf_node == 0 )
354
0
  {
355
0
    if( libphdi_block_tree_node_get_sub_node_at_offset(
356
0
         safe_block_tree_node,
357
0
         offset,
358
0
         &block_tree_node,
359
0
         error ) != 1 )
360
0
    {
361
0
      libcerror_error_set(
362
0
       error,
363
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
364
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
365
0
       "%s: unable to retrieve sub node at offset: %" PRIi64 " (0x%08" PRIx64 ").",
366
0
       function,
367
0
       offset,
368
0
       offset );
369
370
0
      goto on_error;
371
0
    }
372
0
    if( block_tree_node == NULL )
373
0
    {
374
0
      sub_node_offset = offset - safe_block_tree_node->start_offset;
375
376
0
      sub_node_index  = sub_node_offset / safe_block_tree_node->sub_node_size;
377
0
      sub_node_offset = safe_block_tree_node->start_offset + ( sub_node_index * safe_block_tree_node->sub_node_size );
378
379
0
      if( libphdi_block_tree_node_initialize(
380
0
           &sub_block_tree_node,
381
0
           sub_node_offset,
382
0
           safe_block_tree_node->sub_node_size,
383
0
           block_tree->leaf_value_size,
384
0
           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
0
      if( libphdi_block_tree_node_set_sub_node_at_offset(
396
0
           safe_block_tree_node,
397
0
           offset,
398
0
           sub_block_tree_node,
399
0
           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
0
      block_tree_node     = sub_block_tree_node;
413
0
      sub_block_tree_node = NULL;
414
0
    }
415
0
    safe_block_tree_node = block_tree_node;
416
0
  }
417
0
  *leaf_block_tree_node = safe_block_tree_node;
418
419
0
  if( libphdi_block_tree_node_get_leaf_value_at_offset(
420
0
       safe_block_tree_node,
421
0
       offset,
422
0
       &safe_block_descriptor,
423
0
       &block_offset,
424
0
       error ) != 1 )
425
0
  {
426
0
    libcerror_error_set(
427
0
     error,
428
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
429
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
430
0
     "%s: unable to retrieve leaf value at offset: %" PRIi64 " (0x%08" PRIx64 ").",
431
0
     function,
432
0
     offset,
433
0
     offset );
434
435
0
    goto on_error;
436
0
  }
437
0
  if( safe_block_descriptor != NULL )
438
0
  {
439
0
    *existing_block_descriptor = safe_block_descriptor;
440
441
0
    return( 0 );
442
0
  }
443
0
  if( libphdi_block_tree_node_set_leaf_value_at_offset(
444
0
       safe_block_tree_node,
445
0
       offset,
446
0
       block_descriptor,
447
0
       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
0
  *leaf_value_index = (int) ( offset / block_tree->leaf_value_size );
461
462
0
  return( 1 );
463
464
0
on_error:
465
0
  if( sub_block_tree_node != NULL )
466
0
  {
467
0
    libphdi_block_tree_node_free(
468
0
     &sub_block_tree_node,
469
0
     NULL,
470
     NULL );
471
0
  }
472
0
  return( -1 );
473
0
}
474