Coverage Report

Created: 2026-10-22 07:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libesedb/libesedb/libesedb_database.c
Line
Count
Source
1
/*
2
 * Database functions
3
 *
4
 * Copyright (C) 2009-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 "libesedb_block_descriptor.h"
27
#include "libesedb_block_tree.h"
28
#include "libesedb_database.h"
29
#include "libesedb_debug.h"
30
#include "libesedb_definitions.h"
31
#include "libesedb_libbfio.h"
32
#include "libesedb_libcerror.h"
33
#include "libesedb_libcnotify.h"
34
#include "libesedb_libfcache.h"
35
#include "libesedb_libfdata.h"
36
#include "libesedb_page.h"
37
#include "libesedb_page_value.h"
38
#include "libesedb_page_tree.h"
39
#include "libesedb_page_tree_value.h"
40
41
/* Creates a database
42
 * Make sure the value database is referencing, is set to NULL
43
 * Returns 1 if successful or -1 on error
44
 */
45
int libesedb_database_initialize(
46
     libesedb_database_t **database,
47
     libesedb_io_handle_t *io_handle,
48
     libfdata_vector_t *pages_vector,
49
     libfcache_cache_t *pages_cache,
50
     libcerror_error_t **error )
51
3.31k
{
52
3.31k
  static char *function = "libesedb_database_initialize";
53
54
3.31k
  if( database == NULL )
55
0
  {
56
0
    libcerror_error_set(
57
0
     error,
58
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
59
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
60
0
     "%s: invalid database.",
61
0
     function );
62
63
0
    return( -1 );
64
0
  }
65
3.31k
  if( *database != NULL )
66
0
  {
67
0
    libcerror_error_set(
68
0
     error,
69
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
70
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
71
0
     "%s: invalid database value already set.",
72
0
     function );
73
74
0
    return( -1 );
75
0
  }
76
3.31k
  if( io_handle == NULL )
77
0
  {
78
0
    libcerror_error_set(
79
0
     error,
80
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
81
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
82
0
     "%s: invalid IO handle.",
83
0
     function );
84
85
0
    return( -1 );
86
0
  }
87
3.31k
  *database = memory_allocate_structure(
88
3.31k
               libesedb_database_t );
89
90
3.31k
  if( *database == NULL )
91
0
  {
92
0
    libcerror_error_set(
93
0
     error,
94
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
95
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
96
0
     "%s: unable to create database.",
97
0
     function );
98
99
0
    goto on_error;
100
0
  }
101
3.31k
  if( memory_set(
102
3.31k
       ( *database ),
103
3.31k
       0,
104
3.31k
       sizeof( libesedb_database_t ) ) == NULL )
105
0
  {
106
0
    libcerror_error_set(
107
0
     error,
108
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
109
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
110
0
     "%s: unable to clear database.",
111
0
     function );
112
113
0
    memory_free(
114
0
     *database );
115
116
0
    *database = NULL;
117
118
0
    return( -1 );
119
0
  }
120
3.31k
  if( libesedb_page_tree_initialize(
121
3.31k
       &( ( *database )->page_tree ),
122
3.31k
       io_handle,
123
3.31k
       pages_vector,
124
3.31k
       pages_cache,
125
3.31k
       LIBESEDB_FDP_OBJECT_IDENTIFIER_DATABASE,
126
3.31k
       LIBESEDB_PAGE_NUMBER_DATABASE,
127
3.31k
       NULL,
128
3.31k
       NULL,
129
3.31k
       error ) != 1 )
130
0
  {
131
0
    libcerror_error_set(
132
0
     error,
133
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
134
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
135
0
     "%s: unable to create page tree.",
136
0
     function );
137
138
0
    goto on_error;
139
0
  }
140
3.31k
  if( libesedb_block_tree_initialize(
141
3.31k
       &( ( *database )->page_block_tree ),
142
3.31k
       io_handle->file_size,
143
3.31k
       io_handle->page_size,
144
3.31k
       error ) != 1 )
145
0
  {
146
0
    libcerror_error_set(
147
0
     error,
148
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
149
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
150
0
     "%s: unable to create page block tree.",
151
0
     function );
152
153
0
    goto on_error;
154
0
  }
155
3.31k
  return( 1 );
156
157
0
on_error:
158
0
  if( *database != NULL )
159
0
  {
160
0
    if( ( *database )->page_tree != NULL )
161
0
    {
162
0
      libesedb_page_tree_free(
163
0
       &( ( *database )->page_tree ),
164
0
       NULL );
165
0
    }
166
0
    memory_free(
167
0
     *database );
168
169
0
    *database = NULL;
170
0
  }
171
0
  return( -1 );
172
3.31k
}
173
174
/* Frees a database
175
 * Returns 1 if successful or -1 on error
176
 */
