Coverage Report

Created: 2026-05-30 07:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libwtcdb/libwtcdb/libwtcdb_file_header.c
Line
Count
Source
1
/*
2
 * File header functions
3
 *
4
 * Copyright (C) 2010-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 <byte_stream.h>
24
#include <memory.h>
25
#include <types.h>
26
27
#include "libwtcdb_debug.h"
28
#include "libwtcdb_definitions.h"
29
#include "libwtcdb_file_header.h"
30
#include "libwtcdb_io_handle.h"
31
#include "libwtcdb_libcerror.h"
32
#include "libwtcdb_libcnotify.h"
33
34
#include "wtcdb_file_header.h"
35
36
/* Creates file header
37
 * Make sure the value file_header is referencing, is set to NULL
38
 * Returns 1 if successful or -1 on error
39
 */
40
int libwtcdb_file_header_initialize(
41
     libwtcdb_file_header_t **file_header,
42
     libcerror_error_t **error )
43
893
{
44
893
  static char *function = "libwtcdb_file_header_initialize";
45
46
893
  if( file_header == 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 file header.",
53
0
     function );
54
55
0
    return( -1 );
56
0
  }
57
893
  if( *file_header != 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 file header value already set.",
64
0
     function );
65
66
0
    return( -1 );
67
0
  }
68
893
  *file_header = memory_allocate_structure(
69
893
                  libwtcdb_file_header_t );
70
71
893
  if( *file_header == NULL )
72
0
  {
73
0
    libcerror_error_set(
74
0
     error,
75
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
76
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
77
0
     "%s: unable to create file header.",
78
0
     function );
79
80
0
    goto on_error;
81
0
  }
82
893
  if( memory_set(
83
893
       *file_header,
84
893
       0,
85
893
       sizeof( libwtcdb_file_header_t ) ) == NULL )
86
0
  {
87
0
    libcerror_error_set(
88
0
     error,
89
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
90
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
91
0
     "%s: unable to clear file header.",
92
0
     function );
93
94
0
    goto on_error;
95
0
  }
96
893
  return( 1 );
97
98
0
on_error:
99
0
  if( *file_header != NULL )
100
0
  {
101
0
    memory_free(
102
0
     *file_header );
103
104
0
    *file_header = NULL;
105
0
  }
106
0
  return( -1 );
107
893
}
108
109
/* Frees file header
110
 * Returns 1 if successful or -1 on error
111
 */
112
int libwtcdb_file_header_free(
113
     libwtcdb_file_header_t **file_header,
114
     libcerror_error_t **error )
115
893
{
116
893
  static char *function = "libwtcdb_file_header_free";
117
118
893
  if( file_header == NULL )
119
0
  {
120
0
    libcerror_error_set(
121
0
     error,
122
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
123
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
124
0
     "%s: invalid file header.",
125
0
     function );
126
127
0
    return( -1 );
128
0
  }
129
893
  if( *file_header != NULL )
130
893
  {
131
893
    memory_free(
132
893
     *file_header );
133
134
893
    *file_header = NULL;
135
893
  }
136
893
  return( 1 );
137
893
}
138
139
/* Reads the file header data
140
 * Returns 1 if successful or -1 on error
141
 */
142
int libwtcdb_file_header_read_data(
143
     libwtcdb_file_header_t *file_header,
144
     const uint8_t *data,
145
     size_t data_size,
146
     libcerror_error_t **error )
