Coverage Report

Created: 2024-02-25 07:20

/src/libvhdi/libcerror/libcerror_system.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * System functions
3
 *
4
 * Copyright (C) 2008-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 <memory.h>
24
#include <narrow_string.h>
25
#include <system_string.h>
26
#include <types.h>
27
#include <wide_string.h>
28
29
#if defined( HAVE_STDLIB_H ) || defined( WINAPI )
30
#include <stdlib.h>
31
#endif
32
33
#if defined( HAVE_STRING_H ) || defined( WINAPI )
34
#include <string.h>
35
#endif
36
37
#if defined( HAVE_STDARG_H ) || defined( WINAPI )
38
#include <stdarg.h>
39
#elif defined( HAVE_VARARGS_H )
40
#include <varargs.h>
41
#else
42
#error Missing headers stdarg.h and varargs.h
43
#endif
44
45
#include "libcerror_definitions.h"
46
#include "libcerror_error.h"
47
#include "libcerror_system.h"
48
#include "libcerror_types.h"
49
50
#if defined( WINAPI )
51
52
/* The make language identifier macro for the WINAPI FormatMessage function
53
 */
54
#if !defined( MAKELANGID )
55
#define MAKELANGID( primary_language_identifier, sub_language_identifier ) \
56
  ( ( ( (WORD) ( sub_language_identifier ) ) << 10 ) | (WORD) ( primary_language_identifier ) )
57
#endif
58
59
#if !defined( LANG_NEUTRAL )
60
#define LANG_NEUTRAL    0
61
#endif
62
63
#if !defined( SUBLANG_DEFAULT )
64
#define SUBLANG_DEFAULT   1
65
#endif
66
67
#endif /* defined( WINAPI ) */
68
69
#if defined( WINAPI ) && ( WINVER <= 0x0500 )
70
71
/* Cross Windows safe version of FormatMessageA
72
 * Returns the number of printed characters without the end-of-string character or 0 on error
73
 */
74
DWORD libcerror_FormatMessageA(
75
       DWORD flags,
76
       LPCVOID source,
77
       DWORD message_identifier,
78
       DWORD language_identifier,
79
       LPCSTR string,
80
       DWORD string_size,
81
       va_list *argument_list )
82
{
83
  FARPROC function       = NULL;
84
  HMODULE library_handle = NULL;
85
  DWORD print_count      = 0;
86
87
  if( string == NULL )
88
  {
89
    return( 0 );
90
  }
91
  library_handle = LoadLibrary(
92
                    _SYSTEM_STRING( "kernel32.dll" ) );
93
94
  if( library_handle == NULL )
95
  {
96
    return( 0 );
97
  }
98
  function = GetProcAddress(
99
              library_handle,
100
              (LPCSTR) "FormatMessageA" );
101
102
  if( function != NULL )
103
  {
104
    print_count = function(
105
                   flags,
106
                   source,
107
                   message_identifier,
108
                   language_identifier,
109
                   string,
110
                   string_size,
111
                   argument_list );
112
  }
113
  /* This call should be after using the function
114
   * in most cases kernel32.dll will still be available after free
115
   */
116
  if( FreeLibrary(
117
       library_handle ) != TRUE )
118
  {
119
    print_count = 0;
120
  }
121
  return( print_count );
122
}
123
124
/* Cross Windows safe version of FormatMessageW
125
 * Returns the number of printed characters without the end-of-string character or 0 on error
126
 */
127
DWORD libcerror_FormatMessageW(
128
       DWORD flags,
129
       LPCVOID source,
130
       DWORD message_identifier,
131
       DWORD language_identifier,
132
       LPWSTR string,
133
       DWORD string_size,
134
       va_list *argument_list )
