Coverage Report

Created: 2025-06-22 07:35

/src/libphdi/libphdi/libphdi_block_tree_node.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Block tree node functions
3
 *
4
 * Copyright (C) 2015-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 "libphdi_block_tree_node.h"
27
#include "libphdi_definitions.h"
28
#include "libphdi_libcerror.h"
29
30
/* Creates a block tree node
31
 * Make sure the value block_tree_node is referencing, is set to NULL
32
 * Returns 1 if successful or -1 on error
33
 */
34
int libphdi_block_tree_node_initialize(
35
     libphdi_block_tree_node_t **block_tree_node,
36
     off64_t offset,
37
     size64_t size,
38
     size64_t leaf_value_size,
39
     libcerror_error_t **error )
40
0
{
41
0
  static char *function  = "libphdi_block_tree_node_initialize";
42
0
  size64_t sub_node_size = 0;
43
44
0
  if( block_tree_node == NULL )
45
0
  {
46
0
    libcerror_error_set(
47
0
     error,
48
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
49
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
50
0
     "%s: invalid block tree node.",
51
0
     function );
52
53
0
    return( -1 );
54
0
  }
55
0
  if( *block_tree_node != NULL )
56
0
  {
57
0
    libcerror_error_set(
58
0
     error,
59
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
60
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
61
0
     "%s: invalid block tree node value already set.",
62
0
     function );
63
64
0
    return( -1 );
65
0
  }
66
0
  if( offset < 0 )
67
0
  {
68
0
    libcerror_error_set(
69
0
     error,
70
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
71
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
72
0
     "%s: invalid offset value out of bounds.",
73
0
     function );
74
75
0
    return( -1 );
76
0
  }
77
0
  if( ( size == 0 )
78
0
   || ( size > (size64_t) ( INT64_MAX - offset ) ) )
79
0
  {
80
0
    libcerror_error_set(
81
0
     error,
82
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
83
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
84
0
     "%s: invalid size value out of bounds.",
85
0
     function );
86
87
0
    return( -1 );
88
0
  }
89
0
  if( leaf_value_size == 0 )
90
0
  {
91
0
    libcerror_error_set(
92
0
     error,
93
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
94
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
95
0
     "%s: invalid leaf value size value out of bounds.",
96
0
     function );
97
98
0
    return( -1 );
99
0
  }
100
0
  *block_tree_node = memory_allocate_structure(
101
0
                      libphdi_block_tree_node_t );
102
103
0
  if( *block_tree_node == NULL )
104
0
  {
105
0
    libcerror_error_set(
106
0
     error,
107
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
108
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
109
0
     "%s: unable to create block tree node.",
110
0
     function );
111
112
0
    goto on_error;
113
0
  }
114
0
  if( memory_set(
115
0
       *block_tree_node,
116
0
       0,
117
0
       sizeof( libphdi_block_tree_node_t ) ) == NULL )
118
0
  {
119
0
    libcerror_error_set(
120
0
     error,
121
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
122
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
123
0
     "%s: unable to clear block tree node.",
124
0
     function );
125
126
0
    memory_free(
127
0
     *block_tree_node );
128
129
0
    *block_tree_node = NULL;
130
131
0
    return( -1 );
132
0
  }
133
0
  if( libcdata_array_initialize(
134
0
       &( ( *block_tree_node )->sub_nodes_array ),
135
0
       LIBPHDI_BLOCK_TREE_NUMBER_OF_SUB_NODES,
136
0
       error ) != 1 )
137
0
  {
138
0
    libcerror_error_set(
139
0
     error,
140
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
141
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
142
0
     "%s: unable to create sub nodes array.",
143
0
     function );
144
145
0
    goto on_error;
146
0
  }
147
0
  sub_node_size = leaf_value_size;
148
149
0
  while( ( size / sub_node_size ) > LIBPHDI_BLOCK_TREE_NUMBER_OF_SUB_NODES )
150
0
  {
151
0
    sub_node_size *= LIBPHDI_BLOCK_TREE_NUMBER_OF_SUB_NODES;
152
0
  }
153
0
  ( *block_tree_node )->start_offset  = offset;
154
0
  ( *block_tree_node )->end_offset    = offset + size;
155
0
  ( *block_tree_node )->size          = size;
156
0
  ( *block_tree_node )->sub_node_size = sub_node_size;
157
158
0
  if( sub_node_size == leaf_value_size )
159
0
  {
160
0
    ( *block_tree_node )->is_leaf_node = 1;
161
0
  }
162
0
  return( 1 );
163
164
0
on_error:
165
0
  if( *block_tree_node != NULL )
166
0
  {
167
0
    memory_free(
168
0
     *block_tree_node );
169
170
0
    *block_tree_node = NULL;
171
0
  }
172
0
  return( -1 );
173
0
}
174
175
/* Frees a block tree node
176
 * Returns 1 if successful or -1 on error
177
 */
