Coverage Report

Created: 2025-06-22 07:35

/src/libmsiecf/libmsiecf/libmsiecf_file_header.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * File header functions
3
 *
4
 * Copyright (C) 2009-2024, 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 "libmsiecf_file_header.h"
28
#include "libmsiecf_libbfio.h"
29
#include "libmsiecf_libcerror.h"
30
#include "libmsiecf_libcnotify.h"
31
32
#include "msiecf_file_header.h"
33
34
/* Creates a file header
35
 * Make sure the value file_header is referencing, is set to NULL
36
 * Returns 1 if successful or -1 on error
37
 */
38
int libmsiecf_file_header_initialize(
39
     libmsiecf_file_header_t **file_header,
40
     libcerror_error_t **error )
41
3.34k
{
42
3.34k
  static char *function = "libmsiecf_file_header_initialize";
43
44
3.34k
  if( file_header == NULL )
45
0
  {
46
0
    libcerror_error_set(
47
0
     error,
48
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
49
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
50
0
     "%s: invalid file header.",
51
0
     function );
52
53
0
    return( -1 );
54
0
  }
55
3.34k
  if( *file_header != NULL )
56
0
  {
57
0
    libcerror_error_set(
58
0
     error,
59
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
60
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
61
0
     "%s: invalid file header value already set.",
62
0
     function );
63
64
0
    return( -1 );
65
0
  }
66
3.34k
  *file_header = memory_allocate_structure(
67
3.34k
                  libmsiecf_file_header_t );
68
69
3.34k
  if( *file_header == NULL )
70
0
  {
71
0
    libcerror_error_set(
72
0
     error,
73
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
74
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
75
0
     "%s: unable to create file header.",
76
0
     function );
77
78
0
    goto on_error;
79
0
  }
80
3.34k
  if( memory_set(
81
3.34k
       *file_header,
82
3.34k
       0,
83
3.34k
       sizeof( libmsiecf_file_header_t ) ) == NULL )
84
0
  {
85
0
    libcerror_error_set(
86
0
     error,
87
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
88
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
89
0
     "%s: unable to clear file header.",
90
0
     function );
91
92
0
    goto on_error;
93
0
  }
94
3.34k
  return( 1 );
95
96
0
on_error:
97
0
  if( *file_header != NULL )
98
0
  {
99
0
    memory_free(
100
0
     *file_header );
101
102
0
    *file_header = NULL;
103
0
  }
104
0
  return( -1 );
105
3.34k
}
106
107
/* Frees a file header
108
 * Returns 1 if successful or -1 on error
109
 */
110
int libmsiecf_file_header_free(
111
     libmsiecf_file_header_t **file_header,
112
     libcerror_error_t **error )
113
3.34k
{
114
3.34k
  static char *function = "libmsiecf_file_header_free";
115
116
3.34k
  if( file_header == NULL )
117
0
  {
118
0
    libcerror_error_set(
119
0
     error,
120
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
121
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
122
0
     "%s: invalid file header.",
123
0
     function );
124
125
0
    return( -1 );
126
0
  }
127
3.34k
  if( *file_header != NULL )
128
3.34k
  {
129
3.34k
    memory_free(
130
3.34k
     *file_header );
131
132
3.34k
    *file_header = NULL;
133
3.34k
  }
134
3.34k
  return( 1 );
135
3.34k
}
136
137
/* Reads the file header data
138
 * Returns 1 if successful or -1 on error
139
 */
140
int libmsiecf_file_header_read_data(
141
     libmsiecf_file_header_t *file_header,
142
     const uint8_t *data,
143
     size_t data_size,
144
     libcerror_error_t **error )
