Coverage Report

Created: 2025-06-22 07:35

/src/libfsxfs/libfsxfs/libfsxfs_btree_block.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * B+ tree block functions
3
 *
4
 * Copyright (C) 2020-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 "libfsxfs_btree_block.h"
27
#include "libfsxfs_io_handle.h"
28
#include "libfsxfs_libbfio.h"
29
#include "libfsxfs_libcerror.h"
30
#include "libfsxfs_libcnotify.h"
31
32
#include "fsxfs_btree.h"
33
34
/* Creates a B+ tree block
35
 * Make sure the value btree_block is referencing, is set to NULL
36
 * Returns 1 if successful or -1 on error
37
 */
38
int libfsxfs_btree_block_initialize(
39
     libfsxfs_btree_block_t **btree_block,
40
     size_t block_size,
41
     size_t block_number_data_size,
42
     libcerror_error_t **error )
43
10.4k
{
44
10.4k
  static char *function = "libfsxfs_btree_block_initialize";
45
46
10.4k
  if( btree_block == NULL )
47
0
  {
48
0
    libcerror_error_set(
49
0
     error,
50
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
51
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
52
0
     "%s: invalid B+ tree block.",
53
0
     function );
54
55
0
    return( -1 );
56
0
  }
57
10.4k
  if( *btree_block != NULL )
58
0
  {
59
0
    libcerror_error_set(
60
0
     error,
61
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
62
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
63
0
     "%s: invalid B+ tree block value already set.",
64
0
     function );
65
66
0
    return( -1 );
67
0
  }
68
10.4k
  if( ( block_size == 0 )
69
10.4k
   || ( block_size > (size_t) MEMORY_MAXIMUM_ALLOCATION_SIZE ) )
70
0
  {
71
0
    libcerror_error_set(
72
0
     error,
73
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
74
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
75
0
     "%s: invalid block size value out of bounds.",
76
0
     function );
77
78
0
    return( -1 );
79
0
  }
80
10.4k
  *btree_block = memory_allocate_structure(
81
10.4k
                  libfsxfs_btree_block_t );
82
83
10.4k
  if( *btree_block == NULL )
84
0
  {
85
0
    libcerror_error_set(
86
0
     error,
87
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
88
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
89
0
     "%s: unable to create B+ tree block.",
90
0
     function );
91
92
0
    goto on_error;
93
0
  }
94
10.4k
  if( memory_set(
95
10.4k
       *btree_block,
96
10.4k
       0,
97
10.4k
       sizeof( libfsxfs_btree_block_t ) ) == NULL )
98
0
  {
99
0
    libcerror_error_set(
100
0
     error,
101
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
102
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
103
0
     "%s: unable to clear B+ tree block.",
104
0
     function );
105
106
0
    memory_free(
107
0
     *btree_block );
108
109
0
    *btree_block = NULL;
110
111
0
    return( -1 );
112
0
  }
113
10.4k
  ( *btree_block )->data = (uint8_t *) memory_allocate(
114
10.4k
                                        sizeof( uint8_t ) * block_size );
115
116
10.4k
  if( ( *btree_block )->data == NULL )
117
0
  {
118
0
    libcerror_error_set(
119
0
     error,
120
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
121
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
122
0
     "%s: unable to create B+ tree block data.",
123
0
     function );
124
125
0
    goto on_error;
126
0
  }
127
10.4k
  ( *btree_block )->data_size              = block_size;
128
10.4k
  ( *btree_block )->block_number_data_size = block_number_data_size;
129
130
10.4k
  return( 1 );
131
132
0
on_error:
133
0
  if( *btree_block != NULL )
134
0
  {
135
0
    memory_free(
136
0
     *btree_block );
137
138
0
    *btree_block = NULL;
139
0
  }
140
0
  return( -1 );
141
10.4k
}
142
143
/* Frees a B+ tree block
144
 * Returns 1 if successful or -1 on error
145
 */
146
int libfsxfs_btree_block_free(
147
     libfsxfs_btree_block_t **btree_block,
148
     libcerror_error_t **error )