178
int libphdi_block_tree_node_free(
179
     libphdi_block_tree_node_t **block_tree_node,
180
     int (*value_free_function)(
181
            intptr_t **value,
182
            libcerror_error_t **error ),
183
     libcerror_error_t **error )
184
0
{
185
0
  libphdi_block_tree_node_t *sub_block_tree_node = NULL;
186
0
  static char *function                          = "libphdi_block_tree_node_free";
187
0
  int result                                     = 1;
188
0
  int sub_node_index                             = 0;
189
190
0
  if( block_tree_node == NULL )
191
0
  {
192
0
    libcerror_error_set(
193
0
     error,
194
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
195
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
196
0
     "%s: invalid block tree node.",
197
0
     function );
198
199
0
    return( -1 );
200
0
  }
201
0
  if( *block_tree_node != NULL )
202
0
  {
203
0
    if( ( *block_tree_node )->is_leaf_node != 0 )
204
0
    {
205
0
      if( libcdata_array_free(
206
0
           &( ( *block_tree_node )->sub_nodes_array ),
207
0
           value_free_function,
208
0
           error ) != 1 )
209
0
      {
210
0
        libcerror_error_set(
211
0
         error,
212
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
213
0
         LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
214
0
         "%s: unable to free sub nodes array.",
215
0
         function );
216
217
0
        result = -1;
218
0
      }
219
0
    }
220
0
    else
221
0
    {
222
0
      for( sub_node_index = 0;
223
0
           sub_node_index < LIBPHDI_BLOCK_TREE_NUMBER_OF_SUB_NODES;
224
0
           sub_node_index++ )
225
0
      {
226
0
        if( libcdata_array_get_entry_by_index(
227
0
             ( *block_tree_node )->sub_nodes_array,
228
0
             sub_node_index,
229
0
             (intptr_t **) &sub_block_tree_node,
230
0
             error ) != 1 )
231
0
        {
232
0
          libcerror_error_set(
233
0
           error,
234
0
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
235
0
           LIBCERROR_RUNTIME_ERROR_GET_FAILED,
236
0
           "%s: unable to retrieve sub node: %d.",
237
0
           function,
238
0
           sub_node_index );
239
240
0
          result = -1;
241
0
        }
242
0
        if( libphdi_block_tree_node_free(
243
0
             &sub_block_tree_node,
244
0
             value_free_function,
245
0
             error ) != 1 )
246
0
        {
247
0
          libcerror_error_set(
248
0
           error,
249
0
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
250
0
           LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
251
0
           "%s: unable to free sub node: %d.",
252
0
           function,
253
0
           sub_node_index );
254
255
0
          result = -1;
256
0
        }
257
0
      }
258
0
      if( libcdata_array_free(
259
0
           &( ( *block_tree_node )->sub_nodes_array ),
260
0
           NULL,
261
0
           error ) != 1 )
262
0
      {
263
0
        libcerror_error_set(
264
0
         error,
265
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
266
0
         LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
267
0
         "%s: unable to free sub nodes array.",
268
0
         function );
269
270
0
        result = -1;
271
0
      }
272
0
    }
273
0
    memory_free(
274
0
     *block_tree_node );
275
276
0
    *block_tree_node = NULL;
277
0
  }
278
0
  return( result );
279
0
}
280
281
/* Retrieves the sub node for a specific offset
282
 * Returns 1 if successful or -1 on error
283
 */
284
int libphdi_block_tree_node_get_sub_node_at_offset(
285
     libphdi_block_tree_node_t *block_tree_node,
286
     off64_t offset,
287
     libphdi_block_tree_node_t **sub_block_tree_node,
288
     libcerror_error_t **error )