177
int libesedb_database_free(
178
     libesedb_database_t **database,
179
     libcerror_error_t **error )
180
3.42k
{
181
3.42k
  static char *function = "libesedb_database_free";
182
3.42k
  int result            = 1;
183
184
3.42k
  if( database == NULL )
185
0
  {
186
0
    libcerror_error_set(
187
0
     error,
188
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
189
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
190
0
     "%s: invalid database.",
191
0
     function );
192
193
0
    return( -1 );
194
0
  }
195
3.42k
  if( *database != NULL )
196
3.31k
  {
197
3.31k
    if( libesedb_page_tree_free(
198
3.31k
         &( ( *database )->page_tree ),
199
3.31k
         error ) != 1 )
200
0
    {
201
0
      libcerror_error_set(
202
0
       error,
203
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
204
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
205
0
       "%s: unable to free page tree.",
206
0
       function );
207
208
0
      result = -1;
209
0
    }
210
3.31k
    if( libesedb_block_tree_free(
211
3.31k
         &( ( *database )->page_block_tree ),
212
3.31k
         (int (*)(intptr_t **, libcerror_error_t **)) &libesedb_block_descriptor_free,
213
3.31k
         error ) != 1 )
214
0
    {
215
0
      libcerror_error_set(
216
0
       error,
217
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
218
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
219
0
       "%s: unable to free page block tree.",
220
0
       function );
221
222
0
      result = -1;
223
0
    }
224
3.31k
    memory_free(
225
3.31k
     *database );
226
227
3.31k
    *database = NULL;
228
3.31k
  }
229
3.42k
  return( result );
230
3.42k
}
231
232
/* Reads the database values from a leaf page
233
 * Returns 1 if successful or -1 on error
234
 */
235
int libesedb_database_read_values_from_leaf_page(
236
     libesedb_database_t *database,
237
     libesedb_page_t *page,
238
     int *current_leaf_value_index,
239
     libcerror_error_t **error )
