1 /*
2 * System functions
3 *
4 * Copyright (C) 2008-2020, 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 */
libcerror_FormatMessageA(DWORD flags,LPCVOID source,DWORD message_identifier,DWORD language_identifier,LPCSTR string,DWORD string_size,va_list * argument_list)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 */
libcerror_FormatMessageW(DWORD flags,LPCVOID source,DWORD message_identifier,DWORD language_identifier,LPWSTR string,DWORD string_size,va_list * argument_list)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 */
libcerror_system_copy_string_from_error_number(system_character_t * string,size_t string_size,uint32_t error_number)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 */
libcerror_system_copy_string_from_error_number(system_character_t * string,size_t string_size,uint32_t error_number)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 {
248 size_t string_length = 0;
249
250 if( string == NULL )
251 {
252 return( -1 );
253 }
254 if( string_size > (size_t) INT_MAX )
255 {
256 return( -1 );
257 }
258 #if defined( STRERROR_R_CHAR_P )
259 if( strerror_r(
260 (int) error_number,
261 string,
262 string_size ) == NULL )
263 #else
264 if( strerror_r(
265 (int) error_number,
266 string,
267 string_size ) != 0 )
268 #endif
269 {
270 return( -1 );
271 }
272 string[ string_size - 1 ] = (system_character_t) 0;
273
274 string_length = system_string_length(
275 string );
276
277 return( (int) string_length );
278 }
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 */
libcerror_system_copy_string_from_error_number(system_character_t * string,size_t string_size,uint32_t error_number)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 va_start( argument_list, name )
346 #define VAEND( argument_list ) \
347 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 */
VARARGS(libcerror_system_set_error,libcerror_error_t ** error,int error_domain,int error_code,uint32_t system_error_code,const char *,format_string)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 {
372 va_list argument_list;
373
374 libcerror_internal_error_t *internal_error = NULL;
375 system_character_t *error_string = NULL;
376 system_character_t *system_format_string = NULL;
377 void *reallocation = NULL;
378 size_t error_string_size = 0;
379 size_t format_string_length = 0;
380 size_t message_size = 0;
381 size_t next_message_size = LIBCERROR_MESSAGE_INCREMENT_SIZE;
382 size_t string_index = 0;
383 int message_index = 0;
384 int print_count = 0;
385
386 if( error == NULL )
387 {
388 return;
389 }
390 if( format_string == NULL )
391 {
392 return;
393 }
394 format_string_length = narrow_string_length(
395 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 system_format_string = (system_character_t *) format_string;
409 #endif
410 if( *error == NULL )
411 {
412 if( libcerror_error_initialize(
413 error,
414 error_domain,
415 error_code ) != 1 )
416 {
417 goto on_error;
418 }
419 }
420 internal_error = (libcerror_internal_error_t *) *error;
421
422 if( libcerror_error_resize(
423 internal_error ) != 1 )
424 {
425 goto on_error;
426 }
427 if( format_string_length > next_message_size )
428 {
429 next_message_size = ( ( format_string_length / LIBCERROR_MESSAGE_INCREMENT_SIZE ) + 1 )
430 * LIBCERROR_MESSAGE_INCREMENT_SIZE;
431 }
432 do
433 {
434 if( next_message_size >= LIBCERROR_MESSAGE_MAXIMUM_SIZE )
435 {
436 next_message_size = LIBCERROR_MESSAGE_MAXIMUM_SIZE;
437 }
438 reallocation = memory_reallocate(
439 error_string,
440 sizeof( system_character_t ) * next_message_size );
441
442 if( reallocation == NULL )
443 {
444 memory_free(
445 error_string );
446
447 goto on_error;
448 }
449 error_string = (system_character_t *) reallocation;
450
451 message_size = next_message_size;
452
453 /* argument_list cannot be reused in successive calls to vsnprintf
454 */
455 VASTART(
456 argument_list,
457 const char *,
458 format_string );
459
460 print_count = system_string_vsnprintf(
461 error_string,
462 message_size,
463 system_format_string,
464 argument_list );
465
466 VAEND(
467 argument_list );
468
469 if( print_count <= -1 )
470 {
471 next_message_size += LIBCERROR_MESSAGE_INCREMENT_SIZE;
472 }
473 else if( ( (size_t) print_count >= message_size )
474 || ( error_string[ print_count ] != (system_character_t) 0 ) )
475 {
476 next_message_size = (size_t) ( print_count + 1 );
477 print_count = -1;
478 }
479 else
480 {
481 error_string_size = (size_t) print_count + 1;
482 }
483 if( message_size >= LIBCERROR_MESSAGE_MAXIMUM_SIZE )
484 {
485 break;
486 }
487 }
488 while( print_count <= -1 );
489
490 if( message_size >= LIBCERROR_MESSAGE_MAXIMUM_SIZE )
491 {
492 error_string[ LIBCERROR_MESSAGE_MAXIMUM_SIZE - 4 ] = (system_character_t) '.';
493 error_string[ LIBCERROR_MESSAGE_MAXIMUM_SIZE - 3 ] = (system_character_t) '.';
494 error_string[ LIBCERROR_MESSAGE_MAXIMUM_SIZE - 2 ] = (system_character_t) '.';
495 error_string[ LIBCERROR_MESSAGE_MAXIMUM_SIZE - 1 ] = 0;
496 error_string_size = (size_t) LIBCERROR_MESSAGE_MAXIMUM_SIZE;
497 }
498 message_index = internal_error->number_of_messages - 1;
499
500 internal_error->messages[ message_index ] = error_string;
501 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 message_size = internal_error->sizes[ message_index ];
511
512 if( message_size < LIBCERROR_MESSAGE_MAXIMUM_SIZE )
513 {
514 /* TODO move to separate helper function */
515 string_index = internal_error->sizes[ message_index ] - 1;
516
517 if( ( internal_error->messages[ message_index ] != NULL )
518 && ( ( internal_error->messages[ message_index ] )[ string_index - 1 ] == (system_character_t) '.' ) )
519 {
520 string_index -= 1;
521 }
522 reallocation = memory_reallocate(
523 internal_error->messages[ message_index ],
524 sizeof( system_character_t ) * ( message_size + 13 + 512 ) );
525
526 if( reallocation == NULL )
527 {
528 memory_free(
529 internal_error->messages[ message_index ] );
530
531 internal_error->messages[ message_index ] = NULL;
532
533 goto on_error;
534 }
535 internal_error->messages[ message_index ] = (system_character_t *) reallocation;
536
537 if( system_string_copy(
538 &( ( internal_error->messages[ message_index ] )[ string_index ] ),
539 _SYSTEM_STRING( " with error: " ),
540 13 ) == NULL )
541 {
542 memory_free(
543 internal_error->messages[ message_index ] );
544
545 internal_error->messages[ message_index ] = NULL;
546
547 goto on_error;
548 }
549 internal_error->sizes[ message_index ] += 13;
550 string_index += 13;
551
552 print_count = libcerror_system_copy_string_from_error_number(
553 &( ( internal_error->messages[ message_index ] )[ string_index ] ),
554 512,
555 system_error_code );
556
557 if( print_count == -1 )
558 {
559 goto on_error;
560 }
561 internal_error->sizes[ message_index ] += print_count;
562 }
563 if( internal_error->sizes[ message_index ] >= LIBCERROR_MESSAGE_MAXIMUM_SIZE )
564 {
565 internal_error->messages[ message_index ][ LIBCERROR_MESSAGE_MAXIMUM_SIZE - 4 ] = (system_character_t) '.';
566 internal_error->messages[ message_index ][ LIBCERROR_MESSAGE_MAXIMUM_SIZE - 3 ] = (system_character_t) '.';
567 internal_error->messages[ message_index ][ LIBCERROR_MESSAGE_MAXIMUM_SIZE - 2 ] = (system_character_t) '.';
568 internal_error->messages[ message_index ][ LIBCERROR_MESSAGE_MAXIMUM_SIZE - 1 ] = 0;
569 internal_error->sizes[ message_index ] = (size_t) LIBCERROR_MESSAGE_MAXIMUM_SIZE;
570 }
571 return;
572
573 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 return;
582 }
583
584 #undef VARARGS
585 #undef VASTART
586 #undef VAEND
587
588