289
0
{
290
0
  static char *function  = "libphdi_block_tree_node_get_sub_node_at_offset";
291
0
  off64_t sub_node_index = 0;
292
293
0
  if( block_tree_node == NULL )
294
0
  {
295
0
    libcerror_error_set(
296
0
     error,
297
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
298
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
299
0
     "%s: invalid block tree node.",
300
0
     function );
301
302
0
    return( -1 );
303
0
  }
304
0
  if( block_tree_node->is_leaf_node != 0 )
305
0
  {
306
0
    libcerror_error_set(
307
0
     error,
308
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
309
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
310
0
     "%s: invalid block tree node - not a branch node.",
311
0
     function );
312
313
0
    return( -1 );
314
0
  }
315
0
  if( ( offset < block_tree_node->start_offset )
316
0
   || ( offset >= block_tree_node->end_offset ) )
317
0
  {
318
0
    libcerror_error_set(
319
0
     error,
320
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
321
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
322
0
     "%s: invalid offset value out of bounds.",
323
0
     function );
324
325
0
    return( -1 );
326
0
  }
327
0
  sub_node_index = ( offset - block_tree_node->start_offset ) / block_tree_node->sub_node_size;
328
329
0
  if( ( sub_node_index < 0 )
330
0
   || ( sub_node_index > (off64_t) INT_MAX ) )
331
0
  {
332
0
    libcerror_error_set(
333
0
     error,
334
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
335
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
336
0
     "%s: invalid sub node index value out of bounds.",
337
0
     function );
338
339
0
    return( -1 );
340
0
  }
341
0
  if( libcdata_array_get_entry_by_index(
342
0
       block_tree_node->sub_nodes_array,
343
0
       (int) sub_node_index,
344
0
       (intptr_t **) sub_block_tree_node,
345
0
       error ) != 1 )
346
0
  {
347
0
    libcerror_error_set(
348
0
     error,
349
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
350
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
351
0
     "%s: unable to retrieve sub node: %" PRIi64 ".",
352
0
     function,
353
0
     sub_node_index );
354
355
0
    return( -1 );
356
0
  }
357
0
  return( 1 );
358
0
}
359
360
/* Sets the sub node for a specific offset
361
 * Returns 1 if successful or -1 on error
362
 */
363
int libphdi_block_tree_node_set_sub_node_at_offset(
364
     libphdi_block_tree_node_t *block_tree_node,
365
     off64_t offset,
366
     libphdi_block_tree_node_t *sub_block_tree_node,
367
     libcerror_error_t **error )
368
0
{
369
0
  static char *function  = "libphdi_block_tree_node_set_sub_node_at_offset";
370
0
  off64_t sub_node_index = 0;
371
372
0
  if( block_tree_node == NULL )
373
0
  {
374
0
    libcerror_error_set(
375
0
     error,
376
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
377
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
378
0
     "%s: invalid block tree node.",
379
0
     function );
380
381
0
    return( -1 );
382
0
  }
383
0
  if( block_tree_node->is_leaf_node != 0 )
384
0
  {
385
0
    libcerror_error_set(
386
0
     error,
387
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
388
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
389
0
     "%s: invalid block tree node - not a branch node.",
390
0
     function );
391
392
0
    return( -1 );
393
0
  }
394
0
  if( ( offset < block_tree_node->start_offset )
395
0
   || ( offset >= block_tree_node->end_offset ) )
396
0
  {
397
0
    libcerror_error_set(
398
0
     error,
399
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
400
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
401
0
     "%s: invalid offset value out of bounds.",
402
0
     function );
403
404
0
    return( -1 );
405
0
  }
406
0
  sub_node_index = ( offset - block_tree_node->start_offset ) / block_tree_node->sub_node_size;
407
408
0
  if( ( sub_node_index < 0 )
409
0
   || ( sub_node_index > (off64_t) INT_MAX ) )
410
0
  {
411
0
    libcerror_error_set(
412
0
     error,
413
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
414
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
415
0
     "%s: invalid sub node index value out of bounds.",
416
0
     function );
417
418
0
    return( -1 );
419
0
  }
420
0
  if( libcdata_array_set_entry_by_index(
421
0
       block_tree_node->sub_nodes_array,
422
0
       (int) sub_node_index,
423
0
       (intptr_t *) sub_block_tree_node,
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_SET_FAILED,
430
0
     "%s: unable to set sub node: %" PRIi64 ".",
431
0
     function,
432
0
     sub_node_index );
433
434
0
    return( -1 );
435
0
  }
436
0
  return( 1 );
437
0
}
438
439
/* Retrieves the leaf value for a specific offset
440
 * Returns 1 if successful or -1 on error
441
 */
442
int libphdi_block_tree_node_get_leaf_value_at_offset(
443
     libphdi_block_tree_node_t *block_tree_node,
444
     off64_t offset,
445
     libphdi_block_descriptor_t **block_descriptor,
446
     off64_t *block_offset,
447
     libcerror_error_t **error )
