Coverage Report

Created: 2024-10-02 06:58

/src/libevt/libevt/libevt_io_handle.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Input/Output (IO) handle functions
3
 *
4
 * Copyright (C) 2011-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 "libevt_debug.h"
28
#include "libevt_codepage.h"
29
#include "libevt_definitions.h"
30
#include "libevt_io_handle.h"
31
#include "libevt_libbfio.h"
32
#include "libevt_libcdata.h"
33
#include "libevt_libcerror.h"
34
#include "libevt_libcnotify.h"
35
#include "libevt_record_values.h"
36
#include "libevt_unused.h"
37
38
#include "evt_file_header.h"
39
40
const uint8_t evt_end_of_file_record_signature1[ 4 ] = { 0x11, 0x11, 0x11, 0x11 };
41
const uint8_t evt_end_of_file_record_signature2[ 4 ] = { 0x22, 0x22, 0x22, 0x22 };
42
const uint8_t evt_end_of_file_record_signature3[ 4 ] = { 0x33, 0x33, 0x33, 0x33 };
43
const uint8_t evt_end_of_file_record_signature4[ 4 ] = { 0x44, 0x44, 0x44, 0x44 };
44
const uint8_t evt_file_signature[ 4 ]                = { 'L', 'f', 'L', 'e' };
45
46
/* Creates an IO handle
47
 * Make sure the value io_handle is referencing, is set to NULL
48
 * Returns 1 if successful or -1 on error
49
 */
50
int libevt_io_handle_initialize(
51
     libevt_io_handle_t **io_handle,
52
     libcerror_error_t **error )
53
3.54k
{
54
3.54k
  static char *function = "libevt_io_handle_initialize";
55
56
3.54k
  if( io_handle == NULL )
57
0
  {
58
0
    libcerror_error_set(
59
0
     error,
60
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
61
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
62
0
     "%s: invalid IO handle.",
63
0
     function );
64
65
0
    return( -1 );
66
0
  }
67
3.54k
  if( *io_handle != NULL )
68
0
  {
69
0
    libcerror_error_set(
70
0
     error,
71
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
72
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
73
0
     "%s: invalid IO handle value already set.",
74
0
     function );
75
76
0
    return( -1 );
77
0
  }
78
3.54k
  *io_handle = memory_allocate_structure(
79
3.54k
                libevt_io_handle_t );
80
81
3.54k
  if( *io_handle == NULL )
82
0
  {
83
0
    libcerror_error_set(
84
0
     error,
85
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
86
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
87
0
     "%s: unable to create IO handle.",
88
0
     function );
89
90
0
    goto on_error;
91
0
  }
92
3.54k
  if( memory_set(
93
3.54k
       *io_handle,
94
3.54k
       0,
95
3.54k
       sizeof( libevt_io_handle_t ) ) == NULL )
96
0
  {
97
0
    libcerror_error_set(
98
0
     error,
99
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
100
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
101
0
     "%s: unable to clear file.",
102
0
     function );
103
104
0
    goto on_error;
105
0
  }
106
3.54k
  ( *io_handle )->ascii_codepage = LIBEVT_CODEPAGE_WINDOWS_1252;
107
108
3.54k
  return( 1 );
109
110
0
on_error:
111
0
  if( *io_handle != NULL )
112
0
  {
113
0
    memory_free(
114
0
     *io_handle );
115
116
0
    *io_handle = NULL;
117
0
  }
118
0
  return( -1 );
119
3.54k
}
120
121
/* Frees an IO handle
122
 * Returns 1 if successful or -1 on error
123
 */
124
int libevt_io_handle_free(
125
     libevt_io_handle_t **io_handle,
126
     libcerror_error_t **error )
127
3.54k
{
128
3.54k
  static char *function = "libevt_io_handle_free";
129
130
3.54k
  if( io_handle == NULL )
131
0
  {
132
0
    libcerror_error_set(
133
0
     error,
134
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
135
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
136
0
     "%s: invalid IO handle.",
137
0
     function );
138
139
0
    return( -1 );
140
0
  }
141
3.54k
  if( *io_handle != NULL )
142
3.54k
  {
143
3.54k
    memory_free(
144
3.54k
     *io_handle );
145
146
3.54k
    *io_handle = NULL;
147
3.54k
  }
148
3.54k
  return( 1 );
149
3.54k
}
150
151
/* Clears the IO handle
152
 * Returns 1 if successful or -1 on error
153
 */
154
int libevt_io_handle_clear(
155
     libevt_io_handle_t *io_handle,
156
     libcerror_error_t **error )
157
3.50k
{
158
3.50k
  static char *function = "libevt_io_handle_clear";
159
160
3.50k
  if( io_handle == NULL )
161
0
  {
162
0
    libcerror_error_set(
163
0
     error,
164
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
165
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
166
0
     "%s: invalid IO handle.",
167
0
     function );
168
169
0
    return( -1 );
170
0
  }
171
3.50k
  if( memory_set(
172
3.50k
       io_handle,
173
3.50k
       0,
174
3.50k
       sizeof( libevt_io_handle_t ) ) == NULL )
175
0
  {
176
0
    libcerror_error_set(
177
0
     error,
178
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
179
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
180
0
     "%s: unable to clear IO handle.",
181
0
     function );
182
183
0
    return( -1 );
184
0
  }
185
3.50k
  io_handle->ascii_codepage = LIBEVT_CODEPAGE_WINDOWS_1252;
186
187
3.50k
  return( 1 );
188
3.50k
}
189
190
/* Reads the records into the records array
191
 * Returns 1 if successful or -1 on error
192
 */