135
{
136
  FARPROC function       = NULL;
137
  HMODULE library_handle = NULL;
138
  DWORD print_count      = 0;
139
140
  if( string == NULL )
141
  {
142
    return( 0 );
143
  }
144
  library_handle = LoadLibrary(
145
                    _SYSTEM_STRING( "kernel32.dll" ) );
146
147
  if( library_handle == NULL )
148
  {
149
    return( 0 );
150
  }
151
  function = GetProcAddress(
152
              library_handle,
153
              (LPCSTR) "FormatMessageW" );
154
155
  if( function != NULL )
156
  {
157
    print_count = function(
158
                   flags,
159
                   source,
160
                   message_identifier,
161
                   language_identifier,
162
                   string,
163
                   string_size,
164
                   argument_list );
165
  }
166
  /* This call should be after using the function
167
   * in most cases kernel32.dll will still be available after free
168
   */
169
  if( FreeLibrary(
170
       library_handle ) != TRUE )
171
  {
172
    print_count = 0;
173
  }
174
  return( print_count );
175
}
176
177
#endif /* defined( WINAPI ) && ( WINVER <= 0x0500 ) */
178
179
#if defined( WINAPI )
180
181
#if ( WINVER <= 0x0500 )
182
#if defined( HAVE_WIDE_SYSTEM_CHARACTER )
183
#define libcerror_system_FormatMessage libcerror_FormatMessageW
184
#else
185
#define libcerror_system_FormatMessage libcerror_FormatMessageA
186
#endif
187
188
#else
189
#if defined( HAVE_WIDE_SYSTEM_CHARACTER )
190
#define libcerror_system_FormatMessage FormatMessageW
191
#else
192
#define libcerror_system_FormatMessage FormatMessageA
193
#endif
194
#endif /* ( WINVER <= 0x0500 ) */
195
196
/* Retrieves a descriptive string of the error number
197
 * This function uses the WINAPI functions for Windows XP or later
198
 * Returns the string_length if successful or -1 on error
199
 */
200
int libcerror_system_copy_string_from_error_number(
201
     system_character_t *string,
202
     size_t string_size,
203
     uint32_t error_number )
204
{
205
  DWORD print_count = 0;
206
207
  if( string == NULL )
208
  {
209
    return( -1 );
210
  }
211
  if( string_size > (size_t) INT_MAX )
212
  {
213
    return( -1 );
214
  }
215
  print_count = libcerror_system_FormatMessage(
216
                 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
217
                 NULL,
218
                 (DWORD) error_number,
219
                 MAKELANGID(
220
                  LANG_NEUTRAL,
221
                  SUBLANG_DEFAULT ),
222
                 string,
223
                 (DWORD) string_size,
224
                 NULL );
225
226
  if( print_count == 0 )
227
  {
228
    return( -1 );
229
  }
230
  return( (int) print_count );
231
}
232
233
#elif defined( HAVE_STRERROR_R )
234
235
#if defined( HAVE_WIDE_SYSTEM_CHARACTER )
236
#error Missing wide character strerror_r function
237
#endif
238
239
/* Retrieves a descriptive string of the error number
240
 * This function uses the POSIX strerror_r function or equivalent
241
 * Returns the string_length if successful or -1 on error
242
 */
243
int libcerror_system_copy_string_from_error_number(
244
     system_character_t *string,
245
     size_t string_size,
246
     uint32_t error_number )
247
0
{
248
0
  size_t string_length = 0;
249
250
0
  if( string == NULL )
251
0
  {
252
0
    return( -1 );
253
0
  }
254
0
  if( string_size > (size_t) INT_MAX )
255
0
  {
256
0
    return( -1 );
257
0
  }
258
#if defined( STRERROR_R_CHAR_P )
259
  if( strerror_r(
260
       (int) error_number,
261
       string,
262
       string_size ) == NULL )
263
#else
264
0
  if( strerror_r(
265
0
       (int) error_number,
266
0
       string,
267
0
       string_size ) != 0 )
268
0
#endif
269
0
  {
270
0
    return( -1 );
271
0
  }
272
0
  string[ string_size - 1 ] = (system_character_t) 0;
273
274
0
  string_length = system_string_length(
275
0
                   string );
276
277
0
  return( (int) string_length );
278
0
}
279
280
#elif defined( HAVE_STRERROR )
281
282
#if defined( HAVE_WIDE_SYSTEM_CHARACTER )
283
#error Missing wide character strerror function
284
#endif
285
286
/* Retrieves a descriptive string of the error number
287
 * This function uses the POSIX strerror function or equivalent
288
 * Returns the string_length if successful or -1 on error
289
 */