147
885
{
148
885
  static char *function         = "libwtcdb_file_header_read_data";
149
885
  size_t file_header_data_size  = 0;
150
885
  uint8_t file_type             = 0;
151
885
  uint8_t number_of_cache_types = 0;
152
153
#if defined( HAVE_DEBUG_OUTPUT )
154
  uint64_t value_64bit          = 0;
155
  uint32_t value_32bit          = 0;
156
#endif
157
158
885
  if( file_header == NULL )
159
0
  {
160
0
    libcerror_error_set(
161
0
     error,
162
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
163
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
164
0
     "%s: invalid file header.",
165
0
     function );
166
167
0
    return( -1 );
168
0
  }
169
885
  if( data == NULL )
170
0
  {
171
0
    libcerror_error_set(
172
0
     error,
173
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
174
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
175
0
     "%s: invalid data.",
176
0
     function );
177
178
0
    return( -1 );
179
0
  }
180
885
  if( ( data_size < 8 )
181
885
   || ( data_size > (size_t) SSIZE_MAX ) )
182
0
  {
183
0
    libcerror_error_set(
184
0
     error,
185
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
186
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
187
0
     "%s: invalid data size value out of bounds.",
188
0
     function );
189
190
0
    return( -1 );
191
0
  }
192
885
  if( memory_compare(
193
885
       data,
194
885
       wtcdb_cache_file_signature,
195
885
       4 ) == 0 )
196
570
  {
197
570
    file_type             = LIBWTCDB_FILE_TYPE_CACHE;
198
570
    file_header_data_size = 24;
199
570
  }
200
315
  else if( memory_compare(
201
315
            data,
202
315
            wtcdb_index_file_signature,
203
315
            4 ) == 0 )
204
174
  {
205
174
    file_type             = LIBWTCDB_FILE_TYPE_INDEX_V20;
206
174
    file_header_data_size = 24;
207
174
  }
208
141
  else if( memory_compare(
209
141
            &( data[ 4 ] ),
210
141
            wtcdb_index_file_signature,
211
141
            4 ) == 0 )
212
103
  {
213
103
    file_type             = LIBWTCDB_FILE_TYPE_INDEX_V30;
214
103
    file_header_data_size = 28;
215
103
  }
216
885
  if( data_size < file_header_data_size )
217
1
  {
218
1
    libcerror_error_set(
219
1
     error,
220
1
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
221
1
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
222
1
     "%s: invalid data size value out of bounds.",
223
1
     function );
224
225
1
    return( -1 );
226
1
  }
227
#if defined( HAVE_DEBUG_OUTPUT )
228
  if( libcnotify_verbose != 0 )
229
  {
230
    libcnotify_printf(
231
     "%s: file header:\n",
232
     function );
233
    libcnotify_print_data(
234
     data,
235
     file_header_data_size,
236
     0 );
237
  }
238
#endif
239
884
  if( file_type == 0 )
240
38
  {
241
38
    libcerror_error_set(
242
38
     error,
243
38
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
244
38
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
245
38
     "%s: unsupported file signature.",
246
38
     function );
247
248
38
    return( -1 );
249
38
  }
250
846
  if( ( file_type == LIBWTCDB_FILE_TYPE_CACHE )
251
276
   || ( file_type == LIBWTCDB_FILE_TYPE_INDEX_V20 ) )
252
744
  {
253
744
    byte_stream_copy_to_uint32_little_endian(
254
744
     &( data[ 4 ] ),
255
744
     file_header->format_version );
256
744
  }
257
102
  else if( file_type == LIBWTCDB_FILE_TYPE_INDEX_V30 )
258
102
  {
259
102
    byte_stream_copy_to_uint32_little_endian(
260
102
     &( data[ 8 ] ),
261
102
     file_header->format_version );
262
102
  }
263
846
  if( file_type == LIBWTCDB_FILE_TYPE_CACHE )
264
570
  {
265
570
    byte_stream_copy_to_uint32_little_endian(
266
570
     ( (wtcdb_cache_file_header_t *) data )->cache_type,
267
570
     file_header->cache_type );
268
269
570
    byte_stream_copy_to_uint32_little_endian(
270
570
     ( (wtcdb_cache_file_header_t *) data )->first_cache_entry_offset,
271
570
     file_header->first_entry_offset );
272
273
570
    byte_stream_copy_to_uint32_little_endian(
274
570
     ( (wtcdb_cache_file_header_t *) data )->available_cache_entry_offset,
275
570
     file_header->available_cache_entry_offset );
276
277
570
    byte_stream_copy_to_uint32_little_endian(
278
570
     ( (wtcdb_cache_file_header_t *) data )->number_of_cache_entries,
279
570
     file_header->number_of_entries );
280
570
  }
281
276
  else if( file_type == LIBWTCDB_FILE_TYPE_INDEX_V20 )
282
174
  {
283
174
    byte_stream_copy_to_uint32_little_endian(
284
174
     ( (wtcdb_index_file_header_v20_t *) data )->number_of_index_entries,
285
174
     file_header->number_of_entries );
286
174
  }
287
102
  else if( file_type == LIBWTCDB_FILE_TYPE_INDEX_V30 )
288
102
  {
289
102
    byte_stream_copy_to_uint32_little_endian(
290
102
     ( (wtcdb_index_file_header_v30_t *) data )->number_of_index_entries,
291
102
     file_header->number_of_entries );
292
102
  }
293
#if defined( HAVE_DEBUG_OUTPUT )
294
  if( libcnotify_verbose != 0 )
295
  {
296
    if( ( file_type == LIBWTCDB_FILE_TYPE_CACHE )
297
     || ( file_type == LIBWTCDB_FILE_TYPE_INDEX_V20 ) )
298
    {
299
      libcnotify_printf(
300
       "%s: signature\t\t\t\t: %c%c%c%c\n",
301
       function,
302
       data[ 0 ],
303
       data[ 1 ],
304
       data[ 2 ],
305
       data[ 3 ] );
306
    }
307
    else if( file_type == LIBWTCDB_FILE_TYPE_INDEX_V30 )
308
    {
309
      byte_stream_copy_to_uint32_little_endian(
310
       ( (wtcdb_index_file_header_v30_t *) data )->unknown1,
311
       value_32bit );
312
      libcnotify_printf(
313
       "%s: unknown1\t\t\t\t: 0x%08" PRIx32 "\n",
314
       function,
315
       value_32bit );
316
317
      libcnotify_printf(
318
       "%s: signature\t\t\t\t: %c%c%c%c\n",
319
       function,
320
       data[ 4 ],
321
       data[ 5 ],
322
       data[ 6 ],
323
       data[ 7 ] );
324
    }
325
    libcnotify_printf(
326
     "%s: format version\t\t\t\t: %" PRIu32 "\n",
327
     function,
328
     file_header->format_version );
329
330
    if( file_type == LIBWTCDB_FILE_TYPE_CACHE )
331
    {
332
      libcnotify_printf(
333
       "%s: cache type\t\t\t\t: %" PRIu32 "\n",
334
       function,
335
       file_header->cache_type );
336
337
      libcnotify_printf(
338
       "%s: first cache entry offset\t\t: 0x%08" PRIx32 "\n",
339
       function,
340
       file_header->first_entry_offset );
341
342
      libcnotify_printf(
343
       "%s: available cache entry offset\t\t: 0x%08" PRIx32 "\n",
344
       function,
345
       file_header->available_cache_entry_offset );
346
347
      libcnotify_printf(
348
       "%s: number of cache entries\t\t\t: %" PRIu32 "\n",
349
       function,
350
       file_header->number_of_entries );
351
    }
352
    else if( file_type == LIBWTCDB_FILE_TYPE_INDEX_V20 )
353
    {
354
      byte_stream_copy_to_uint32_little_endian(
355
       ( (wtcdb_index_file_header_v20_t *) data )->unknown1,
356
       value_32bit );
357
      libcnotify_printf(
358
       "%s: unknown1\t\t\t\t: 0x%08" PRIx32 "\n",
359
       function,
360
       value_32bit );
361
362
      byte_stream_copy_to_uint32_little_endian(
363
       ( (wtcdb_index_file_header_v20_t *) data )->number_of_index_entries_used,
364
       value_32bit );
365
      libcnotify_printf(
366
       "%s: number of index entries used\t\t: %" PRIu32 "\n",
367
       function,
368
       value_32bit );
369
370
      libcnotify_printf(
371
       "%s: number of index entries\t\t\t: %" PRIu32 "\n",
372
       function,
373
       file_header->number_of_entries );
374
375
      byte_stream_copy_to_uint32_little_endian(
376
       ( (wtcdb_index_file_header_v20_t *) data )->unknown2,
377
       value_32bit );
378
      libcnotify_printf(
379
       "%s: unknown2\t\t\t\t: 0x%08" PRIx32 "\n",
380
       function,
381
       value_32bit );
382
    }
383
    else if( file_type == LIBWTCDB_FILE_TYPE_INDEX_V30 )
384
    {
385
      byte_stream_copy_to_uint64_little_endian(
386
       ( (wtcdb_index_file_header_v30_t *) data )->unknown2,
387
       value_64bit );
388
      libcnotify_printf(
389
       "%s: unknown2\t\t\t\t: 0x%08" PRIx64 "\n",
390
       function,
391
       value_64bit );
392
393
      byte_stream_copy_to_uint32_little_endian(
394
       ( (wtcdb_index_file_header_v30_t *) data )->number_of_index_entries_used,
395
       value_32bit );
396
      libcnotify_printf(
397
       "%s: number of index entries used\t\t: %" PRIu32 "\n",
398
       function,
399
       value_32bit );
400
401
      libcnotify_printf(
402
       "%s: number of index entries\t\t\t: %" PRIu32 "\n",
403
       function,
404
       file_header->number_of_entries );
405
    }
406
    libcnotify_printf(
407
     "\n" );
408
  }
409
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
410
411
846
  if( ( file_header->format_version != 20 )
412
783
   && ( file_header->format_version != 21 )
413
225
   && ( file_header->format_version != 30 )
414
187
   && ( file_header->format_version != 31 )
415
115
   && ( file_header->format_version != 32 ) )
416
67
  {
417
67
    libcerror_error_set(
418
67
     error,
419
67
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
420
67
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
421
67
     "%s: unsupported format version: %" PRIu32 ".",
422
67
     function,
423
67
     file_header->format_version );
424
425
67
    return( -1 );
426
67
  }
427
779
  file_header->file_type = file_type;
428
429
779
  if( file_header->file_type == LIBWTCDB_FILE_TYPE_CACHE )
430
541
  {
431
541
    if( ( file_header->format_version == 20 )
432
502
     || ( file_header->format_version == 21 ) )
433
430
    {
434
430
      number_of_cache_types = 5;
435
430
    }
436
111
    else if( file_header->format_version == 30 )
437
21
    {
438
21
      number_of_cache_types = 9;
439
21
    }
440
90
    else if( file_header->format_version == 31 )
441
56
    {
442
56
      number_of_cache_types = 11;
443
56
    }
444
34
    else if( file_header->format_version == 32 )
445
34
    {
446
34
      number_of_cache_types = 14;
447
34
    }
448
541
    if( file_header->cache_type >= number_of_cache_types )
449
52
    {
450
52
      libcerror_error_set(
451
52
       error,
452
52
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
453
52
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
454
52
       "%s: unsupported cache type: %" PRIu32 ".",
455
52
       function,
456
52
       file_header->cache_type );
457
458
52
      return( -1 );
459
52
    }
460
489
    if( file_header->first_entry_offset == 0 )
461
74
    {
462
74
      file_header->first_entry_offset = 24;
463
74
    }
464
415
    else if( file_header->first_entry_offset < 24 )
465
5
    {
466
5
      libcerror_error_set(
467
5
       error,
468
5
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
469
5
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
470
5
       "%s: unsupported first entry offset: %" PRIu32 ".",
471
5
       function,
472
5
       file_header->first_entry_offset );
473
474
5
      return( -1 );
475
5
    }
476
489
  }
477
238
  else if( file_header->file_type == LIBWTCDB_FILE_TYPE_INDEX_V20 )
478
145
  {
479
145
    file_header->first_entry_offset = sizeof( wtcdb_index_file_header_v20_t );
480
145
  }
481
93
  else if( file_header->file_type == LIBWTCDB_FILE_TYPE_INDEX_V30 )
482
93
  {
483
93
    if( file_header->format_version == 30 )
484
1
    {
485
1
      file_header->first_entry_offset = 0x110;
486
1
    }
487
92
    else if( file_header->format_version == 31 )
488
1
    {
489
1
      file_header->first_entry_offset = 0x78;
490
1
    }
491
91
    else if( file_header->format_version == 32 )
492
1
    {
493
1
      file_header->first_entry_offset = 0xd8;
494
1
    }
495
93
  }
496
722
  return( 1 );
497
779
}
498
499
/* Reads the file header
500
 * Returns 1 if successful or -1 on error
501
 */