193
int libevt_io_handle_read_records(
194
     libevt_io_handle_t *io_handle,
195
     libbfio_handle_t *file_io_handle,
196
     uint32_t first_record_offset,
197
     uint32_t end_of_file_record_offset,
198
     libfdata_list_t *records_list,
199
     off64_t *last_record_offset,
200
     libcerror_error_t **error )
201
3.82k
{
202
3.82k
  libevt_record_values_t *record_values = NULL;
203
3.82k
  static char *function                 = "libevt_io_handle_read_records";
204
3.82k
  ssize_t read_count                    = 0;
205
3.82k
  off64_t file_offset                   = 0;
206
3.82k
  off64_t safe_last_record_offset       = 0;
207
3.82k
  uint32_t record_iterator              = 0;
208
3.82k
  uint8_t record_type                   = 0;
209
3.82k
  int element_index                     = 0;
210
211
3.82k
  if( io_handle == NULL )
212
0
  {
213
0
    libcerror_error_set(
214
0
     error,
215
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
216
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
217
0
     "%s: invalid IO handle.",
218
0
     function );
219
220
0
    return( -1 );
221
0
  }
222
3.82k
  if( ( (off64_t) first_record_offset < (off64_t) sizeof( evt_file_header_t ) )
223
3.82k
   || ( (size64_t) first_record_offset >= io_handle->file_size ) )
224
2.41k
  {
225
2.41k
    libcerror_error_set(
226
2.41k
     error,
227
2.41k
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
228
2.41k
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
229
2.41k
     "%s: invalid first record offset value out of bounds.",
230
2.41k
     function );
231
232
2.41k
    goto on_error;
233
2.41k
  }
234
1.41k
  if( last_record_offset == NULL )
235
0
  {
236
0
    libcerror_error_set(
237
0
     error,
238
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
239
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
240
0
     "%s: invalid last record offset.",
241
0
     function );
242
243
0
    return( -1 );
244
0
  }
245
1.41k
  file_offset = (off64_t) first_record_offset;
246
247
1.41k
  do
248
19.2k
  {
249
#if defined( HAVE_DEBUG_OUTPUT )
250
    if( libcnotify_verbose != 0 )
251
    {
252
      libcnotify_printf(
253
       "%s: reading record: %" PRIu32 " at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
254
       function,
255
       record_iterator,
256
       file_offset,
257
       file_offset );
258
    }
259
#endif
260
19.2k
    if( libevt_record_values_initialize(
261
19.2k
         &record_values,
262
19.2k
         error ) != 1 )
263
0
    {
264
0
      libcerror_error_set(
265
0
       error,
266
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
267
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
268
0
       "%s: unable to create record values.",
269
0
       function );
270
271
0
      goto on_error;
272
0
    }
273
19.2k
    safe_last_record_offset = file_offset;
274
275
19.2k
    read_count = libevt_record_values_read_file_io_handle(
276
19.2k
                  record_values,
277
19.2k
                  file_io_handle,
278
19.2k
                  io_handle,
279
19.2k
                  &file_offset,
280
19.2k
                  &( io_handle->has_wrapped ),
281
19.2k
                  1,
282
19.2k
                  error );
283
284
19.2k
    if( read_count == -1 )
285
1.25k
    {
286
1.25k
      libcerror_error_set(
287
1.25k
       error,
288
1.25k
       LIBCERROR_ERROR_DOMAIN_IO,
289
1.25k
       LIBCERROR_IO_ERROR_READ_FAILED,
290
1.25k
       "%s: unable to read record: %" PRIu32 " at offset: %" PRIi64 " (0x%08" PRIx64 ").",
291
1.25k
       function,
292
1.25k
       record_iterator,
293
1.25k
       safe_last_record_offset,
294
1.25k
       safe_last_record_offset );
295
296
1.25k
      goto on_error;
297
1.25k
    }
298
17.9k
    record_type = record_values->type;
299
300
17.9k
    if( record_type == LIBEVT_RECORD_TYPE_EVENT )
301
17.8k
    {
302
17.8k
      if( libfdata_list_append_element(
303
17.8k
           records_list,
304
17.8k
           &element_index,
305
17.8k
           0,
306
17.8k
           safe_last_record_offset,
307
17.8k
           (size64_t) read_count,
308
17.8k
           0,
309
17.8k
           error ) != 1 )
310
0
      {
311
0
        libcerror_error_set(
312
0
         error,
313
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
314
0
         LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
315
0
         "%s: unable to append record to records list.",
316
0
         function );
317
318
0
        goto on_error;
319
0
      }
320
17.8k
    }
321
17.9k
    if( libevt_record_values_free(
322
17.9k
         &record_values,
323
17.9k
         error ) != 1 )
324
0
    {
325
0
      libcerror_error_set(
326
0
       error,
327
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
328
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
329
0
       "%s: unable to free record values.",
330
0
       function );
331
332
0
      goto on_error;
333
0
    }
334
17.9k
    if( record_type == LIBEVT_RECORD_TYPE_END_OF_FILE )
335
94
    {
336
#if defined( HAVE_DEBUG_OUTPUT )
337
      if( libcnotify_verbose != 0 )
338
      {
339
        libcnotify_printf(
340
         "%s: end-of-file record found at offset: 0x%08" PRIx64 ".\n",
341
         function,
342
         file_offset );
343
      }
344
#endif
345
94
      break;
346
94
    }
347
17.8k
    if( ( file_offset > (off64_t) end_of_file_record_offset )
348
17.8k
     && ( file_offset < (off64_t) ( end_of_file_record_offset + read_count ) ) )
349
66
    {
350
#if defined( HAVE_DEBUG_OUTPUT )
351
      if( libcnotify_verbose != 0 )
352
      {
353
        libcnotify_printf(
354
         "%s: file offset: 0x%08" PRIx64 " exceeds end-of-file offset: 0x%08" PRIx64 ".\n",
355
         function,
356
         file_offset,
357
         end_of_file_record_offset );
358
      }
359
#endif
360
66
      break;
361
66
    }
362
17.8k
    record_iterator++;
363
17.8k
  }
364
17.8k
  while( record_type != LIBEVT_RECORD_TYPE_END_OF_FILE );
365
366
160
  if( record_type == LIBEVT_RECORD_TYPE_END_OF_FILE )
367
94
  {
368
94
    if( safe_last_record_offset != (off64_t) end_of_file_record_offset )
369
92
    {
370
#if defined( HAVE_DEBUG_OUTPUT )
371
      if( libcnotify_verbose != 0 )
372
      {
373
        libcnotify_printf(
374
         "%s: mismatch in end of file record offset ( %" PRIi64 " != %" PRIu32 " ).\n",
375
         function,
376
         safe_last_record_offset,
377
         end_of_file_record_offset );
378
      }
379
#endif
380
92
      io_handle->flags |= LIBEVT_IO_HANDLE_FLAG_IS_CORRUPTED;
381
92
    }
382
94
    safe_last_record_offset += read_count;
383
94
  }
384
160
  if( ( io_handle->has_wrapped != 0 )
385
160
   && ( ( io_handle->flags & LIBEVT_FILE_FLAG_HAS_WRAPPED ) == 0 ) )
386
119
  {
387
#if defined( HAVE_DEBUG_OUTPUT )
388
    if( libcnotify_verbose != 0 )
389
    {
390
      libcnotify_printf(
391
       "%s: file has wrapped but file flags indicate otherwise.\n",
392
       function );
393
    }
394
#endif
395
119
    io_handle->flags |= LIBEVT_IO_HANDLE_FLAG_IS_CORRUPTED;
396
119
  }
397
160
  *last_record_offset = safe_last_record_offset;
398
399
160
  return( 1 );
400
401
3.66k
on_error:
402
3.66k
  if( record_values != NULL )
403
1.25k
  {
404
1.25k
    libevt_record_values_free(
405
1.25k
     &record_values,
406
1.25k
     NULL );
407
1.25k
  }
408
3.66k
  *last_record_offset = safe_last_record_offset;
409
410
3.66k
  return( -1 );
411
1.41k
}
412
413
/* Scans for the end-of-file record and adjusts the offsets accordingly
414
 * Returns 1 if successful, 0 if not or -1 on error
415
 */
