libcerror_system.c 15.1 KB
Newer Older
1 2 3
/*
 * System functions
 *
4
 * Copyright (C) 2008-2018, Joachim Metz <joachim.metz@gmail.com>
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 *
 * Refer to AUTHORS for acknowledgements.
 *
 * This software is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this software.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <common.h>
#include <memory.h>
24 25
#include <narrow_string.h>
#include <system_string.h>
26
#include <types.h>
27
#include <wide_string.h>
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44

#if defined( HAVE_STDLIB_H ) || defined( WINAPI )
#include <stdlib.h>
#endif

#if defined( HAVE_STRING_H ) || defined( WINAPI )
#include <string.h>
#endif

#if defined( HAVE_STDARG_H ) || defined( WINAPI )
#include <stdarg.h>
#elif defined( HAVE_VARARGS_H )
#include <varargs.h>
#else
#error Missing headers stdarg.h and varargs.h
#endif

45
#include "libcerror_definitions.h"
46 47 48 49
#include "libcerror_error.h"
#include "libcerror_system.h"
#include "libcerror_types.h"

50 51
#if defined( WINAPI )

52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
/* The make language identifier macro for the WINAPI FormatMessage function
 */
#if !defined( MAKELANGID )
#define MAKELANGID( primary_language_identifier, sub_language_identifier ) \
	( ( ( (WORD) ( sub_language_identifier ) ) << 10 ) | (WORD) ( primary_language_identifier ) )
#endif

#if !defined( LANG_NEUTRAL )
#define LANG_NEUTRAL		0
#endif

#if !defined( SUBLANG_DEFAULT )
#define SUBLANG_DEFAULT		1
#endif

67 68
#endif /* defined( WINAPI ) */

69 70 71
#if defined( WINAPI ) && ( WINVER <= 0x0500 )

/* 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 75 76 77 78 79 80 81 82 83 84
 */