290
int libcerror_system_copy_string_from_error_number(
291
     system_character_t *string,
292
     size_t string_size,
293
     uint32_t error_number )
294
{
295
#if defined( HAVE_WIDE_SYSTEM_CHARACTER )
296
  const wchar_t *static_error_string = NULL;
297
#else
298
  const char *static_error_string    = NULL;
299
#endif
300
  size_t static_error_string_length  = 0;
301
302
  if( string == NULL )
303
  {
304
    return( -1 );
305
  }
306
  if( string_size > (size_t) INT_MAX )
307
  {
308
    return( -1 );
309
  }
310
#if defined( HAVE_WIDE_SYSTEM_CHARACTER )
311
  static_error_string = _wcserror(
312
                         (int) error_number );
313
#else
314
  static_error_string = strerror(
315
                         (int) error_number );
316
#endif
317
318
  if( static_error_string == NULL )
319
  {
320
    return( -1 );
321
  }
322
  static_error_string_length = system_string_length(
323
                                static_error_string );
324
325
  if( system_string_copy(
326
       string,
327
       static_error_string,
328
       static_error_string_length ) == NULL )
329
  {
330
    return( -1 );
331
  }
332
  string[ static_error_string_length ] = 0;
333
334
  return( (int) static_error_string_length );
335
}
336
337
#else
338
#error Missing error to string system function
339
#endif
340
341
#if defined( HAVE_STDARG_H ) || defined( WINAPI )
342
#define VARARGS( function, error, error_domain, error_code, system_error_code, type, argument ) \
343
        function( error, error_domain, error_code, system_error_code, type argument, ... )
344
#define VASTART( argument_list, type, name ) \
345
0
        va_start( argument_list, name )
346
#define VAEND( argument_list ) \
347
0
        va_end( argument_list )
348
349
#elif defined( HAVE_VARARGS_H )
350
#define VARARGS( function, error, error_domain, error_code, system_error_code, type, argument ) \
351
        function( error, error_domain, error_code, system_error_code, va_alist ) va_dcl
352
#define VASTART( argument_list, type, name ) \
353
        { type name; va_start( argument_list ); name = va_arg( argument_list, type )
354
#define VAEND( argument_list ) \
355
        va_end( argument_list ); }
356
357
#endif
358
359
/* Sets an error and adds a system specific error string if possible
360
 * Creates the error if necessary
361
 * The error domain and code are set only the first time and the error message is appended for back tracing
362
 */
363
void VARARGS(
364
      libcerror_system_set_error,
365
      libcerror_error_t **error,
366
      int error_domain,
367
      int error_code,
368
      uint32_t system_error_code,
369
      const char *,
370
      format_string )