240
1.44k
{
241
1.44k
  libesedb_page_tree_value_t *page_tree_value = NULL;
242
1.44k
  libesedb_page_value_t *page_value           = NULL;
243
1.44k
  static char *function                       = "libesedb_database_read_values_from_leaf_page";
244
1.44k
  uint32_t page_flags                         = 0;
245
1.44k
  uint16_t number_of_page_values              = 0;
246
1.44k
  uint16_t page_value_index                   = 0;
247
248
1.44k
  if( database == NULL )
249
0
  {
250
0
    libcerror_error_set(
251
0
     error,
252
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
253
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
254
0
     "%s: invalid database.",
255
0
     function );
256
257
0
    return( -1 );
258
0
  }
259
1.44k
  if( database->page_tree == NULL )
260
0
  {
261
0
    libcerror_error_set(
262
0
     error,
263
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
264
0
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
265
0
     "%s: invalid database - missing page tree.",
266
0
     function );
267
268
0
    return( -1 );
269
0
  }
270
1.44k
  if( current_leaf_value_index == NULL )
271
0
  {
272
0
    libcerror_error_set(
273
0
     error,
274
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
275
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
276
0
     "%s: invalid current leaf value index.",
277
0
     function );
278
279
0
    return( -1 );
280
0
  }
281
1.44k
  if( libesedb_page_get_flags(
282
1.44k
       page,
283
1.44k
       &page_flags,
284
1.44k
       error ) != 1 )
285
0
  {
286
0
    libcerror_error_set(
287
0
     error,
288
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
289
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
290
0
     "%s: unable to retrieve page flags.",
291
0
     function );
292
293
0
    goto on_error;
294
0
  }
295
1.44k
  if( ( page_flags & LIBESEDB_PAGE_FLAG_IS_LEAF ) == 0 )
296
17
  {
297
17
    libcerror_error_set(
298
17
     error,
299
17
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
300
17
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
301
17
     "%s: unsupported page - not a leaf page.",
302
17
     function );
303
304
17
    goto on_error;
305
17
  }
306
1.43k
  if( libesedb_page_get_number_of_values(
307
1.43k
       page,
308
1.43k
       &number_of_page_values,
309
1.43k
       error ) != 1 )
310
0
  {
311
0
    libcerror_error_set(
312
0
     error,
313
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
314
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
315
0
     "%s: unable to retrieve number of page values.",
316
0
     function );
317
318
0
    goto on_error;
319
0
  }
320
1.43k
  for( page_value_index = 1;
321
58.0k
       page_value_index < number_of_page_values;
322
56.5k
       page_value_index++ )
323
56.6k
  {
324
56.6k
    if( libesedb_page_get_value_by_index(
325
56.6k
         page,
326
56.6k
         page_value_index,
327
56.6k
         &page_value,
328
56.6k
         error ) != 1 )
329
0
    {
330
0
      libcerror_error_set(
331
0
       error,
332
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
333
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
334
0
       "%s: unable to retrieve page value: %" PRIu16 ".",
335
0
       function,
336
0
       page_value_index );
337
338
0
      goto on_error;
339
0
    }
340
56.6k
    if( page_value == NULL )
341
0
    {
342
0
      libcerror_error_set(
343
0
       error,
344
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
345
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
346
0
       "%s: missing page value: %" PRIu16 ".",
347
0
       function,
348
0
       page_value_index );
349
350
0
      goto on_error;
351
0
    }
352
#if defined( HAVE_DEBUG_OUTPUT )
353
    if( libcnotify_verbose != 0 )
354
    {
355
      libcnotify_printf(
356
       "%s: page value: %03" PRIu16 " page tag flags\t\t: 0x%02" PRIx8 "",
357
       function,
358
       page_value_index,
359
       page_value->flags );
360
      libesedb_debug_print_page_tag_flags(
361
       page_value->flags );
362
      libcnotify_printf(
363
       "\n" );
364
    }
365
#endif
366
56.6k
    if( ( page_value->flags & LIBESEDB_PAGE_TAG_FLAG_IS_DEFUNCT ) != 0 )
367
3.53k
    {
368
3.53k
      continue;
369
3.53k
    }
370
53.1k
    if( libesedb_page_tree_value_initialize(
371
53.1k
         &page_tree_value,
372
53.1k
         error ) != 1 )
373
0
    {
374
0
      libcerror_error_set(
375
0
       error,
376
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
377
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
378
0
       "%s: unable to create page tree value.",
379
0
       function );
380
381
0
      goto on_error;
382
0
    }
383
53.1k
    if( libesedb_page_tree_value_read_data(
384
53.1k
         page_tree_value,
385
53.1k
         page_value->data,
386
53.1k
         (size_t) page_value->size,
387
53.1k
         page_value->flags,
388
53.1k
         error ) != 1 )
389
62
    {
390
62
      libcerror_error_set(
391
62
       error,
392
62
       LIBCERROR_ERROR_DOMAIN_IO,
393
62
       LIBCERROR_IO_ERROR_READ_FAILED,
394
62
       "%s: unable to read page tree value: %" PRIu16 ".",
395
62
       function,
396
62
       page_value_index );
397
398
62
      goto on_error;
399
62
    }
400
/* TODO implement */
401
402
#if defined( HAVE_DEBUG_OUTPUT )
403
    if( libcnotify_verbose != 0 )
404
    {
405
      libcnotify_printf(
406
       "%s: database value: %d data:\n",
407
       function,
408
       *current_leaf_value_index );
409
      libcnotify_print_data(
410
       page_tree_value->data,
411
       page_tree_value->data_size,
412
       0 );
413
    }
414
#endif
415
53.0k
    if( *current_leaf_value_index == INT_MAX )
416
0
    {
417
0
      libcerror_error_set(
418
0
       error,
419
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
420
0
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
421
0
       "%s: invalid current leaf value index value out of bounds.",
422
0
       function );
423
424
0
      goto on_error;
425
0
    }
426
53.0k
    *current_leaf_value_index += 1;
427
428
53.0k
    if( libesedb_page_tree_value_free(
429
53.0k
         &page_tree_value,
430
53.0k
         error ) != 1 )
431
0
    {
432
0
      libcerror_error_set(
433
0
       error,
434
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
435
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
436
0
       "%s: unable to free page tree value.",
437
0
       function );
438
439
0
      goto on_error;
440
0
    }
441
53.0k
  }
442
1.36k
  return( 1 );
443
444
79
on_error:
445
79
  if( page_tree_value != NULL )
446
62
  {
447
62
    libesedb_page_tree_value_free(
448
62
     &page_tree_value,
449
62
     NULL );
450
62
  }
451
79
  return( -1 );
452
1.43k
}
453
454
/* Reads the database
455
 * Returns 1 if successful or -1 on error
456
 */
457
int libesedb_database_read_file_io_handle(
458
     libesedb_database_t *database,
459
     libbfio_handle_t *file_io_handle,
460
     libcerror_error_t **error )