DWORD libcerror_FormatMessageA(
       DWORD flags,
       LPCVOID source,
       DWORD message_identifier,
       DWORD language_identifier,
       LPCSTR string,
       DWORD string_size,
       va_list *argument_list )
{
	FARPROC function       = NULL;
	HMODULE library_handle = NULL;
85
	DWORD print_count      = 0;
86 87 88

	if( string == NULL )
	{
89
		return( 0 );
90 91
	}
	library_handle = LoadLibrary(
92
	                  _SYSTEM_STRING( "kernel32.dll" ) );
93 94 95

	if( library_handle == NULL )
	{
96
		return( 0 );
97 98 99 100 101 102 103
	}
	function = GetProcAddress(
		    library_handle,
		    (LPCSTR) "FormatMessageA" );

	if( function != NULL )
	{
104 105 106 107 108 109 110 111
		print_count = function(
		               flags,
		               source,
		               message_identifier,
		               language_identifier,
		               string,
		               string_size,
		               argument_list );
112 113 114 115 116 117 118
	}
	/* This call should be after using the function
	 * in most cases kernel32.dll will still be available after free
	 */
	if( FreeLibrary(
	     library_handle ) != TRUE )
	{
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 128 129 130 131 132 133 134 135 136 137
 */
DWORD libcerror_FormatMessageW(
       DWORD flags,
       LPCVOID source,
       DWORD message_identifier,
       DWORD language_identifier,
       LPWSTR string,
       DWORD string_size,
       va_list *argument_list )
{
	FARPROC function       = NULL;
	HMODULE library_handle = NULL;
138
	DWORD print_count      = 0;
139 140 141

	if( string == NULL )
	{
142
		return( 0 );
143 144
	}
	library_handle = LoadLibrary(
145
	                  _SYSTEM_STRING( "kernel32.dll" ) );
146 147 148

	if( library_handle == NULL )
	{
149
		return( 0 );
150 151 152
	}
	function = GetProcAddress(
		    library_handle,
153
		    (LPCSTR) "FormatMessageW" );
154 155 156

	if( function != NULL )
	{
157 158 159 160 161 162 163 164
		print_count = function(
		               flags,
		               source,
		               message_identifier,
		               language_identifier,
		               string,
		               string_size,
		               argument_list );
165 166 167 168 169 170 171
	}
	/* This call should be after using the function
	 * in most cases kernel32.dll will still be available after free
	 */
	if( FreeLibrary(
	     library_handle ) != TRUE )
	{
172
		print_count = 0;
173
	}
174
	return( print_count );
175 176
}

177 178 179 180 181 182 183 184 185
#endif /* defined( WINAPI ) && ( WINVER <= 0x0500 ) */

#if defined( WINAPI )

#if ( WINVER <= 0x0500 )
#if defined( HAVE_WIDE_SYSTEM_CHARACTER )
#define libcerror_system_FormatMessage libcerror_FormatMessageW
#else
#define libcerror_system_FormatMessage libcerror_FormatMessageA
186 187
#endif

188 189 190 191 192 193 194
#else
#if defined( HAVE_WIDE_SYSTEM_CHARACTER )
#define libcerror_system_FormatMessage FormatMessageW
#else
#define libcerror_system_FormatMessage FormatMessageA
#endif
#endif /* ( WINVER <= 0x0500 ) */
195 196 197 198 199 200

/* Retrieves a descriptive string of the error number
 * This function uses the WINAPI functions for Windows XP or later
 * Returns the string_length if successful or -1 on error
 */
int libcerror_system_copy_string_from_error_number(
201
     system_character_t *string,
202 203 204 205 206 207 208 209 210 211 212 213 214
     size_t string_size,
     uint32_t error_number )
{
	DWORD print_count = 0;

	if( string == NULL )
	{
		return( -1 );
	}
	if( string_size > (size_t) INT_MAX )
	{
		return( -1 );
	}
215 216
	print_count = libcerror_system_FormatMessage(
	               FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
	               NULL,
	               (DWORD) error_number,
	               MAKELANGID(
	                LANG_NEUTRAL,
	                SUBLANG_DEFAULT ),
	               string,
	               (DWORD) string_size,
	               NULL );

	if( print_count == 0 )
	{
		return( -1 );
	}
	return( (int) print_count );
}

#elif defined( HAVE_STRERROR_R )

235 236 237 238
#if defined( HAVE_WIDE_SYSTEM_CHARACTER )
#error Missing wide character strerror_r function
#endif

239 240 241 242 243
/* Retrieves a descriptive string of the error number
 * This function uses the POSIX strerror_r function or equivalent
 * Returns the string_length if successful or -1 on error
 */
int libcerror_system_copy_string_from_error_number(
244
     system_character_t *string,
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
     size_t string_size,
     uint32_t error_number )
{
	size_t string_length = 0;

	if( string == NULL )
	{
		return( -1 );
	}
	if( string_size > (size_t) INT_MAX )
	{
		return( -1 );
	}
#if defined( STRERROR_R_CHAR_P )
	if( strerror_r(
	     (int) error_number,
	     string,
	     string_size ) == NULL )
#else
	if( strerror_r(
	     (int) error_number,
	     string,
	     string_size ) != 0 )
#endif
	{
		return( -1 );
	}
272
	string[ string_size - 1 ] = (system_character_t) 0;
273

274
	string_length = system_string_length(
275 276 277 278 279
	                 string );

	return( (int) string_length );
}

280 281 282 283 284
#elif defined( HAVE_STRERROR )

#if defined( HAVE_WIDE_SYSTEM_CHARACTER )
#error Missing wide character strerror function
#endif
285 286 287 288 289 290

/* Retrieves a descriptive string of the error number
 * This function uses the POSIX strerror function or equivalent
 * Returns the string_length if successful or -1 on error
 */
int libcerror_system_copy_string_from_error_number(
291
     system_character_t *string,
292 293 294
     size_t string_size,
     uint32_t error_number )
{
295
#if defined( HAVE_WIDE_SYSTEM_CHARACTER )
296 297 298 299 300 301 302 303 304 305 306 307 308 309
	const wchar_t *static_error_string = NULL;
#else
	const char *static_error_string    = NULL;
#endif
	size_t static_error_string_length  = 0;

	if( string == NULL )
	{
		return( -1 );
	}
	if( string_size > (size_t) INT_MAX )
	{
		return( -1 );
	}
310
#if defined( HAVE_WIDE_SYSTEM_CHARACTER )
311 312 313 314 315 316 317 318 319 320 321
	static_error_string = _wcserror(
	                       (int) error_number );
#else
	static_error_string = strerror(
	                       (int) error_number );
#endif

	if( static_error_string == NULL )
	{
		return( -1 );
	}
322
	static_error_string_length = system_string_length(
323 324
	                              static_error_string );

325
	if( system_string_copy(
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
	     string,
	     static_error_string,
	     static_error_string_length ) == NULL )
	{
		return( -1 );
	}
	string[ static_error_string_length ] = 0;

	return( (int) static_error_string_length );
}

#else
#error Missing error to string system function
#endif

#if defined( HAVE_STDARG_H ) || defined( WINAPI )
#define VARARGS( function, error, error_domain, error_code, system_error_code, type, argument ) \
        function( error, error_domain, error_code, system_error_code, type argument, ... )
#define VASTART( argument_list, type, name ) \
        va_start( argument_list, name )
#define VAEND( argument_list ) \
        va_end( argument_list )

#elif defined( HAVE_VARARGS_H )
#define VARARGS( function, error, error_domain, error_code, system_error_code, type, argument ) \
        function( error, error_domain, error_code, system_error_code, va_alist ) va_dcl
#define VASTART( argument_list, type, name ) \
        { type name; va_start( argument_list ); name = va_arg( argument_list, type )
#define VAEND( argument_list ) \
        va_end( argument_list ); }

#endif

/* Sets an error and adds a system specific error string if possible
 * Creates the error if necessary
 * The error domain and code are set only the first time and the error message is appended for back tracing
 */
void VARARGS(
      libcerror_system_set_error,
      libcerror_error_t **error,
      int error_domain,
      int error_code,
      uint32_t system_error_code,
      const char *,
      format_string )
{
	va_list argument_list;

374
	libcerror_internal_error_t *internal_error = NULL;
375
	system_character_t *error_string           = NULL;
376 377
	system_character_t *system_format_string   = NULL;
	void *reallocation                         = NULL;
378
	size_t error_string_size                   = 0;
379
	size_t format_string_length                = 0;
380 381
	size_t message_size                        = 0;
	size_t next_message_size                   = LIBCERROR_MESSAGE_INCREMENT_SIZE;
382 383 384
	size_t string_index                        = 0;
	int message_index                          = 0;
	int print_count                            = 0;
385 386 387 388 389 390 391 392 393

	if( error == NULL )
	{
		return;
	}
	if( format_string == NULL )
	{
		return;
	}
394
	format_string_length = narrow_string_length(
395 396
	                        format_string );

397
#if defined( HAVE_WIDE_SYSTEM_CHARACTER )
398 399 400 401
	libcerror_error_get_system_format_string(
	 format_string,
	 format_string_length,
	 &system_format_string );
402

403 404 405
	if( system_format_string == NULL )
	{
		return;
406 407
	}
#else
408
	system_format_string = (system_character_t *) format_string;
409 410 411
#endif
	if( *error == NULL )
	{
412 413 414 415
		if( libcerror_error_initialize(
		     error,
		     error_domain,
		     error_code ) != 1 )
416 417 418 419
		{
			goto on_error;
		}
	}
420
	internal_error = (libcerror_internal_error_t *) *error;
421

422 423
	if( libcerror_error_resize(
	     internal_error ) != 1 )
424 425 426
	{
		goto on_error;
	}
427
	if( format_string_length > next_message_size )
428
	{
429 430
		next_message_size = ( ( format_string_length / LIBCERROR_MESSAGE_INCREMENT_SIZE ) + 1 )
		                  * LIBCERROR_MESSAGE_INCREMENT_SIZE;
431
	}
432 433
	message_index = internal_error->number_of_messages - 1;
	error_string  = internal_error->messages[ message_index ];
434 435 436

	do
	{
437 438 439 440
		if( next_message_size >= LIBCERROR_MESSAGE_MAXIMUM_SIZE )
		{
			next_message_size = LIBCERROR_MESSAGE_MAXIMUM_SIZE;
		}
441
		reallocation = memory_reallocate(
442 443
		                error_string,
		                sizeof( system_character_t ) * next_message_size );
444 445 446 447

		if( reallocation == NULL )
		{
			memory_free(
448
			 error_string );
449

450
			goto on_error;
451
		}
452 453 454
		error_string = (system_character_t *) reallocation;

		message_size = next_message_size;
455

456 457
		/* argument_list cannot be reused in successive calls to vsnprintf
		 */
458 459 460 461 462
		VASTART(
		 argument_list,
		 const char *,
		 format_string );

463 464
		print_count = system_string_vsnprintf(
		               error_string,
465 466 467 468 469 470 471 472 473
		               message_size,
		               system_format_string,
		               argument_list );

		VAEND(
		 argument_list );

		if( print_count <= -1 )
		{
474
			next_message_size += LIBCERROR_MESSAGE_INCREMENT_SIZE;
475
		}
476 477
		else if( ( (size_t) print_count >= message_size )
		      || ( error_string[ print_count ] != (system_character_t) 0 ) )
478
		{
479 480 481 482 483 484
			next_message_size = (size_t) ( print_count + 1 );
			print_count       = -1;
		}
		else
		{
			error_string_size = (size_t) print_count + 1;
485 486 487 488 489 490 491 492
		}
		if( message_size >= LIBCERROR_MESSAGE_MAXIMUM_SIZE )
		{
			break;
		}
	}
	while( print_count <= -1 );

493 494 495 496 497 498 499 500 501 502 503
	if( message_size >= LIBCERROR_MESSAGE_MAXIMUM_SIZE )
	{
		error_string[ LIBCERROR_MESSAGE_MAXIMUM_SIZE - 4 ] = (system_character_t) '.';
		error_string[ LIBCERROR_MESSAGE_MAXIMUM_SIZE - 3 ] = (system_character_t) '.';
		error_string[ LIBCERROR_MESSAGE_MAXIMUM_SIZE - 2 ] = (system_character_t) '.';
		error_string[ LIBCERROR_MESSAGE_MAXIMUM_SIZE - 1 ] = 0;
		error_string_size                                  = (size_t) LIBCERROR_MESSAGE_MAXIMUM_SIZE;
	}
	internal_error->messages[ message_index ] = error_string;
	internal_error->sizes[ message_index ]    = error_string_size;

504
#if defined( HAVE_WIDE_SYSTEM_CHARACTER )
505 506 507 508 509 510
	memory_free(
	 system_format_string );

	system_format_string = NULL;
#endif

511
	message_size = internal_error->sizes[ message_index ];
512

513
	if( message_size < LIBCERROR_MESSAGE_MAXIMUM_SIZE )
514
	{
515 516
/* TODO move to separate helper function */
		string_index = internal_error->sizes[ message_index ] - 1;
517

518 519 520 521 522 523 524 525
		if( ( internal_error->messages[ message_index ] != NULL )
		 && ( ( internal_error->messages[ message_index ] )[ string_index - 1 ] == (system_character_t) '.' ) )
		{
			string_index -= 1;
		}
		reallocation = memory_reallocate(
				internal_error->messages[ message_index ],
				sizeof( system_character_t ) * ( message_size + 13 + 512 ) );
526

527 528 529 530
		if( reallocation == NULL )
		{
			memory_free(
			 internal_error->messages[ message_index ] );
531

532
			internal_error->messages[ message_index ] = NULL;
533

534 535 536
			goto on_error;
		}
		internal_error->messages[ message_index ] = (system_character_t *) reallocation;
537

538 539 540 541 542 543 544
		if( system_string_copy(
		     &( ( internal_error->messages[ message_index ] )[ string_index ] ),
		     _SYSTEM_STRING( " with error: " ),
		     13 ) == NULL )
		{
			memory_free(
			 internal_error->messages[ message_index ] );
545

546
			internal_error->messages[ message_index ] = NULL;
547

548 549 550 551
			goto on_error;
		}
		internal_error->sizes[ message_index ] += 13;
		string_index                           += 13;
552

553 554 555 556
		print_count = libcerror_system_copy_string_from_error_number(
		               &( ( internal_error->messages[ message_index ] )[ string_index ] ),
		               512,
		               system_error_code );
557

558 559 560 561 562
		if( print_count == -1 )
		{
			goto on_error;
		}
		message_size += (size_t) print_count;
563

564 565 566 567 568 569 570 571 572
		internal_error->sizes[ message_index ] += print_count;
	}
	if( internal_error->sizes[ message_index ] >= LIBCERROR_MESSAGE_MAXIMUM_SIZE )
	{
		internal_error->messages[ message_index ][ LIBCERROR_MESSAGE_MAXIMUM_SIZE - 4 ] = (system_character_t) '.';
		internal_error->messages[ message_index ][ LIBCERROR_MESSAGE_MAXIMUM_SIZE - 3 ] = (system_character_t) '.';
		internal_error->messages[ message_index ][ LIBCERROR_MESSAGE_MAXIMUM_SIZE - 2 ] = (system_character_t) '.';
		internal_error->messages[ message_index ][ LIBCERROR_MESSAGE_MAXIMUM_SIZE - 1 ] = 0;
		internal_error->sizes[ message_index ]                                          = (size_t) LIBCERROR_MESSAGE_MAXIMUM_SIZE;
573 574 575 576
	}
	return;

on_error:
577
#if defined( HAVE_WIDE_SYSTEM_CHARACTER )
578 579 580 581 582 583 584 585 586 587 588 589 590
	if( system_format_string != NULL )
	{
		memory_free(
		 system_format_string );
	}
#endif
	return;
}

#undef VARARGS
#undef VASTART
#undef VAEND