416
int libevt_io_handle_end_of_file_record_scan(
417
     libevt_io_handle_t *io_handle,
418
     libbfio_handle_t *file_io_handle,
419
     uint32_t *first_record_offset,
420
     uint32_t *end_of_file_record_offset,
421
     libcerror_error_t **error )
422
1.07k
{
423
1.07k
  uint8_t *scan_block         = NULL;
424
1.07k
  static char *function       = "libevt_io_handle_end_of_file_record_scan";
425
1.07k
  off64_t file_offset         = 0;
426
1.07k
  off64_t initial_file_offset = 0;
427
1.07k
  size_t read_size            = 0;
428
1.07k
  size_t scan_block_offset    = 0;
429
1.07k
  size_t scan_block_size      = 8192;
430
1.07k
  ssize_t read_count          = 0;
431
1.07k
  uint8_t scan_state          = LIBEVT_RECOVER_SCAN_STATE_START;
432
1.07k
  uint8_t scan_has_wrapped    = 0;
433
434
1.07k
  if( io_handle == NULL )
435
0
  {
436
0
    libcerror_error_set(
437
0
     error,
438
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
439
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
440
0
     "%s: invalid IO handle.",
441
0
     function );
442
443
0
    return( -1 );
444
0
  }
445
1.07k
  if( first_record_offset == NULL )
446
0
  {
447
0
    libcerror_error_set(
448
0
     error,
449
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
450
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
451
0
     "%s: invalid first record offset.",
452
0
     function );
453
454
0
    return( -1 );
455
0
  }
456
1.07k
  if( end_of_file_record_offset == NULL )
457
0
  {
458
0
    libcerror_error_set(
459
0
     error,
460
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
461
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
462
0
     "%s: invalid end of file record offset.",
463
0
     function );
464
465
0
    return( -1 );
466
0
  }
467
1.07k
  scan_block = (uint8_t *) memory_allocate(
468
1.07k
          sizeof( uint8_t ) * scan_block_size );
469
470
1.07k
  if( scan_block == NULL )
471
0
  {
472
0
    libcerror_error_set(
473
0
     error,
474
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
475
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
476
0
     "%s: unable to create scan block.",
477
0
     function );
478
479
0
    goto on_error;
480
0
  }
481
  /* If the file has wrapped start looking for the end-of-file record after the end-of-file record offset
482
   */
483
1.07k
  file_offset = (off64_t) *end_of_file_record_offset;
484
485
1.07k
  if( ( file_offset < (off64_t) sizeof( evt_file_header_t ) )
486
1.07k
   || ( (size64_t) file_offset >= io_handle->file_size ) )
487
567
  {
488
567
    file_offset = (off64_t) sizeof( evt_file_header_t );
489
567
  }
490
1.07k
  initial_file_offset = file_offset;
491
492
1.07k
  do
493
7.86k
  {
494
7.86k
    if( ( (size64_t) file_offset + scan_block_size ) > io_handle->file_size )
495
1.25k
    {
496
1.25k
      read_size = (size_t) ( io_handle->file_size - file_offset );
497
1.25k
    }
498
6.60k
    else
499
6.60k
    {
500
6.60k
      read_size = scan_block_size;
501
6.60k
    }
502
7.86k
    read_count = libbfio_handle_read_buffer_at_offset(
503
7.86k
            file_io_handle,
504
7.86k
            scan_block,
505
7.86k
            read_size,
506
7.86k
            file_offset,
507
7.86k
            error );
508
509
7.86k
    if( read_count != (ssize_t) read_size )
510
0
    {
511
0
      libcerror_error_set(
512
0
       error,
513
0
       LIBCERROR_ERROR_DOMAIN_IO,
514
0
       LIBCERROR_IO_ERROR_READ_FAILED,
515
0
       "%s: unable to read scan block at offset: %" PRIi64 " (0x%08" PRIx64 ").",
516
0
       function,
517
0
       file_offset,
518
0
       file_offset );
519
520
0
      goto on_error;
521
0
    }
522
7.86k
    file_offset += read_count;
523
524
7.86k
    if( read_size >= 4 )
525
7.66k
    {
526
7.66k
      for( scan_block_offset = 0;
527
13.6M
           scan_block_offset < ( read_size - 4 );
528
13.6M
           scan_block_offset += 4 )
529
13.6M
      {
530
13.6M
        if( scan_state == LIBEVT_RECOVER_SCAN_STATE_START )
531
12.0M
        {
532
12.0M
          if( memory_compare(
533
12.0M
               &( scan_block[ scan_block_offset ] ),
534
12.0M
               evt_end_of_file_record_signature1,
535
12.0M
               4 ) == 0 )
536
13.7k
          {
537
13.7k
            scan_state = LIBEVT_RECOVER_SCAN_STATE_FOUND_EOF_SIGNATURE1;
538
13.7k
          }
539
12.0M
        }
540
1.60M
        else if( scan_state == LIBEVT_RECOVER_SCAN_STATE_FOUND_EOF_SIGNATURE1 )
541
13.7k
        {
542
13.7k
          if( memory_compare(
543
13.7k
               &( scan_block[ scan_block_offset ] ),
544
13.7k
               evt_end_of_file_record_signature2,
545
13.7k
               4 ) == 0 )
546
3.91k
          {
547
3.91k
            scan_state = LIBEVT_RECOVER_SCAN_STATE_FOUND_EOF_SIGNATURE2;
548
3.91k
          }
549
9.80k
          else
550
9.80k
          {
551
9.80k
            scan_state = LIBEVT_RECOVER_SCAN_STATE_START;
552
9.80k
          }
553
13.7k
        }
554
1.59M
        else if( scan_state == LIBEVT_RECOVER_SCAN_STATE_FOUND_EOF_SIGNATURE2 )
555
3.90k
        {
556
3.90k
          if( memory_compare(
557
3.90k
               &( scan_block[ scan_block_offset ] ),
558
3.90k
               evt_end_of_file_record_signature3,
559
3.90k
               4 ) == 0 )
560
1.98k
          {
561
1.98k
            scan_state = LIBEVT_RECOVER_SCAN_STATE_FOUND_EOF_SIGNATURE3;
562
1.98k
          }
563
1.92k
          else
564
1.92k
          {
565
1.92k
            scan_state = LIBEVT_RECOVER_SCAN_STATE_START;
566
1.92k
          }
567
3.90k
        }
568
1.58M
        else if( scan_state == LIBEVT_RECOVER_SCAN_STATE_FOUND_EOF_SIGNATURE3 )
569
1.96k
        {
570
1.96k
          if( memory_compare(
571
1.96k
               &( scan_block[ scan_block_offset ] ),
572
1.96k
               evt_end_of_file_record_signature4,
573
1.96k
               4 ) == 0 )
574
456
          {
575
456
            *end_of_file_record_offset = (uint32_t) ( file_offset - read_count + scan_block_offset - 16 );
576
577
456
            scan_state = LIBEVT_RECOVER_SCAN_STATE_FOUND_EOF_SIGNATURE4;
578
456
          }
579
1.50k
          else
580
1.50k
          {
581
1.50k
            scan_state = LIBEVT_RECOVER_SCAN_STATE_START;
582
1.50k
          }
583
1.96k
        }
584
1.58M
        else if( scan_state == LIBEVT_RECOVER_SCAN_STATE_FOUND_EOF_SIGNATURE4 )
585
1.58M
        {
586
1.58M
          if( memory_compare(
587
1.58M
               &( scan_block[ scan_block_offset ] ),
588
1.58M
               evt_file_signature,
589
1.58M
               4 ) == 0 )
590
314
          {
591
314
            *first_record_offset = (uint32_t) ( file_offset - read_count + scan_block_offset - 4 );
592
593
314
            scan_state = LIBEVT_RECOVER_SCAN_STATE_FOUND_RECORD_SIGNATURE;
594
595
314
            break;
596
314
          }
597
1.58M
        }
598
13.6M
      }
599
7.66k
    }
600
7.86k
    if( scan_state == LIBEVT_RECOVER_SCAN_STATE_FOUND_RECORD_SIGNATURE )
601
314
    {
602
314
      break;
603
314
    }
604
7.54k
    if( ( scan_has_wrapped == 0 )
605
7.54k
     && ( (size64_t) file_offset >= io_handle->file_size ) )
606
845
    {
607
845
      file_offset = (off64_t) sizeof( evt_file_header_t );
608
609
845
      scan_has_wrapped = 1;
610
845
    }
611
7.54k
  }
612
7.54k
  while( ( scan_has_wrapped == 0 )
613
7.54k
      || ( file_offset < initial_file_offset ) );
614
615
1.07k
  memory_free(
616
1.07k
   scan_block );
617
618
1.07k
  scan_block = NULL;
619
620
1.07k
  if( scan_state == LIBEVT_RECOVER_SCAN_STATE_FOUND_RECORD_SIGNATURE )
621
314
  {
622
314
    return( 1 );
623
314
  }
624
757
  return( 0 );
625
626
0
on_error:
627
0
  if( scan_block != NULL )
628
0
  {
629
0
    memory_free(
630
0
     scan_block );
631
0
  }
632
0
  return( -1 );
633
1.07k
}
634
635
/* Scans for the event record and adds them to the recovered records array
636
 * Returns 1 if successful, 0 if not or -1 on error
637
 */
