Coverage Report

Created: 2026-05-30 07:13

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