502
int libwtcdb_file_header_read_file_io_handle(
503
     libwtcdb_file_header_t *file_header,
504
     libbfio_handle_t *file_io_handle,
505
     libcerror_error_t **error )
506
893
{
507
893
  uint8_t file_header_data[ 32 ];
508
509
893
  static char *function = "libwtcdb_file_header_read_file_io_handle";
510
893
  ssize_t read_count    = 0;
511
512
893
  if( file_header == NULL )
513
0
  {
514
0
    libcerror_error_set(
515
0
     error,
516
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
517
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
518
0
     "%s: invalid file header.",
519
0
     function );
520
521
0
    return( -1 );
522
0
  }
523
#if defined( HAVE_DEBUG_OUTPUT )
524
  if( libcnotify_verbose != 0 )
525
  {
526
    libcnotify_printf(
527
     "%s: reading file header at offset: 0 (0x00000000)\n",
528
     function );
529
  }
530
#endif
531
893
  read_count = libbfio_handle_read_buffer_at_offset(
532
893
                file_io_handle,
533
893
                file_header_data,
534
893
                32,
535
893
                0,
536
893
                error );
537
538
893
  if( read_count < (ssize_t) 24 )
539
8
  {
540
8
    libcerror_error_set(
541
8
     error,
542
8
     LIBCERROR_ERROR_DOMAIN_IO,
543
8
     LIBCERROR_IO_ERROR_READ_FAILED,
544
8
     "%s: unable to read file header data at offset: 0 (0x00000000).",
545
8
     function );
546
547
8
    return( -1 );
548
8
  }
549
885
  if( libwtcdb_file_header_read_data(
550
885
       file_header,
551
885
       file_header_data,
552
885
       (size_t) read_count,
553
885
       error ) != 1 )
554
163
  {
555
163
    libcerror_error_set(
556
163
     error,
557
163
     LIBCERROR_ERROR_DOMAIN_IO,
558
163
     LIBCERROR_IO_ERROR_READ_FAILED,
559
163
     "%s: unable to read file header.",
560
163
     function );
561
562
163
    return( -1 );
563
163
  }
564
722
  return( 1 );
565
885
}
566