638
int libevt_io_handle_event_record_scan(
639
     libevt_io_handle_t *io_handle,
640
     libbfio_handle_t *file_io_handle,
641
     off64_t file_offset,
642
     size64_t size,
643
     libfdata_list_t *recovered_records_list,
644
     libcerror_error_t **error )
645
5.08k
{
646
5.08k
  libevt_record_values_t *record_values = NULL;
647
5.08k
  uint8_t *scan_block                   = NULL;
648
5.08k
  static char *function                 = "libevt_io_handle_event_record_scan";
649
5.08k
  off64_t record_offset                 = 0;
650
5.08k
  size_t read_size                      = 0;
651
5.08k
  size_t scan_block_offset              = 0;
652
5.08k
  size_t scan_block_size                = 8192;
653
5.08k
  ssize_t read_count                    = 0;
654
5.08k
  int element_index                     = 0;
655
656
5.08k
  if( io_handle == NULL )
657
0
  {
658
0
    libcerror_error_set(
659
0
     error,
660
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
661
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
662
0
     "%s: invalid IO handle.",
663
0
     function );
664
665
0
    return( -1 );
666
0
  }
667
5.08k
  if( file_offset < 0 )
668
0
  {
669
0
    libcerror_error_set(
670
0
     error,
671
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
672
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_LESS_THAN_ZERO,
673
0
     "%s: invalid file offset value less than zero.",
674
0
     function );
675
676
0
    return( -1 );
677
0
  }
678
5.08k
  if( size > (off64_t) INT64_MAX )
679
0
  {
680
0
    libcerror_error_set(
681
0
     error,
682
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
683
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
684
0
     "%s: invalid size value exceeds maximum.",
685
0
     function );
686
687
0
    return( -1 );
688
0
  }
689
5.08k
  scan_block = (uint8_t *) memory_allocate(
690
5.08k
          sizeof( uint8_t ) * scan_block_size );
691
692
5.08k
  if( scan_block == NULL )
693
0
  {
694
0
    libcerror_error_set(
695
0
     error,
696
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
697
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
698
0
     "%s: unable to create scan block.",
699
0
     function );
700
701
0
    goto on_error;
702
0
  }
703
24.5k
  while( size >= 4 )
704
21.6k
  {
705
21.6k
    if( scan_block_size > size )
706
3.29k
    {
707
3.29k
      read_size = (size_t) size;
708
3.29k
    }
709
18.3k
    else
710
18.3k
    {
711
18.3k
      read_size = scan_block_size;
712
18.3k
    }
713
21.6k
    read_count = libbfio_handle_read_buffer_at_offset(
714
21.6k
            file_io_handle,
715
21.6k
            scan_block,
716
21.6k
            read_size,
717
21.6k
            file_offset,
718
21.6k
            error );
719
720
21.6k
    if( read_count != (ssize_t) read_size )
721
2.19k
    {
722
2.19k
      libcerror_error_set(
723
2.19k
       error,
724
2.19k
       LIBCERROR_ERROR_DOMAIN_IO,
725
2.19k
       LIBCERROR_IO_ERROR_READ_FAILED,
726
2.19k
       "%s: unable to read scan block at offset: %" PRIi64 " (0x%08" PRIx64 ").",
727
2.19k
       function,
728
2.19k
       file_offset,
729
2.19k
       file_offset );
730
731
2.19k
      goto on_error;
732
2.19k
    }
733
19.4k
    scan_block_offset = 0;
734
735
27.4M
    while( scan_block_offset <= ( read_size - 4 ) )
736
27.4M
    {
737
27.4M
      if( memory_compare(
738
27.4M
           &( scan_block[ scan_block_offset ] ),
739
27.4M
           evt_file_signature,
740
27.4M
           4 ) != 0 )
741
26.9M
      {
742
26.9M
        scan_block_offset += 4;
743
744
26.9M
        continue;
745
26.9M
      }
746
435k
      record_offset = file_offset + scan_block_offset - 4;
747
748
435k
      if( record_values == NULL )
749
307k
      {
750
307k
        if( libevt_record_values_initialize(
751
307k
             &record_values,
752
307k
             error ) != 1 )
753
0
        {
754
0
          libcerror_error_set(
755
0
           error,
756
0
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
757
0
           LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
758
0
           "%s: unable to create record values.",
759
0
           function );
760
761
0
          goto on_error;
762
0
        }
763
307k
      }
764
#if defined( HAVE_DEBUG_OUTPUT )
765
      if( libcnotify_verbose != 0 )
766
      {
767
        libcnotify_printf(
768
         "%s: reading recovered record at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
769
         function,
770
         record_offset,
771
         record_offset );
772
      }
773
#endif
774
435k
      read_count = libevt_record_values_read_file_io_handle(
775
435k
              record_values,
776
435k
              file_io_handle,
777
435k
              io_handle,
778
435k
              &record_offset,
779
435k
                    &( io_handle->has_wrapped ),
780
435k
              0,
781
435k
              error );
782
783
435k
      if( read_count == -1 )
784
130k
      {
785
130k
        libcerror_error_set(
786
130k
         error,
787
130k
         LIBCERROR_ERROR_DOMAIN_IO,
788
130k
         LIBCERROR_IO_ERROR_READ_FAILED,
789
130k
         "%s: unable to read record at offset: %" PRIi64 ".",
790
130k
         function,
791
130k
         record_offset );
792
793
#if defined( HAVE_DEBUG_OUTPUT )
794
        if( libcnotify_verbose != 0 )
795
        {
796
          if( ( error != NULL )
797
           && ( *error != NULL ) )
798
          {
799
            libcnotify_print_error_backtrace(
800
             *error );
801
          }
802
        }
803
#endif
804
130k
        libcerror_error_free(
805
130k
         error );
806
807
130k
        scan_block_offset += 4;
808
809
130k
        continue;
810
130k
      }
811
305k
      if( record_values->type == LIBEVT_RECORD_TYPE_EVENT )
812
305k
      {
813
305k
        if( libfdata_list_append_element(
814
305k
             recovered_records_list,
815
305k
             &element_index,
816
305k
             0,
817
305k
             file_offset + scan_block_offset - 4,
818
305k
             (size64_t) read_count,
819
305k
             0,
820
305k
             error ) != 1 )
821
0
        {
822
0
          libcerror_error_set(
823
0
           error,
824
0
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
825
0
           LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
826
0
           "%s: unable to append recovered record to records list.",
827
0
           function );
828
829
0
          goto on_error;
830
0
        }
831
305k
      }
832
305k
      if( libevt_record_values_free(
833
305k
           &record_values,
834
305k
           error ) != 1 )
835
0
      {
836
0
        libcerror_error_set(
837
0
         error,
838
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
839
0
         LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
840
0
         "%s: unable to free record values.",
841
0
         function );
842
843
0
        goto on_error;
844
0
      }
845
305k
      scan_block_offset += read_count - 4;
846
305k
    }
847
19.4k
    file_offset += scan_block_offset;
848
19.4k
    size        -= scan_block_offset;
849
19.4k
  }
850
2.89k
  if( record_values != NULL )
851
2.32k
  {
852
2.32k
    if( libevt_record_values_free(
853
2.32k
         &record_values,
854
2.32k
         error ) != 1 )
855
0
    {
856
0
      libcerror_error_set(
857
0
       error,
858
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
859
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
860
0
       "%s: unable to free record values.",
861
0
       function );
862
863
0
      goto on_error;
864
0
    }
865
2.32k
  }
866
2.89k
  memory_free(
867
2.89k
   scan_block );
868
869
2.89k
  scan_block = NULL;
870
871
2.89k
  return( 1 );
872
873
2.19k
on_error:
874
2.19k
  if( record_values != NULL )
875
133
  {
876
133
    libevt_record_values_free(
877
133
     &record_values,
878
133
     NULL );
879
133
  }
880
2.19k
  if( scan_block != NULL )
881
2.19k
  {
882
2.19k
    memory_free(
883
2.19k
     scan_block );
884
2.19k
  }
885
2.19k
  return( -1 );
886
2.89k
}
887
888
/* Tries to recover records
889
 * Returns 1 if successful or -1 on error
890
 */