149
10.4k
{
150
10.4k
  static char *function = "libfsxfs_btree_block_free";
151
10.4k
  int result            = 1;
152
153
10.4k
  if( btree_block == NULL )
154
0
  {
155
0
    libcerror_error_set(
156
0
     error,
157
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
158
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
159
0
     "%s: invalid B+ tree block.",
160
0
     function );
161
162
0
    return( -1 );
163
0
  }
164
10.4k
  if( *btree_block != NULL )
165
10.4k
  {
166
10.4k
    if( ( *btree_block )->header != NULL )
167
10.1k
    {
168
10.1k
      if( libfsxfs_btree_header_free(
169
10.1k
           &( ( *btree_block )->header ),
170
10.1k
           error ) != 1 )
171
0
      {
172
0
        libcerror_error_set(
173
0
         error,
174
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
175
0
         LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
176
0
         "%s: unable to free B+ tree header.",
177
0
         function );
178
179
0
        result = -1;
180
0
      }
181
10.1k
    }
182
10.4k
    memory_free(
183
10.4k
     ( *btree_block )->data );
184
185
10.4k
    memory_free(
186
10.4k
     *btree_block );
187
188
10.4k
    *btree_block = NULL;
189
10.4k
  }
190
10.4k
  return( result );
191
10.4k
}
192
193
/* Reads the B+ tree block data
194
 * Returns 1 if successful or -1 on error
195
 */
196
int libfsxfs_btree_block_read_data(
197
     libfsxfs_btree_block_t *btree_block,
198
     libfsxfs_io_handle_t *io_handle,
199
     const uint8_t *data,
200
     size_t data_size,
201
     libcerror_error_t **error )