371
0
{
372
0
  va_list argument_list;
373
374
0
  libcerror_internal_error_t *internal_error = NULL;
375
0
  system_character_t *error_string           = NULL;
376
0
  system_character_t *system_format_string   = NULL;
377
0
  void *reallocation                         = NULL;
378
0
  size_t error_string_size                   = 0;
379
0
  size_t format_string_length                = 0;
380
0
  size_t message_size                        = 0;
381
0
  size_t next_message_size                   = LIBCERROR_MESSAGE_INCREMENT_SIZE;
382
0
  size_t string_index                        = 0;
383
0
  int message_index                          = 0;
384
0
  int print_count                            = 0;
385
386
0
  if( error == NULL )
387
0
  {
388
0
    return;
389
0
  }
390
0
  if( format_string == NULL )
391
0
  {
392
0
    return;
393
0
  }
394
0
  format_string_length = narrow_string_length(
395
0
                          format_string );
396
397
#if defined( HAVE_WIDE_SYSTEM_CHARACTER )
398
  libcerror_error_get_system_format_string(
399
   format_string,
400
   format_string_length,
401
   &system_format_string );
402
403
  if( system_format_string == NULL )
404
  {
405
    return;
406
  }
407
#else
408
0
  system_format_string = (system_character_t *) format_string;
409
0
#endif
410
0
  if( *error == NULL )
411
0
  {
412
0
    if( libcerror_error_initialize(
413
0
         error,
414
0
         error_domain,
415
0
         error_code ) != 1 )
416
0
    {
417
0
      goto on_error;
418
0
    }
419
0
  }
420
0
  internal_error = (libcerror_internal_error_t *) *error;
421
422
0
  if( libcerror_error_resize(
423
0
       internal_error ) != 1 )
424
0
  {
425
0
    goto on_error;
426
0
  }
427
0
  if( format_string_length > next_message_size )
428
0
  {
429
0
    next_message_size = ( ( format_string_length / LIBCERROR_MESSAGE_INCREMENT_SIZE ) + 1 )
430
0
                      * LIBCERROR_MESSAGE_INCREMENT_SIZE;
431
0
  }
432
0
  do
433
0
  {
434
0
    if( next_message_size >= LIBCERROR_MESSAGE_MAXIMUM_SIZE )
435
0
    {
436
0
      next_message_size = LIBCERROR_MESSAGE_MAXIMUM_SIZE;
437
0
    }
438
0
    reallocation = memory_reallocate(
439
0
                    error_string,
440
0
                    sizeof( system_character_t ) * next_message_size );
441
442
0
    if( reallocation == NULL )
443
0
    {
444
0
      memory_free(
445
0
       error_string );
446
447
0
      goto on_error;
448
0
    }
449
0
    error_string = (system_character_t *) reallocation;
450
451
0
    message_size = next_message_size;
452
453
    /* argument_list cannot be reused in successive calls to vsnprintf
454
     */
455
0
    VASTART(
456
0
     argument_list,
457
0
     const char *,
458
0
     format_string );
459
460
0
    print_count = system_string_vsnprintf(
461
0
                   error_string,
462
0
                   message_size,
463
0
                   system_format_string,
464
0
                   argument_list );
465
466
0
    VAEND(
467
0
     argument_list );
468
469
0
    if( print_count <= -1 )
470
0
    {
471
0
      next_message_size += LIBCERROR_MESSAGE_INCREMENT_SIZE;
472
0
    }
473
0
    else if( ( (size_t) print_count >= message_size )
474
0
          || ( error_string[ print_count ] != (system_character_t) 0 ) )
475
0
    {
476
0
      next_message_size = (size_t) ( print_count + 1 );
477
0
      print_count       = -1;
478
0
    }
479
0
    else
480
0
    {
481
0
      error_string_size = (size_t) print_count + 1;
482
0
    }
483
0
    if( message_size >= LIBCERROR_MESSAGE_MAXIMUM_SIZE )
484
0
    {
485
0
      break;
486
0
    }
487
0
  }
488
0
  while( print_count <= -1 );
489
490
0
  if( message_size >= LIBCERROR_MESSAGE_MAXIMUM_SIZE )
491
0
  {
492
0
    error_string[ LIBCERROR_MESSAGE_MAXIMUM_SIZE - 4 ] = (system_character_t) '.';
493
0
    error_string[ LIBCERROR_MESSAGE_MAXIMUM_SIZE - 3 ] = (system_character_t) '.';
494
0
    error_string[ LIBCERROR_MESSAGE_MAXIMUM_SIZE - 2 ] = (system_character_t) '.';
495
0
    error_string[ LIBCERROR_MESSAGE_MAXIMUM_SIZE - 1 ] = 0;
496
0
    error_string_size                                  = (size_t) LIBCERROR_MESSAGE_MAXIMUM_SIZE;
497
0
  }
498
0
  message_index = internal_error->number_of_messages - 1;
499
500
0
  internal_error->messages[ message_index ] = error_string;
501
0
  internal_error->sizes[ message_index ]    = error_string_size;
502
503
#if defined( HAVE_WIDE_SYSTEM_CHARACTER )
504
  memory_free(
505
   system_format_string );
506
507
  system_format_string = NULL;
508
#endif
509
510
0
  message_size = internal_error->sizes[ message_index ];
511
512
0
  if( message_size < LIBCERROR_MESSAGE_MAXIMUM_SIZE )
513
0
  {
514
/* TODO move to separate helper function */
515
0
    string_index = internal_error->sizes[ message_index ] - 1;
516
517
0
    if( ( internal_error->messages[ message_index ] != NULL )
518
0
     && ( ( internal_error->messages[ message_index ] )[ string_index - 1 ] == (system_character_t) '.' ) )
519
0
    {
520
0
      string_index -= 1;
521
0
    }
522
0
    reallocation = memory_reallocate(
523
0
                    internal_error->messages[ message_index ],
524
0
                    sizeof( system_character_t ) * ( message_size + 13 + 512 ) );
525
526
0
    if( reallocation == NULL )
527
0
    {
528
0
      memory_free(
529
0
       internal_error->messages[ message_index ] );
530
531
0
      internal_error->messages[ message_index ] = NULL;
532
533
0
      goto on_error;
534
0
    }
535
0
    internal_error->messages[ message_index ] = (system_character_t *) reallocation;
536
537
0
    if( system_string_copy(
538
0
         &( ( internal_error->messages[ message_index ] )[ string_index ] ),
539
0
         _SYSTEM_STRING( " with error: " ),
540
0
         13 ) == NULL )
541
0
    {
542
0
      memory_free(
543
0
       internal_error->messages[ message_index ] );
544
545
0
      internal_error->messages[ message_index ] = NULL;
546
547
0
      goto on_error;
548
0
    }
549
0
    internal_error->sizes[ message_index ] += 13;
550
0
    string_index                           += 13;
551
552
0
    print_count = libcerror_system_copy_string_from_error_number(
553
0
                   &( ( internal_error->messages[ message_index ] )[ string_index ] ),
554
0
                   512,
555
0
                   system_error_code );
556
557
0
    if( print_count == -1 )
558
0
    {
559
0
      goto on_error;
560
0
    }
561
0
    internal_error->sizes[ message_index ] += print_count;
562
0
  }
563
0
  if( internal_error->sizes[ message_index ] >= LIBCERROR_MESSAGE_MAXIMUM_SIZE )
564
0
  {
565
0
    internal_error->messages[ message_index ][ LIBCERROR_MESSAGE_MAXIMUM_SIZE - 4 ] = (system_character_t) '.';
566
0
    internal_error->messages[ message_index ][ LIBCERROR_MESSAGE_MAXIMUM_SIZE - 3 ] = (system_character_t) '.';
567
0
    internal_error->messages[ message_index ][ LIBCERROR_MESSAGE_MAXIMUM_SIZE - 2 ] = (system_character_t) '.';
568
0
    internal_error->messages[ message_index ][ LIBCERROR_MESSAGE_MAXIMUM_SIZE - 1 ] = 0;
569
0
    internal_error->sizes[ message_index ]                                          = (size_t) LIBCERROR_MESSAGE_MAXIMUM_SIZE;
570
0
  }
571
0
  return;
572
573
0
on_error:
574
#if defined( HAVE_WIDE_SYSTEM_CHARACTER )
575
  if( system_format_string != NULL )
576
  {
577
    memory_free(
578
     system_format_string );
579
  }
580
#endif
581
0
  return;
582
0
}
583
584
#undef VARARGS
585
#undef VASTART
586
#undef VAEND
587