Coverage Report

Created: 2023-06-07 06:53

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