Coverage Report

Created: 2023-06-07 06:53

/src/libevtx/libevtx/libevtx_chunks_table.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Chunks table functions
3
 *
4
 * Copyright (C) 2011-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 "libevtx_chunk.h"
27
#include "libevtx_chunks_table.h"
28
#include "libevtx_io_handle.h"
29
#include "libevtx_libbfio.h"
30
#include "libevtx_libcerror.h"
31
#include "libevtx_libfcache.h"
32
#include "libevtx_libfdata.h"
33
#include "libevtx_record_values.h"
34
#include "libevtx_unused.h"
35
36
/* Creates a chunks table
37
 * Make sure the value chunks_table is referencing, is set to NULL
38
 * Returns 1 if successful or -1 on error
39
 */
40
int libevtx_chunks_table_initialize(
41
     libevtx_chunks_table_t **chunks_table,
42
     libevtx_io_handle_t *io_handle,
43
     libfdata_vector_t *chunks_vector,
44
     libfcache_cache_t *chunks_cache,
45
     libcerror_error_t **error )
46
2.58k
{
47
2.58k
  static char *function = "libevtx_chunks_table_initialize";
48
49
2.58k
  if( chunks_table == NULL )
50
0
  {
51
0
    libcerror_error_set(
52
0
     error,
53
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
54
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
55
0
     "%s: invalid chunks table.",
56
0
     function );
57
58
0
    return( -1 );
59
0
  }
60
2.58k
  if( *chunks_table != NULL )
61
0
  {
62
0
    libcerror_error_set(
63
0
     error,
64
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
65
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
66
0
     "%s: invalid chunks table value already set.",
67
0
     function );
68
69
0
    return( -1 );
70
0
  }
71
2.58k
  if( io_handle == NULL )
72
0
  {
73
0
    libcerror_error_set(
74
0
     error,
75
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
76
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
77
0
     "%s: invalid IO handle.",
78
0
     function );
79
80
0
    return( -1 );
81
0
  }
82
2.58k
  *chunks_table = memory_allocate_structure(
83
2.58k
                   libevtx_chunks_table_t );
84
85
2.58k
  if( *chunks_table == NULL )
86
0
  {
87
0
    libcerror_error_set(
88
0
     error,
89
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
90
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
91
0
     "%s: unable to create chunks table.",
92
0
     function );
93
94
0
    goto on_error;
95
0
  }
96
2.58k
  if( memory_set(
97
2.58k
       *chunks_table,
98
2.58k
       0,
99
2.58k
       sizeof( libevtx_chunks_table_t ) ) == NULL )
100
0
  {
101
0
    libcerror_error_set(
102
0
     error,
103
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
104
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
105
0
     "%s: unable to clear chunks table.",
106
0
     function );
107
108
109
0
    goto on_error;
110
0
  }
111
2.58k
  ( *chunks_table )->io_handle     = io_handle;
112
2.58k
  ( *chunks_table )->chunks_vector = chunks_vector;
113
2.58k
  ( *chunks_table )->chunks_cache  = chunks_cache;
114
115
2.58k
  return( 1 );
116
117
0
on_error:
118
0
  if( *chunks_table != NULL )
119
0
  {
120
0
    memory_free(
121
0
     *chunks_table );
122
123
0
    *chunks_table = NULL;
124
0
  }
125
0
  return( -1 );
126
2.58k
}
127
128
/* Frees a chunks table
129
 * Returns 1 if successful or -1 on error
130
 */
131
int libevtx_chunks_table_free(
132
     libevtx_chunks_table_t **chunks_table,
133
     libcerror_error_t **error )
134
2.58k
{
135
2.58k
  static char *function = "libevtx_chunks_table_free";
136
2.58k
  int result            = 1;
137
138
2.58k
  if( chunks_table == NULL )
139
0
  {
140
0
    libcerror_error_set(
141
0
     error,
142
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
143
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
144
0
     "%s: invalid chunks table.",
145
0
     function );
146
147
0
    return( -1 );
148
0
  }
149
2.58k
  if( *chunks_table != NULL )
150
2.58k
  {
151
2.58k
    memory_free(
152
2.58k
     *chunks_table );
153
154
2.58k
    *chunks_table = NULL;
155
2.58k
  }
156
2.58k
  return( result );
157
2.58k
}
158
159
/* Reads a chunk
160
 * Callback function for the chunk vector
161
 * Returns 1 if successful or -1 on error
162
 */
163
int libevtx_chunks_table_read_record(
164
     intptr_t *io_handle,
165
     libbfio_handle_t *file_io_handle,
166
     libfdata_list_element_t *list_element,
167
     libfdata_cache_t *cache,
168
     int data_range_file_index LIBEVTX_ATTRIBUTE_UNUSED,
169
     off64_t data_range_offset,
170
     size64_t data_range_size,
171
     uint32_t data_range_flags LIBEVTX_ATTRIBUTE_UNUSED,
172
     uint8_t read_flags LIBEVTX_ATTRIBUTE_UNUSED,
173
     libcerror_error_t **error )