145
3.31k
{
146
3.31k
  static char *function = "libmsiecf_file_header_read_data";
147
148
#if defined( HAVE_DEBUG_OUTPUT )
149
  uint32_t value_32bit  = 0;
150
#endif
151
152
3.31k
  if( file_header == NULL )
153
0
  {
154
0
    libcerror_error_set(
155
0
     error,
156
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
157
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
158
0
     "%s: invalid file header.",
159
0
     function );
160
161
0
    return( -1 );
162
0
  }
163
3.31k
  if( data == NULL )
164
0
  {
165
0
    libcerror_error_set(
166
0
     error,
167
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
168
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
169
0
     "%s: invalid data.",
170
0
     function );
171
172
0
    return( -1 );
173
0
  }
174
3.31k
  if( ( data_size < sizeof( msiecf_file_header_t ) )
175
3.31k
   || ( data_size > (size_t) SSIZE_MAX ) )
176
0
  {
177
0
    libcerror_error_set(
178
0
     error,
179
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
180
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
181
0
     "%s: invalid data size value out of bounds.",
182
0
     function );
183
184
0
    return( -1 );
185
0
  }
186
#if defined( HAVE_DEBUG_OUTPUT )
187
  if( libcnotify_verbose != 0 )
188
  {
189
    libcnotify_printf(
190
     "%s: file header data:\n",
191
     function );
192
    libcnotify_print_data(
193
     data,
194
     sizeof( msiecf_file_header_t ),
195
     0 );
196
  }
197
#endif
198
3.31k
  if( ( ( (msiecf_file_header_t *) data )->signature[ 27 ] != 0 )
199
3.31k
   || ( ( (msiecf_file_header_t *) data )->signature[ 26 ] < (uint8_t) '0' )
200
3.31k
   || ( ( (msiecf_file_header_t *) data )->signature[ 26 ] > (uint8_t) '9' )
201
3.31k
   || ( ( (msiecf_file_header_t *) data )->signature[ 25 ] != (uint8_t) '.' )
202
3.31k
   || ( ( (msiecf_file_header_t *) data )->signature[ 24 ] < (uint8_t) '0' )
203
3.31k
   || ( ( (msiecf_file_header_t *) data )->signature[ 24 ] > (uint8_t) '9' )
204
3.31k
   || ( memory_compare(
205
3.22k
         ( (msiecf_file_header_t *) data )->signature,
206
3.22k
         "Client UrlCache MMF Ver ",
207
3.22k
         24 ) != 0 ) )
208
337
  {
209
337
    libcerror_error_set(
210
337
     error,
211
337
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
212
337
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
213
337
     "%s: invalid file signature.",
214
337
     function );
215
216
337
    return( -1 );
217
337
  }
218
2.97k
  file_header->major_version = ( (msiecf_file_header_t *) data )->signature[ 24 ] - (uint8_t) '0';
219
2.97k
  file_header->minor_version = ( (msiecf_file_header_t *) data )->signature[ 26 ] - (uint8_t) '0';
220
221
2.97k
  byte_stream_copy_to_uint32_little_endian(
222
2.97k
   ( (msiecf_file_header_t *) data )->file_size,
223
2.97k
   file_header->file_size );
224
225
2.97k
  byte_stream_copy_to_uint32_little_endian(
226
2.97k
   ( (msiecf_file_header_t *) data )->hash_table_offset,
227
2.97k
   file_header->hash_table_offset );
228
229
2.97k
  byte_stream_copy_to_uint32_little_endian(
230
2.97k
   ( (msiecf_file_header_t *) data )->number_of_blocks,
231
2.97k
   file_header->number_of_blocks );
232
233
2.97k
  byte_stream_copy_to_uint32_little_endian(
234
2.97k
   ( (msiecf_file_header_t *) data )->number_of_allocated_blocks,
235
2.97k
   file_header->number_of_allocated_blocks );
236
237
#if defined( HAVE_DEBUG_OUTPUT )
238
  if( libcnotify_verbose != 0 )
239
  {
240
    libcnotify_printf(
241
     "%s: signature\t\t\t\t: %s\n",
242
     function,
243
     ( (msiecf_file_header_t *) data )->signature );
244
245
    libcnotify_printf(
246
     "%s: file size\t\t\t\t: %" PRIu32 "\n",
247
     function,
248
     file_header->file_size );
249
250
    libcnotify_printf(
251
     "%s: hash table offset\t\t\t: %" PRIu32 " (0x%08" PRIx32 ")\n",
252
     function,
253
     file_header->hash_table_offset,
254
     file_header->hash_table_offset );
255
256
    libcnotify_printf(
257
     "%s: number of blocks\t\t\t: %" PRIu32 "\n",
258
     function,
259
     file_header->number_of_blocks );
260
261
    libcnotify_printf(
262
     "%s: number of allocated blocks\t\t: %" PRIu32 "\n",
263
     function,
264
     file_header->number_of_allocated_blocks );
265
266
    byte_stream_copy_to_uint32_little_endian(
267
     ( (msiecf_file_header_t *) data )->unknown1,
268
     value_32bit );
269
    libcnotify_printf(
270
     "%s: unknown1\t\t\t\t: 0x%08" PRIx32 "\n",
271
     function,
272
     value_32bit );
273
274
    byte_stream_copy_to_uint32_little_endian(
275
     ( (msiecf_file_header_t *) data )->cache_size_limit,
276
     value_32bit );
277
    libcnotify_printf(
278
     "%s: cache size limit\t\t\t: %" PRIu32 " bytes\n",
279
     function,
280
     value_32bit );
281
282
    byte_stream_copy_to_uint32_little_endian(
283
     ( (msiecf_file_header_t *) data )->unknown2,
284
     value_32bit );
285
    libcnotify_printf(
286
     "%s: unknown2\t\t\t\t: 0x%08" PRIx32 "\n",
287
     function,
288
     value_32bit );
289
290
    byte_stream_copy_to_uint32_little_endian(
291
     ( (msiecf_file_header_t *) data )->cache_size,
292
     value_32bit );
293
    libcnotify_printf(
294
     "%s: cache size\t\t\t\t: %" PRIu32 " bytes\n",
295
     function,
296
     value_32bit );
297
298
    byte_stream_copy_to_uint32_little_endian(
299
     ( (msiecf_file_header_t *) data )->unknown3,
300
     value_32bit );
301
    libcnotify_printf(
302
     "%s: unknown3\t\t\t\t: 0x%08" PRIx32 "\n",
303
     function,
304
     value_32bit );
305
306
    byte_stream_copy_to_uint32_little_endian(
307
     ( (msiecf_file_header_t *) data )->non_releasable_cache_size,
308
     value_32bit );
309
    libcnotify_printf(
310
     "%s: non-releasable cache size\t\t: %" PRIu32 " bytes\n",
311
     function,
312
     value_32bit );
313
314
    byte_stream_copy_to_uint32_little_endian(
315
     ( (msiecf_file_header_t *) data )->unknown4,
316
     value_32bit );
317
    libcnotify_printf(
318
     "%s: unknown4\t\t\t\t: 0x%08" PRIx32 "\n",
319
     function,
320
     value_32bit );
321
322
    libcnotify_printf(
323
     "\n" );
324
  }
325
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
326
327
2.97k
  if( ! ( ( ( file_header->major_version == 4 )
328
2.97k
    &&      ( file_header->minor_version == 7 ) )
329
2.97k
   ||     ( ( file_header->major_version == 5 )
330
2.96k
    &&      ( file_header->minor_version == 2 ) ) ) )
331
24
  {
332
24
    libcerror_error_set(
333
24
     error,
334
24
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
335
24
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
336
24
     "%s: unsupported format version: %d.%d.",
337
24
     function,
338
24
     file_header->major_version,
339
24
     file_header->minor_version );
340
341
24
    return( -1 );
342
24
  }
343
2.95k
  return( 1 );
344
2.97k
}
345
346
/* Reads the file header
347
 * Returns 1 if successful or -1 on error
348
 */