461
3.31k
{
462
3.31k
  libesedb_page_t *page        = NULL;
463
3.31k
  static char *function        = "libesedb_database_read_file_io_handle";
464
3.31k
  off64_t page_offset          = 0;
465
3.31k
  uint32_t leaf_page_number    = 0;
466
3.31k
  int current_leaf_value_index = 0;
467
468
3.31k
  if( database == NULL )
469
0
  {
470
0
    libcerror_error_set(
471
0
     error,
472
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
473
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
474
0
     "%s: invalid database.",
475
0
     function );
476
477
0
    return( -1 );
478
0
  }
479
3.31k
  if( database->page_tree == NULL )
480
0
  {
481
0
    libcerror_error_set(
482
0
     error,
483
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
484
0
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
485
0
     "%s: invalid database - missing page tree.",
486
0
     function );
487
488
0
    return( -1 );
489
0
  }
490
3.31k
  if( database->page_tree->io_handle == NULL )
491
0
  {
492
0
    libcerror_error_set(
493
0
     error,
494
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
495
0
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
496
0
     "%s: invalid database - invalid page tree - missing IO handle.",
497
0
     function );
498
499
0
    return( -1 );
500
0
  }
501
3.31k
  if( libesedb_page_tree_get_get_first_leaf_page_number(
502
3.31k
       database->page_tree,
503
3.31k
       file_io_handle,
504
3.31k
       &leaf_page_number,
505
3.31k
       error ) != 1 )
506
1.40k
  {
507
1.40k
    libcerror_error_set(
508
1.40k
     error,
509
1.40k
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
510
1.40k
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
511
1.40k
     "%s: unable to retrieve first leaf page number from page tree.",
512
1.40k
     function );
513
514
1.40k
    return( -1 );
515
1.40k
  }
516
3.27k
  while( leaf_page_number != 0 )
517
1.80k
  {
518
1.80k
    page_offset = ( leaf_page_number + 1 ) * database->page_tree->io_handle->page_size;
519
520
1.80k
    if( libesedb_page_tree_check_if_page_block_first_read(
521
1.80k
         database->page_tree,
522
1.80k
         database->page_block_tree,
523
1.80k
         leaf_page_number,
524
1.80k
         page_offset,
525
1.80k
         error ) != 1 )
526
217
    {
527
217
      libcerror_error_set(
528
217
       error,
529
217
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
530
217
       LIBCERROR_RUNTIME_ERROR_GENERIC,
531
217
       "%s: unable to check if first read of page number: %" PRIu32 ".",
532
217
       function,
533
217
       leaf_page_number );
534
535
217
      return( -1 );
536
217
    }
537
1.59k
#if ( SIZEOF_INT <= 4 )
538
1.59k
    if( leaf_page_number > (uint32_t) INT_MAX )
539
#else
540
    if( leaf_page_number > (unsigned int) INT_MAX )
541
#endif
542
46
    {
543
46
      libcerror_error_set(
544
46
       error,
545
46
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
546
46
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
547
46
       "%s: invalid leaf page number value out of bounds.",
548
46
       function );
549
550
46
      return( -1 );
551
46
    }
552
1.54k
    if( libfdata_vector_get_element_value_by_index(
553
1.54k
         database->page_tree->pages_vector,
554
1.54k
         (intptr_t *) file_io_handle,
555
1.54k
         (libfdata_cache_t *) database->page_tree->pages_cache,
556
1.54k
         (int) leaf_page_number - 1,
557
1.54k
         (intptr_t **) &page,
558
1.54k
         0,
559
1.54k
         error ) != 1 )
560
98
    {
561
98
      libcerror_error_set(
562
98
       error,
563
98
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
564
98
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
565
98
       "%s: unable to retrieve page: %" PRIu32 ".",
566
98
       function,
567
98
       leaf_page_number );
568
569
98
      return( -1 );
570
98
    }
571
1.44k
    if( libesedb_database_read_values_from_leaf_page(
572
1.44k
         database,
573
1.44k
         page,
574
1.44k
         &current_leaf_value_index,
575
1.44k
         error ) != 1 )
576
79
    {
577
79
      libcerror_error_set(
578
79
       error,
579
79
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
580
79
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
581
79
       "%s: unable to read values from page: %" PRIu32 ".",
582
79
       function,
583
79
       leaf_page_number );
584
585
79
      return( -1 );
586
79
    }
587
1.36k
    if( libesedb_page_get_next_page_number(
588
1.36k
         page,
589
1.36k
         &leaf_page_number,
590
1.36k
         error ) != 1 )
591
0
    {
592
0
      libcerror_error_set(
593
0
       error,
594
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
595
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
596
0
       "%s: unable to retrieve next page number from page: %" PRIu32 ".",
597
0
       function,
598
0
       leaf_page_number );
599
600
0
      return( -1 );
601
0
    }
602
1.36k
  }
603
1.46k
  return( 1 );
604
1.90k
}
605