448
0
{
449
0
  static char *function     = "libphdi_block_tree_node_get_leaf_value_at_offset";
450
0
  off64_t leaf_value_index  = 0;
451
0
  off64_t safe_block_offset = 0;
452
453
0
  if( block_tree_node == NULL )
454
0
  {
455
0
    libcerror_error_set(
456
0
     error,
457
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
458
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
459
0
     "%s: invalid block tree node.",
460
0
     function );
461
462
0
    return( -1 );
463
0
  }
464
0
  if( block_tree_node->is_leaf_node == 0 )
465
0
  {
466
0
    libcerror_error_set(
467
0
     error,
468
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
469
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
470
0
     "%s: invalid block tree node - not a leaf node.",
471
0
     function );
472
473
0
    return( -1 );
474
0
  }
475
0
  if( ( offset < block_tree_node->start_offset )
476
0
   || ( offset >= block_tree_node->end_offset ) )
477
0
  {
478
0
    libcerror_error_set(
479
0
     error,
480
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
481
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
482
0
     "%s: invalid offset value out of bounds.",
483
0
     function );
484
485
0
    return( -1 );
486
0
  }
487
0
  if( block_offset == NULL )
488
0
  {
489
0
    libcerror_error_set(
490
0
     error,
491
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
492
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
493
0
     "%s: invalid block offset.",
494
0
     function );
495
496
0
    return( -1 );
497
0
  }
498
0
  safe_block_offset = offset - block_tree_node->start_offset;
499
500
0
  leaf_value_index = safe_block_offset / block_tree_node->sub_node_size;
501
502
0
  if( ( leaf_value_index < 0 )
503
0
   || ( leaf_value_index > (off64_t) INT_MAX ) )
504
0
  {
505
0
    libcerror_error_set(
506
0
     error,
507
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
508
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
509
0
     "%s: invalid leaf value index value out of bounds.",
510
0
     function );
511
512
0
    return( -1 );
513
0
  }
514
0
  if( libcdata_array_get_entry_by_index(
515
0
       block_tree_node->sub_nodes_array,
516
0
       (int) leaf_value_index,
517
0
       (intptr_t **) block_descriptor,
518
0
       error ) != 1 )
519
0
  {
520
0
    libcerror_error_set(
521
0
     error,
522
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
523
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
524
0
     "%s: unable to retrieve leaf value: %" PRIi64 ".",
525
0
     function,
526
0
     leaf_value_index );
527
528
0
    return( -1 );
529
0
  }
530
0
  *block_offset = safe_block_offset - ( leaf_value_index * block_tree_node->sub_node_size );
531
532
0
  return( 1 );
533
0
}
534
535
/* Sets the leaf value for a specific offset
536
 * Returns 1 if successful or -1 on error
537
 */
538
int libphdi_block_tree_node_set_leaf_value_at_offset(
539
     libphdi_block_tree_node_t *block_tree_node,
540
     off64_t offset,
541
     libphdi_block_descriptor_t *block_descriptor,
542
     libcerror_error_t **error )
543
0
{
544
0
  static char *function    = "libphdi_block_tree_node_set_leaf_value_at_offset";
545
0
  off64_t leaf_value_index = 0;
546
547
0
  if( block_tree_node == NULL )
548
0
  {
549
0
    libcerror_error_set(
550
0
     error,
551
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
552
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
553
0
     "%s: invalid block tree node.",
554
0
     function );
555
556
0
    return( -1 );
557
0
  }
558
0
  if( block_tree_node->is_leaf_node == 0 )
559
0
  {
560
0
    libcerror_error_set(
561
0
     error,
562
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
563
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
564
0
     "%s: invalid block tree node - not a leaf node.",
565
0
     function );
566
567
0
    return( -1 );
568
0
  }
569
0
  if( ( offset < block_tree_node->start_offset )
570
0
   || ( offset >= block_tree_node->end_offset ) )
571
0
  {
572
0
    libcerror_error_set(
573
0
     error,
574
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
575
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
576
0
     "%s: invalid offset value out of bounds.",
577
0
     function );
578
579
0
    return( -1 );
580
0
  }
581
0
  leaf_value_index = ( offset - block_tree_node->start_offset ) / block_tree_node->sub_node_size;
582
583
0
  if( ( leaf_value_index < 0 )
584
0
   || ( leaf_value_index > (off64_t) INT_MAX ) )
585
0
  {
586
0
    libcerror_error_set(
587
0
     error,
588
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
589
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
590
0
     "%s: invalid leaf value index value out of bounds.",
591
0
     function );
592
593
0
    return( -1 );
594
0
  }
595
0
  if( libcdata_array_set_entry_by_index(
596
0
       block_tree_node->sub_nodes_array,
597
0
       (int) leaf_value_index,
598
0
       (intptr_t *) block_descriptor,
599
0
       error ) != 1 )
600
0
  {
601
0
    libcerror_error_set(
602
0
     error,
603
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
604
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
605
0
     "%s: unable to set leaf value: %" PRIi64 ".",
606
0
     function,
607
0
     leaf_value_index );
608
609
0
    return( -1 );
610
0
  }
611
0
  return( 1 );
612
0
}
613