349
int libmsiecf_file_header_read_file_io_handle(
350
     libmsiecf_file_header_t *file_header,
351
     libbfio_handle_t *file_io_handle,
352
     off64_t file_offset,
353
     libcerror_error_t **error )
354
3.34k
{
355
3.34k
  uint8_t file_header_data[ sizeof( msiecf_file_header_t ) ];
356
357
3.34k
  static char *function = "libmsiecf_file_header_read_file_io_handle";
358
3.34k
  ssize_t read_count    = 0;
359
360
3.34k
  if( file_header == NULL )
361
0
  {
362
0
    libcerror_error_set(
363
0
     error,
364
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
365
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
366
0
     "%s: invalid file header.",
367
0
     function );
368
369
0
    return( -1 );
370
0
  }
371
#if defined( HAVE_DEBUG_OUTPUT )
372
  if( libcnotify_verbose != 0 )
373
  {
374
    libcnotify_printf(
375
     "%s: reading file header at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
376
     function,
377
     file_offset,
378
     file_offset );
379
  }
380
#endif
381
3.34k
  read_count = libbfio_handle_read_buffer_at_offset(
382
3.34k
                file_io_handle,
383
3.34k
                file_header_data,
384
3.34k
                sizeof( msiecf_file_header_t ),
385
3.34k
                file_offset,
386
3.34k
                error );
387
388
3.34k
  if( read_count != (ssize_t) sizeof( msiecf_file_header_t ) )
389
30
  {
390
30
    libcerror_error_set(
391
30
     error,
392
30
     LIBCERROR_ERROR_DOMAIN_IO,
393
30
     LIBCERROR_IO_ERROR_READ_FAILED,
394
30
     "%s: unable to read file header data at offset: %" PRIi64 " (0x%08" PRIx64 ").",
395
30
     function,
396
30
     file_offset,
397
30
     file_offset );
398
399
30
    return( -1 );
400
30
  }
401
3.31k
  if( libmsiecf_file_header_read_data(
402
3.31k
       file_header,
403
3.31k
       file_header_data,
404
3.31k
       sizeof( msiecf_file_header_t ),
405
3.31k
       error ) != 1 )
406
361
  {
407
361
    libcerror_error_set(
408
361
     error,
409
361
     LIBCERROR_ERROR_DOMAIN_IO,
410
361
     LIBCERROR_IO_ERROR_READ_FAILED,
411
361
     "%s: unable to read file header.",
412
361
     function );
413
414
361
    return( -1 );
415
361
  }
416
2.95k
  return( 1 );
417
3.31k
}
418