891
int libevt_io_handle_recover_records(
892
     libevt_io_handle_t *io_handle,
893
     libbfio_handle_t *file_io_handle,
894
     uint32_t first_record_offset,
895
     uint32_t end_of_file_record_offset,
896
     off64_t last_record_offset,
897
     libfdata_list_t *records_list,
898
     libfdata_list_t *recovered_records_list,
899
     libcerror_error_t **error )
900
3.50k
{
901
3.50k
  static char *function  = "libevt_io_handle_recover_records";
902
3.50k
  int result             = 0;
903
904
3.50k
  if( io_handle == NULL )
905
0
  {
906
0
    libcerror_error_set(
907
0
     error,
908
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
909
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
910
0
     "%s: invalid IO handle.",
911
0
     function );
912
913
0
    return( -1 );
914
0
  }
915
3.50k
  if( last_record_offset == (off64_t) first_record_offset )
916
1.07k
  {
917
#if defined( HAVE_DEBUG_OUTPUT )
918
    if( libcnotify_verbose != 0 )
919
    {
920
      libcnotify_printf(
921
       "%s: no records found at specified offsets scanning for end-of-file record.\n",
922
       function );
923
    }
924
#endif
925
1.07k
    io_handle->flags |= LIBEVT_IO_HANDLE_FLAG_IS_CORRUPTED;
926
927
1.07k
    result = libevt_io_handle_end_of_file_record_scan(
928
1.07k
              io_handle,
929
1.07k
              file_io_handle,
930
1.07k
              &first_record_offset,
931
1.07k
              &end_of_file_record_offset,
932
1.07k
              error );
933
934
1.07k
    if( result == -1 )
935
0
    {
936
0
      libcerror_error_set(
937
0
       error,
938
0
       LIBCERROR_ERROR_DOMAIN_IO,
939
0
       LIBCERROR_IO_ERROR_READ_FAILED,
940
0
       "%s: unable to scan for end of file record.",
941
0
       function );
942
943
0
      return( -1 );
944
0
    }
945
1.07k
    else if( result != 0 )
946
314
    {
947
#if defined( HAVE_DEBUG_OUTPUT )
948
      if( libcnotify_verbose != 0 )
949
      {
950
        libcnotify_printf(
951
         "%s: end-of-file record found at offset: 0x%08" PRIx64 ".\n",
952
         function,
953
         end_of_file_record_offset );
954
      }
955
#endif
956
314
      result = libevt_io_handle_read_records(
957
314
                io_handle,
958
314
                file_io_handle,
959
314
                first_record_offset,
960
314
                end_of_file_record_offset,
961
314
                records_list,
962
314
                &last_record_offset,
963
314
                error );
964
965
314
      if( result != 1 )
966
260
      {
967
#if defined( HAVE_DEBUG_OUTPUT )
968
        if( libcnotify_verbose != 0 )
969
        {
970
          if( ( error != NULL )
971
           && ( *error != NULL ) )
972
          {
973
            libcerror_error_free(
974
             error );
975
          }
976
        }
977
#endif
978
260
        libcerror_error_set(
979
260
         error,
980
260
         LIBCERROR_ERROR_DOMAIN_IO,
981
260
         LIBCERROR_IO_ERROR_READ_FAILED,
982
260
         "%s: unable to read records.",
983
260
         function );
984
985
#if defined( HAVE_DEBUG_OUTPUT )
986
        if( libcnotify_verbose != 0 )
987
        {
988
          if( ( error != NULL )
989
           && ( *error != NULL ) )
990
          {
991
            libcnotify_print_error_backtrace(
992
             *error );
993
          }
994
        }
995
#endif
996
260
        libcerror_error_free(
997
260
         error );
998
260
      }
999
314
    }
1000
757
    else
1001
757
    {
1002
757
      first_record_offset = (uint32_t) sizeof( evt_file_header_t );
1003
757
      last_record_offset  = (off64_t) sizeof( evt_file_header_t );
1004
757
    }
1005
1.07k
  }
1006
3.50k
  if( io_handle->has_wrapped == 0 )
1007
2.86k
  {
1008
2.86k
    if( first_record_offset > (uint32_t) sizeof( evt_file_header_t ) )
1009
2.33k
    {
1010
#if defined( HAVE_DEBUG_OUTPUT )
1011
      if( libcnotify_verbose != 0 )
1012
      {
1013
        libcnotify_printf(
1014
         "%s: scanning unused space before records at offset: 0x%08" PRIzd " - 0x%08" PRIx32 "\n",
1015
         function,
1016
         sizeof( evt_file_header_t ),
1017
         first_record_offset );
1018
      }
1019
#endif
1020
2.33k
      if( libevt_io_handle_event_record_scan(
1021
2.33k
           io_handle,
1022
2.33k
           file_io_handle,
1023
2.33k
           (off64_t) sizeof( evt_file_header_t ),
1024
2.33k
           (size64_t) ( first_record_offset - sizeof( evt_file_header_t ) ),
1025
2.33k
           recovered_records_list,
1026
2.33k
           error ) != 1 )
1027
1.89k
      {
1028
#if defined( HAVE_DEBUG_OUTPUT )
1029
        if( libcnotify_verbose != 0 )
1030
        {
1031
          if( ( error != NULL )
1032
           && ( *error != NULL ) )
1033
          {
1034
            libcerror_error_free(
1035
             error );
1036
          }
1037
        }
1038
#endif
1039
1.89k
        libcerror_error_set(
1040
1.89k
         error,
1041
1.89k
         LIBCERROR_ERROR_DOMAIN_IO,
1042
1.89k
         LIBCERROR_IO_ERROR_READ_FAILED,
1043
1.89k
         "%s: unable to scan for event records.",
1044
1.89k
         function );
1045
1046
#if defined( HAVE_DEBUG_OUTPUT )
1047
        if( libcnotify_verbose != 0 )
1048
        {
1049
          if( ( error != NULL )
1050
           && ( *error != NULL ) )
1051
          {
1052
            libcnotify_print_error_backtrace(
1053
             *error );
1054
          }
1055
        }
1056
#endif
1057
1.89k
        libcerror_error_free(
1058
1.89k
         error );
1059
1.89k
      }
1060
2.33k
    }
1061
2.86k
    if( last_record_offset < (off64_t) io_handle->file_size )
1062
2.74k
    {
1063
#if defined( HAVE_DEBUG_OUTPUT )
1064
      if( libcnotify_verbose != 0 )
1065
      {
1066
        if( last_record_offset > (off64_t) sizeof( evt_file_header_t ) )
1067
        {
1068
          libcnotify_printf(
1069
           "%s: scanning unused space after records at offset: 0x%08" PRIx64 " - 0x%08" PRIx64 "\n",
1070
           function,
1071
           last_record_offset,
1072
           io_handle->file_size );
1073
        }
1074
        else
1075
        {
1076
          libcnotify_printf(
1077
           "%s: scanning unused space after header at offset: 0x%08" PRIx64 " - 0x%08" PRIx64 "\n",
1078
           function,
1079
           last_record_offset,
1080
           io_handle->file_size );
1081
        }
1082
      }
1083
#endif
1084
2.74k
      if( libevt_io_handle_event_record_scan(
1085
2.74k
           io_handle,
1086
2.74k
           file_io_handle,
1087
2.74k
           last_record_offset,
1088
2.74k
           io_handle->file_size - last_record_offset,
1089
2.74k
           recovered_records_list,
1090
2.74k
           error ) != 1 )
1091
300
      {
1092
#if defined( HAVE_DEBUG_OUTPUT )
1093
        if( libcnotify_verbose != 0 )
1094
        {
1095
          if( ( error != NULL )
1096
           && ( *error != NULL ) )
1097
          {
1098
            libcerror_error_free(
1099
             error );
1100
          }
1101
        }
1102
#endif
1103
300
        libcerror_error_set(
1104
300
         error,
1105
300
         LIBCERROR_ERROR_DOMAIN_IO,
1106
300
         LIBCERROR_IO_ERROR_READ_FAILED,
1107
300
         "%s: unable to scan for event records.",
1108
300
         function );
1109
1110
#if defined( HAVE_DEBUG_OUTPUT )
1111
        if( libcnotify_verbose != 0 )
1112
        {
1113
          if( ( error != NULL )
1114
           && ( *error != NULL ) )
1115
          {
1116
            libcnotify_print_error_backtrace(
1117
             *error );
1118
          }
1119
        }
1120
#endif
1121
300
        libcerror_error_free(
1122
300
         error );
1123
300
      }
1124
2.74k
    }
1125
2.86k
  }
1126
643
  else
1127
643
  {
1128
643
    if( last_record_offset < (off64_t) first_record_offset )
1129
18
    {
1130
#if defined( HAVE_DEBUG_OUTPUT )
1131
      if( libcnotify_verbose != 0 )
1132
      {
1133
        libcnotify_printf(
1134
         "%s: scanning unused space between records at offset: 0x%08" PRIx64 " - 0x%08" PRIx32 "\n",
1135
         function,
1136
         last_record_offset,
1137
         first_record_offset );
1138
      }
1139
#endif
1140
18
      if( libevt_io_handle_event_record_scan(
1141
18
           io_handle,
1142
18
           file_io_handle,
1143
18
           last_record_offset,
1144
18
           (size64_t) first_record_offset - last_record_offset,
1145
18
           recovered_records_list,
1146
18
           error ) != 1 )
1147
3
      {
1148
#if defined( HAVE_DEBUG_OUTPUT )
1149
        if( libcnotify_verbose != 0 )
1150
        {
1151
          if( ( error != NULL )
1152
           && ( *error != NULL ) )
1153
          {
1154
            libcerror_error_free(
1155
             error );
1156
          }
1157
        }
1158
#endif
1159
3
        libcerror_error_set(
1160
3
         error,
1161
3
         LIBCERROR_ERROR_DOMAIN_IO,
1162
3
         LIBCERROR_IO_ERROR_READ_FAILED,
1163
3
         "%s: unable to scan for event records.",
1164
3
         function );
1165
1166
#if defined( HAVE_DEBUG_OUTPUT )
1167
        if( libcnotify_verbose != 0 )
1168
        {
1169
          if( ( error != NULL )
1170
           && ( *error != NULL ) )
1171
          {
1172
            libcnotify_print_error_backtrace(
1173
             *error );
1174
          }
1175
        }
1176
#endif
1177
3
        libcerror_error_free(
1178
3
         error );
1179
3
      }
1180
18
    }
1181
643
  }
1182
3.50k
  return( 1 );
1183
3.50k
}
1184