202
10.1k
{
203
10.1k
  static char *function   = "libfsxfs_btree_block_read_data";
204
10.1k
  size_t header_data_size = 0;
205
206
10.1k
  if( btree_block == NULL )
207
0
  {
208
0
    libcerror_error_set(
209
0
     error,
210
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
211
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
212
0
     "%s: invalid B+ tree block.",
213
0
     function );
214
215
0
    return( -1 );
216
0
  }
217
10.1k
  if( btree_block->header != NULL )
218
0
  {
219
0
    libcerror_error_set(
220
0
     error,
221
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
222
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
223
0
     "%s: invalid B+ tree block - header value already set.",
224
0
     function );
225
226
0
    return( -1 );
227
0
  }
228
10.1k
  if( io_handle == NULL )
229
0
  {
230
0
    libcerror_error_set(
231
0
     error,
232
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
233
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
234
0
     "%s: invalid IO handle.",
235
0
     function );
236
237
0
    return( -1 );
238
0
  }
239
10.1k
  if( io_handle->format_version == 5 )
240
4.16k
  {
241
4.16k
    if( btree_block->block_number_data_size == 8 )
242
338
    {
243
338
      header_data_size = sizeof( fsxfs_btree_header_v5_64bit_t );
244
338
    }
245
3.83k
    else
246
3.83k
    {
247
3.83k
      header_data_size = sizeof( fsxfs_btree_header_v5_32bit_t );
248
3.83k
    }
249
4.16k
  }
250
5.96k
  else
251
5.96k
  {
252
5.96k
    if( btree_block->block_number_data_size == 8 )
253
2.54k
    {
254
2.54k
      header_data_size = sizeof( fsxfs_btree_header_v1_64bit_t );
255
2.54k
    }
256
3.41k
    else
257
3.41k
    {
258
3.41k
      header_data_size = sizeof( fsxfs_btree_header_v1_32bit_t );
259
3.41k
    }
260
5.96k
  }
261
10.1k
  if( data == NULL )
262
0
  {
263
0
    libcerror_error_set(
264
0
     error,
265
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
266
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
267
0
     "%s: invalid data.",
268
0
     function );
269
270
0
    return( -1 );
271
0
  }
272
10.1k
  if( ( data_size < header_data_size )
273
10.1k
   || ( data_size > (size_t) SSIZE_MAX ) )
274
0
  {
275
0
    libcerror_error_set(
276
0
     error,
277
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
278
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
279
0
     "%s: invalid data size value out of bounds.",
280
0
     function );
281
282
0
    return( -1 );
283
0
  }
284
10.1k
  if( libfsxfs_btree_header_initialize(
285
10.1k
       &( btree_block->header ),
286
10.1k
       error ) != 1 )
287
0
  {
288
0
    libcerror_error_set(
289
0
     error,
290
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
291
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
292
0
     "%s: unable to create B+ tree header.",
293
0
     function );
294
295
0
    goto on_error;
296
0
  }
297
10.1k
  if( libfsxfs_btree_header_read_data(
298
10.1k
       btree_block->header,
299
10.1k
       io_handle,
300
10.1k
       data,
301
10.1k
       header_data_size,
302
10.1k
       btree_block->block_number_data_size,
303
10.1k
       error ) != 1 )
304
0
  {
305
0
    libcerror_error_set(
306
0
     error,
307
0
     LIBCERROR_ERROR_DOMAIN_IO,
308
0
     LIBCERROR_IO_ERROR_READ_FAILED,
309
0
     "%s: unable to read B+ tree header.",
310
0
     function );
311
312
0
    goto on_error;
313
0
  }
314
10.1k
  btree_block->records_data      = &( data[ header_data_size ] );
315
10.1k
  btree_block->records_data_size = data_size - header_data_size;
316
317
#if defined( HAVE_DEBUG_OUTPUT )
318
  if( libcnotify_verbose != 0 )
319
  {
320
    libcnotify_printf(
321
     "%s: B+ tree records data:\n",
322
     function );
323
    libcnotify_print_data(
324
     btree_block->records_data,
325
     btree_block->records_data_size,
326
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
327
  }
328
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
329
330
10.1k
  return( 1 );
331
332
0
on_error:
333
0
  if( btree_block->header != NULL )
334
0
  {
335
0
    libfsxfs_btree_header_free(
336
0
     &( btree_block->header ),
337
0
     NULL );
338
0
  }
339
0
  return( -1 );
340
10.1k
}
341
342
/* Reads the B+ tree block from a Basic File IO (bfio) handle
343
 * Returns 1 if successful or -1 on error
344
 */
345
int libfsxfs_btree_block_read_file_io_handle(
346
     libfsxfs_btree_block_t *btree_block,
347
     libfsxfs_io_handle_t *io_handle,
348
     libbfio_handle_t *file_io_handle,
349
     off64_t file_offset,
350
     libcerror_error_t **error )
351
10.4k
{
352
10.4k
  static char *function = "libfsxfs_btree_block_read_file_io_handle";
353
10.4k
  ssize_t read_count    = 0;
354
355
10.4k
  if( btree_block == NULL )
356
0
  {
357
0
    libcerror_error_set(
358
0
     error,
359
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
360
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
361
0
     "%s: invalid B+ tree block.",
362
0
     function );
363
364
0
    return( -1 );
365
0
  }
366
10.4k
  if( btree_block->header != NULL )
367
0
  {
368
0
    libcerror_error_set(
369
0
     error,
370
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
371
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
372
0
     "%s: invalid B+ tree block - header value already set.",
373
0
     function );
374
375
0
    return( -1 );
376
0
  }
377
#if defined( HAVE_DEBUG_OUTPUT )
378
  if( libcnotify_verbose != 0 )
379
  {
380
    libcnotify_printf(
381
     "%s: reading B+ tree block at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
382
     function,
383
     file_offset,
384
     file_offset );
385
  }
386
#endif
387
10.4k
  read_count = libbfio_handle_read_buffer_at_offset(
388
10.4k
                file_io_handle,
389
10.4k
                btree_block->data,
390
10.4k
                btree_block->data_size,
391
10.4k
                file_offset,
392
10.4k
                error );
393
394
10.4k
  if( read_count != (ssize_t) btree_block->data_size )
395
329
  {
396
329
    libcerror_error_set(
397
329
     error,
398
329
     LIBCERROR_ERROR_DOMAIN_IO,
399
329
     LIBCERROR_IO_ERROR_READ_FAILED,
400
329
     "%s: unable to read B+ tree block data at offset: %" PRIi64 " (0x%08" PRIx64 ").",
401
329
     function,
402
329
     file_offset,
403
329
     file_offset );
404
405
329
    return( -1 );
406
329
  }
407
10.1k
  if( libfsxfs_btree_block_read_data(
408
10.1k
       btree_block,
409
10.1k
       io_handle,
410
10.1k
       btree_block->data,
411
10.1k
       btree_block->data_size,
412
10.1k
       error ) != 1 )
413
0
  {
414
0
    libcerror_error_set(
415
0
     error,
416
0
     LIBCERROR_ERROR_DOMAIN_IO,
417
0
     LIBCERROR_IO_ERROR_READ_FAILED,
418
0
     "%s: unable to read B+ tree block at offset: %" PRIi64 " (0x%08" PRIx64 ").",
419
0
     function,
420
0
     file_offset,
421
0
     file_offset );
422
423
0
    return( -1 );
424
0
  }
425
10.1k
  return( 1 );
426
10.1k
}
427