Coverage Report

Created: 2026-03-05 07:45

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-2025, 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
4.59k
{
52
4.59k
  static char *function = "libesedb_database_initialize";
53
54
4.59k
  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
4.59k
  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
4.59k
  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
4.59k
  *database = memory_allocate_structure(
88
4.59k
               libesedb_database_t );
89
90
4.59k
  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
4.59k
  if( memory_set(
102
4.59k
       ( *database ),
103
4.59k
       0,
104
4.59k
       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
4.59k
  if( libesedb_page_tree_initialize(
121
4.59k
       &( ( *database )->page_tree ),
122
4.59k
       io_handle,
123
4.59k
       pages_vector,
124
4.59k
       pages_cache,
125
4.59k
       LIBESEDB_FDP_OBJECT_IDENTIFIER_DATABASE,
126
4.59k
       LIBESEDB_PAGE_NUMBER_DATABASE,
127
4.59k
       NULL,
128
4.59k
       NULL,
129
4.59k
       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
4.59k
  if( libesedb_block_tree_initialize(
141
4.59k
       &( ( *database )->page_block_tree ),
142
4.59k
       io_handle->file_size,
143
4.59k
       io_handle->page_size,
144
4.59k
       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
4.59k
  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
4.59k
}
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
4.74k
{
181
4.74k
  static char *function = "libesedb_database_free";
182
4.74k
  int result            = 1;
183
184
4.74k
  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
4.74k
  if( *database != NULL )
196
4.59k
  {
197
4.59k
    if( libesedb_page_tree_free(
198
4.59k
         &( ( *database )->page_tree ),
199
4.59k
         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
4.59k
    if( libesedb_block_tree_free(
211
4.59k
         &( ( *database )->page_block_tree ),
212
4.59k
         (int (*)(intptr_t **, libcerror_error_t **)) &libesedb_block_descriptor_free,
213
4.59k
         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
4.59k
    memory_free(
225
4.59k
     *database );
226
227
4.59k
    *database = NULL;
228
4.59k
  }
229
4.74k
  return( result );
230
4.74k
}
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
2.02k
{
241
2.02k
  libesedb_page_tree_value_t *page_tree_value = NULL;
242
2.02k
  libesedb_page_value_t *page_value           = NULL;
243
2.02k
  static char *function                       = "libesedb_database_read_values_from_leaf_page";
244
2.02k
  uint32_t page_flags                         = 0;
245
2.02k
  uint16_t number_of_page_values              = 0;
246
2.02k
  uint16_t page_value_index                   = 0;
247
248
2.02k
  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
2.02k
  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
2.02k
  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
2.02k
  if( libesedb_page_get_flags(
282
2.02k
       page,
283
2.02k
       &page_flags,
284
2.02k
       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
2.02k
  if( ( page_flags & LIBESEDB_PAGE_FLAG_IS_LEAF ) == 0 )
296
69
  {
297
69
    libcerror_error_set(
298
69
     error,
299
69
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
300
69
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
301
69
     "%s: unsupported page - not a leaf page.",
302
69
     function );
303
304
69
    goto on_error;
305
69
  }
306
1.95k
  if( libesedb_page_get_number_of_values(
307
1.95k
       page,
308
1.95k
       &number_of_page_values,
309
1.95k
       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.95k
  for( page_value_index = 1;
321
71.0k
       page_value_index < number_of_page_values;
322
69.0k
       page_value_index++ )
323
69.1k
  {
324
69.1k
    if( libesedb_page_get_value_by_index(
325
69.1k
         page,
326
69.1k
         page_value_index,
327
69.1k
         &page_value,
328
69.1k
         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
69.1k
    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
69.1k
    if( ( page_value->flags & LIBESEDB_PAGE_TAG_FLAG_IS_DEFUNCT ) != 0 )
367
3.69k
    {
368
3.69k
      continue;
369
3.69k
    }
370
65.4k
    if( libesedb_page_tree_value_initialize(
371
65.4k
         &page_tree_value,
372
65.4k
         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
65.4k
    if( libesedb_page_tree_value_read_data(
384
65.4k
         page_tree_value,
385
65.4k
         page_value->data,
386
65.4k
         (size_t) page_value->size,
387
65.4k
         page_value->flags,
388
65.4k
         error ) != 1 )
389
65
    {
390
65
      libcerror_error_set(
391
65
       error,
392
65
       LIBCERROR_ERROR_DOMAIN_IO,
393
65
       LIBCERROR_IO_ERROR_READ_FAILED,
394
65
       "%s: unable to read page tree value: %" PRIu16 ".",
395
65
       function,
396
65
       page_value_index );
397
398
65
      goto on_error;
399
65
    }
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
65.3k
    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
65.3k
    *current_leaf_value_index += 1;
427
428
65.3k
    if( libesedb_page_tree_value_free(
429
65.3k
         &page_tree_value,
430
65.3k
         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
65.3k
  }
442
1.89k
  return( 1 );
443
444
134
on_error:
445
134
  if( page_tree_value != NULL )
446
65
  {
447
65
    libesedb_page_tree_value_free(
448
65
     &page_tree_value,
449
65
     NULL );
450
65
  }
451
134
  return( -1 );
452
1.95k
}
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
4.59k
{
462
4.59k
  libesedb_page_t *page        = NULL;
463
4.59k
  static char *function        = "libesedb_database_read_file_io_handle";
464
4.59k
  off64_t page_offset          = 0;
465
4.59k
  uint32_t leaf_page_number    = 0;
466
4.59k
  int current_leaf_value_index = 0;
467
468
4.59k
  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
4.59k
  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
4.59k
  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
4.59k
  if( libesedb_page_tree_get_get_first_leaf_page_number(
502
4.59k
       database->page_tree,
503
4.59k
       file_io_handle,
504
4.59k
       &leaf_page_number,
505
4.59k
       error ) != 1 )
506
1.71k
  {
507
1.71k
    libcerror_error_set(
508
1.71k
     error,
509
1.71k
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
510
1.71k
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
511
1.71k
     "%s: unable to retrieve first leaf page number from page tree.",
512
1.71k
     function );
513
514
1.71k
    return( -1 );
515
1.71k
  }
516
4.76k
  while( leaf_page_number != 0 )
517
2.48k
  {
518
2.48k
    page_offset = ( leaf_page_number + 1 ) * database->page_tree->io_handle->page_size;
519
520
2.48k
    if( libesedb_page_tree_check_if_page_block_first_read(
521
2.48k
         database->page_tree,
522
2.48k
         database->page_block_tree,
523
2.48k
         leaf_page_number,
524
2.48k
         page_offset,
525
2.48k
         error ) != 1 )
526
238
    {
527
238
      libcerror_error_set(
528
238
       error,
529
238
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
530
238
       LIBCERROR_RUNTIME_ERROR_GENERIC,
531
238
       "%s: unable to check if first read of page number: %" PRIu32 ".",
532
238
       function,
533
238
       leaf_page_number );
534
535
238
      return( -1 );
536
238
    }
537
2.24k
#if ( SIZEOF_INT <= 4 )
538
2.24k
    if( leaf_page_number > (uint32_t) INT_MAX )
539
#else
540
    if( leaf_page_number > (unsigned int) INT_MAX )
541
#endif
542
82
    {
543
82
      libcerror_error_set(
544
82
       error,
545
82
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
546
82
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
547
82
       "%s: invalid leaf page number value out of bounds.",
548
82
       function );
549
550
82
      return( -1 );
551
82
    }
552
2.16k
    if( libfdata_vector_get_element_value_by_index(
553
2.16k
         database->page_tree->pages_vector,
554
2.16k
         (intptr_t *) file_io_handle,
555
2.16k
         (libfdata_cache_t *) database->page_tree->pages_cache,
556
2.16k
         (int) leaf_page_number - 1,
557
2.16k
         (intptr_t **) &page,
558
2.16k
         0,
559
2.16k
         error ) != 1 )
560
138
    {
561
138
      libcerror_error_set(
562
138
       error,
563
138
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
564
138
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
565
138
       "%s: unable to retrieve page: %" PRIu32 ".",
566
138
       function,
567
138
       leaf_page_number );
568
569
138
      return( -1 );
570
138
    }
571
2.02k
    if( libesedb_database_read_values_from_leaf_page(
572
2.02k
         database,
573
2.02k
         page,
574
2.02k
         &current_leaf_value_index,
575
2.02k
         error ) != 1 )
576
134
    {
577
134
      libcerror_error_set(
578
134
       error,
579
134
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
580
134
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
581
134
       "%s: unable to read values from page: %" PRIu32 ".",
582
134
       function,
583
134
       leaf_page_number );
584
585
134
      return( -1 );
586
134
    }
587
1.89k
    if( libesedb_page_get_next_page_number(
588
1.89k
         page,
589
1.89k
         &leaf_page_number,
590
1.89k
         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.89k
  }
603
2.28k
  return( 1 );
604
2.87k
}
605