174
1.54k
{
175
1.54k
  libevtx_chunk_t *chunk                       = NULL;
176
1.54k
  libevtx_chunks_table_t *chunks_table         = NULL;
177
1.54k
  libevtx_record_values_t *chunk_record_values = NULL;
178
1.54k
  libevtx_record_values_t *record_values       = NULL;
179
1.54k
  static char *function                        = "libevtx_io_handle_read_chunk";
180
1.54k
  size_t calculated_chunk_data_offset          = 0;
181
1.54k
  size_t chunk_data_offset                     = 0;
182
1.54k
  uint16_t number_of_records                   = 0;
183
1.54k
  uint16_t record_index                        = 0;
184
185
1.54k
  LIBEVTX_UNREFERENCED_PARAMETER( data_range_file_index );
186
1.54k
  LIBEVTX_UNREFERENCED_PARAMETER( data_range_flags );
187
1.54k
  LIBEVTX_UNREFERENCED_PARAMETER( read_flags );
188
189
1.54k
  if( io_handle == NULL )
190
0
  {
191
0
    libcerror_error_set(
192
0
     error,
193
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
194
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
195
0
     "%s: invalid IO handle.",
196
0
     function );
197
198
0
    return( -1 );
199
0
  }
200
1.54k
  chunks_table = (libevtx_chunks_table_t *) io_handle;
201
202
  /* The chunk index is stored in the data range size
203
  */
204
1.54k
  if( data_range_size > (uint64_t) UINT16_MAX )
205
0
  {
206
0
    libcerror_error_set(
207
0
     error,
208
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
209
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
210
0
     "%s: invalid data range size value out of bounds.",
211
0
     function );
212
213
0
    goto on_error;
214
0
  }
215
1.54k
  if( libfdata_vector_get_element_value_by_index(
216
1.54k
       chunks_table->chunks_vector,
217
1.54k
       (intptr_t *) file_io_handle,
218
1.54k
       (libfdata_cache_t *) chunks_table->chunks_cache,
219
1.54k
       (uint16_t) data_range_size,
220
1.54k
       (intptr_t **) &chunk,
221
1.54k
       0,
222
1.54k
       error ) != 1 )
223
0
  {
224
0
    libcerror_error_set(
225
0
     error,
226
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
227
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
228
0
     "%s: unable to retrieve chunk: %" PRIu64 ".",
229
0
     function,
230
0
     data_range_size );
231
232
0
    goto on_error;
233
0
  }
234
1.54k
  if( chunk == NULL )
235
0
  {
236
0
    libcerror_error_set(
237
0
     error,
238
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
239
0
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
240
0
     "%s: missing chunk: %" PRIu64 ".",
241
0
     function,
242
0
     data_range_size );
243
244
0
    goto on_error;
245
0
  }
246
1.54k
  if( ( data_range_offset < chunk->file_offset )
247
1.54k
   || ( data_range_offset >= (off64_t) ( chunk->file_offset + chunk->data_size ) ) )
248
0
  {
249
0
    libcerror_error_set(
250
0
     error,
251
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
252
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
253
0
     "%s: invalid chunk file offset value out of bounds.",
254
0
     function );
255
256
0
    goto on_error;
257
0
  }
258
1.54k
  calculated_chunk_data_offset = (size_t) ( data_range_offset - chunk->file_offset );
259
260
1.54k
  if( libevtx_chunk_get_number_of_records(
261
1.54k
       chunk,
262
1.54k
       &number_of_records,
263
1.54k
       error ) != 1 )
264
0
  {
265
0
    libcerror_error_set(
266
0
     error,
267
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
268
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
269
0
     "%s: unable to retrieve number of records from chunk.",
270
0
     function );
271
272
0
    goto on_error;
273
0
  }
274
/* TODO optimize determining the corresponding record */
275
1.54k
  for( record_index = 0;
276
1.54k
       record_index < number_of_records;
277
1.54k
       record_index++ )
278
1.54k
  {
279
1.54k
    if( libevtx_chunk_get_record(
280
1.54k
         chunk,
281
1.54k
         record_index,
282
1.54k
         &chunk_record_values,
283
1.54k
         error ) != 1 )
284
0
    {
285
0
      libcerror_error_set(
286
0
       error,
287
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
288
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
289
0
       "%s: unable to retrieve record: %" PRIu16 " from chunk.",
290
0
       function,
291
0
       record_index );
292
293
0
      goto on_error;
294
0
    }
295
1.54k
    if( chunk_record_values == NULL )
296
0
    {
297
0
      libcerror_error_set(
298
0
       error,
299
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
300
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
301
0
       "%s: missing record: %" PRIu16 ".",
302
0
       function,
303
0
       record_index );
304
305
0
      goto on_error;
306
0
    }
307
1.54k
    chunk_data_offset = chunk_record_values->chunk_data_offset;
308
309
1.54k
    if( calculated_chunk_data_offset == chunk_data_offset )
310
1.54k
    {
311
1.54k
      break;
312
1.54k
    }
313
1.54k
  }
314
/* TODO allow to control look up in normal vs recovered */
315
1.54k
  if( calculated_chunk_data_offset != chunk_data_offset )
316
0
  {
317
0
    if( libevtx_chunk_get_number_of_recovered_records(
318
0
         chunk,
319
0
         &number_of_records,
320
0
         error ) != 1 )
321
0
    {
322
0
      libcerror_error_set(
323
0
       error,
324
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
325
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
326
0
       "%s: unable to retrieve number of recovered records from chunk.",
327
0
       function );
328
329
0
      goto on_error;
330
0
    }
331
0
    for( record_index = 0;
332
0
         record_index < number_of_records;
333
0
         record_index++ )
334
0
    {
335
0
      if( libevtx_chunk_get_recovered_record(
336
0
           chunk,
337
0
           record_index,
338
0
           &chunk_record_values,
339
0
           error ) != 1 )
340
0
      {
341
0
        libcerror_error_set(
342
0
         error,
343
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
344
0
         LIBCERROR_RUNTIME_ERROR_GET_FAILED,
345
0
         "%s: unable to retrieve recovered record: %" PRIu16 " from chunk.",
346
0
         function,
347
0
         record_index );
348
349
0
        goto on_error;
350
0
      }
351
0
      if( chunk_record_values == NULL )
352
0
      {
353
0
        libcerror_error_set(
354
0
         error,
355
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
356
0
         LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
357
0
         "%s: missing recovered record: %" PRIu16 ".",
358
0
         function,
359
0
         record_index );
360
361
0
        goto on_error;
362
0
      }
363
0
      chunk_data_offset = chunk_record_values->chunk_data_offset;
364
365
0
      if( calculated_chunk_data_offset == chunk_data_offset )
366
0
      {
367
0
        break;
368
0
      }
369
0
    }
370
0
  }
371
1.54k
  if( calculated_chunk_data_offset != chunk_data_offset )
372
0
  {
373
0
    libcerror_error_set(
374
0
     error,
375
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
376
0
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
377
0
     "%s: no record found at offset: %" PRIi64 ".",
378
0
     function,
379
0
     data_range_offset );
380
381
0
    goto on_error;
382
0
  }
383
  /* The record values are managed by the chunk and freed after usage
384
   * A copy is created to make sure that the records values that are passed
385
   * to the records list can be managed by the list
386
   */
387
1.54k
  if( libevtx_record_values_clone(
388
1.54k
       &record_values,
389
1.54k
       chunk_record_values,
390
1.54k
       error ) != 1 )
391
0
  {
392
0
    libcerror_error_set(
393
0
     error,
394
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
395
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
396
0
     "%s: unable to create record values.",
397
0
     function );
398
399
0
    goto on_error;
400
0
  }
401
1.54k
  if( libevtx_record_values_read_xml_document(
402
1.54k
       record_values,
403
1.54k
       chunks_table->io_handle,
404
1.54k
       chunk->data,
405
1.54k
       chunk->data_size,
406
1.54k
       error ) != 1 )
407
1.48k
  {
408
1.48k
    libcerror_error_set(
409
1.48k
     error,
410
1.48k
     LIBCERROR_ERROR_DOMAIN_IO,
411
1.48k
     LIBCERROR_IO_ERROR_READ_FAILED,
412
1.48k
     "%s: unable to read record values XML document.",
413
1.48k
     function );
414
415
1.48k
    goto on_error;
416
1.48k
  }
417
61
  if( libfdata_list_element_set_element_value(
418
61
       list_element,
419
61
       (intptr_t *) file_io_handle,
420
61
       cache,
421
61
       (intptr_t *) record_values,
422
61
       (int (*)(intptr_t **, libcerror_error_t **)) &libevtx_record_values_free,
423
61
       LIBFDATA_LIST_ELEMENT_VALUE_FLAG_MANAGED,
424
61
       error ) != 1 )
425
0
  {
426
0
    libcerror_error_set(
427
0
     error,
428
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
429
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
430
0
     "%s: unable to set record values as element value.",
431
0
     function );
432
433
0
    goto on_error;
434
0
  }
435
61
  return( 1 );
436
437
1.48k
on_error:
438
1.48k
  if( record_values != NULL )
439
1.48k
  {
440
1.48k
    libevtx_record_values_free(
441
1.48k
     &record_values,
442
1.48k
     NULL );
443
1.48k
  }
444
1.48k
  return( -1 );
445
61
}
446