1 /*
2 * Error 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_STDARG_H ) || defined( WINAPI )
30 #include <stdarg.h>
31 #elif defined( HAVE_VARARGS_H )
32 #include <varargs.h>
33 #else
34 #error Missing headers stdarg.h and varargs.h
35 #endif
36
37 #include <errno.h>
38
39 #include "libcerror_definitions.h"
40 #include "libcerror_error.h"
41 #include "libcerror_types.h"
42
43 /* Creates an error
44 * Returns 1 if successful or -1 on error
45 */
libcerror_error_initialize(libcerror_error_t ** error,int error_domain,int error_code)46 int libcerror_error_initialize(
47 libcerror_error_t **error,
48 int error_domain,
49 int error_code )
50 {
51 libcerror_internal_error_t *internal_error = NULL;
52
53 if( error == NULL )
54 {
55 return( -1 );
56 }
57 if( *error != NULL )
58 {
59 return( -1 );
60 }
61 internal_error = memory_allocate_structure(
62 libcerror_internal_error_t );
63
64 if( internal_error == NULL )
65 {
66 return( -1 );
67 }
68 internal_error->domain = error_domain;
69 internal_error->code = error_code;
70 internal_error->number_of_messages = 0;
71 internal_error->messages = NULL;
72 internal_error->sizes = NULL;
73
74 *error = (libcerror_error_t *) internal_error;
75
76 return( 1 );
77 }
78
79 /* Free an error and its elements
80 */
libcerror_error_free(libcerror_error_t ** error)81 void libcerror_error_free(
82 libcerror_error_t **error )
83 {
84 libcerror_internal_error_t *internal_error = NULL;
85 int message_index = 0;
86
87 if( error == NULL )
88 {
89 return;
90 }
91 if( *error != NULL )
92 {
93 internal_error = (libcerror_internal_error_t *) *error;
94
95 if( internal_error->messages != NULL )
96 {
97 for( message_index = 0;
98 message_index < internal_error->number_of_messages;
99 message_index++ )
100 {
101 if( internal_error->messages[ message_index ] != NULL )
102 {
103 memory_free(
104 internal_error->messages[ message_index ] );
105 }
106 }
107 memory_free(
108 internal_error->messages );
109 }
110 if( internal_error->sizes != NULL )
111 {
112 memory_free(
113 internal_error->sizes );
114 }
115 memory_free(
116 *error );
117
118 *error = NULL;
119 }
120 }
121
122 /* Resizes an error
123 * Returns 1 if successful or -1 on error
124 */
libcerror_error_resize(libcerror_internal_error_t * internal_error)125 int libcerror_error_resize(
126 libcerror_internal_error_t *internal_error )
127 {
128 void *reallocation = NULL;
129 int message_index = 0;
130 int number_of_messages = 0;
131
132 if( internal_error == NULL )
133 {
134 return( -1 );
135 }
136 message_index = internal_error->number_of_messages;
137 number_of_messages = internal_error->number_of_messages + 1;
138
139 reallocation = memory_reallocate(
140 internal_error->messages,
141 sizeof( system_character_t * ) * number_of_messages );
142
143 if( reallocation == NULL )
144 {
145 return( -1 );
146 }
147 internal_error->messages = (system_character_t **) reallocation;
148
149 internal_error->messages[ message_index ] = NULL;
150
151 reallocation = memory_reallocate(
152 internal_error->sizes,
153 sizeof( size_t ) * number_of_messages );
154
155 if( reallocation == NULL )
156 {
157 return( -1 );
158 }
159 internal_error->sizes = (size_t *) reallocation;
160
161 internal_error->sizes[ message_index ] = 0;
162
163 internal_error->number_of_messages += 1;
164
165 return( 1 );
166 }
167
168 #if defined( HAVE_WIDE_SYSTEM_CHARACTER )
169
170 /* Retrieves the format string as a system string
171 */
libcerror_error_get_system_format_string(const char * format_string,size_t format_string_length,system_character_t ** system_format_string)172 void libcerror_error_get_system_format_string(
173 const char *format_string,
174 size_t format_string_length,
175 system_character_t **system_format_string )
176 {
177 void *reallocation = NULL;
178 size_t next_format_string_length = 0;
179 int print_count = 0;
180
181 #if defined( __BORLANDC__ ) || defined( _MSC_VER )
182 size_t string_index = 0;
183 #endif
184
185 if( format_string == NULL )
186 {
187 return;
188 }
189 if( format_string_length > (size_t) SSIZE_MAX )
190 {
191 return;
192 }
193 if( system_format_string == NULL )
194 {
195 return;
196 }
197 next_format_string_length = format_string_length + 1;
198
199 do
200 {
201 if( next_format_string_length >= LIBCERROR_MESSAGE_MAXIMUM_SIZE )
202 {
203 next_format_string_length = LIBCERROR_MESSAGE_MAXIMUM_SIZE;
204 }
205 reallocation = memory_reallocate(
206 *system_format_string,
207 sizeof( system_character_t ) * next_format_string_length );
208
209 if( reallocation == NULL )
210 {
211 memory_free(
212 *system_format_string );
213
214 *system_format_string = NULL;
215
216 return;
217 }
218 *system_format_string = (system_character_t *) reallocation;
219
220 format_string_length = next_format_string_length;
221
222 #if defined( __BORLANDC__ ) || defined( _MSC_VER )
223 print_count = wide_string_snwprintf(
224 *system_format_string,
225 format_string_length,
226 L"%S",
227 format_string );
228 #else
229 print_count = wide_string_snwprintf(
230 *system_format_string,
231 format_string_length,
232 L"%s",
233 format_string );
234 #endif
235 if( print_count <= -1 )
236 {
237 next_format_string_length += LIBCERROR_MESSAGE_INCREMENT_SIZE;
238 }
239 else if( ( (size_t) print_count > format_string_length )
240 || ( ( *system_format_string )[ print_count ] != 0 ) )
241 {
242 next_format_string_length = (size_t) print_count;
243 print_count = -1;
244 }
245 if( next_format_string_length >= LIBCERROR_MESSAGE_MAXIMUM_SIZE )
246 {
247 /* TODO handle similar to error string */
248 memory_free(
249 *system_format_string );
250
251 *system_format_string = NULL;
252
253 return;
254 }
255 }
256 while( print_count <= -1 );
257
258 #if defined( __BORLANDC__ ) || defined( _MSC_VER )
259 /* Rewrite %s to %S
260 */
261 string_index = 0;
262
263 while( string_index < format_string_length )
264 {
265 if( ( *system_format_string )[ string_index ] == 0 )
266 {
267 break;
268 }
269 else if( ( *system_format_string )[ string_index ] == (system_character_t) '%' )
270 {
271 string_index++;
272
273 if( ( *system_format_string )[ string_index ] == (system_character_t) 's' )
274 {
275 ( *system_format_string )[ string_index ] = (system_character_t) 'S';
276 }
277 }
278 string_index++;
279 }
280 #endif /* defined( __BORLANDC__ ) || defined( _MSC_VER ) */
281 }
282
283 #endif /* defined( HAVE_WIDE_SYSTEM_CHARACTER ) */
284
285 #if defined( HAVE_STDARG_H ) || defined( WINAPI )
286 #define VARARGS( function, error, error_domain, error_code, type, argument ) \
287 function( error, error_domain, error_code, type argument, ... )
288 #define VASTART( argument_list, type, name ) \
289 va_start( argument_list, name )
290 #define VAEND( argument_list ) \
291 va_end( argument_list )
292
293 #elif defined( HAVE_VARARGS_H )
294 #define VARARGS( function, error, error_domain, error_code, type, argument ) \
295 function( error, error_domain, error_code, va_alist ) va_dcl
296 #define VASTART( argument_list, type, name ) \
297 { type name; va_start( argument_list ); name = va_arg( argument_list, type )
298 #define VAEND( argument_list ) \
299 va_end( argument_list ); }
300
301 #endif /* defined( HAVE_STDARG_H ) || defined( WINAPI ) */
302
303 /* Sets an error
304 * Creates the error if necessary
305 * The error domain and code are set only the first time and the error message is appended for back tracing
306 */
VARARGS(libcerror_error_set,libcerror_error_t ** error,int error_domain,int error_code,const char *,format_string)307 void VARARGS(
308 libcerror_error_set,
309 libcerror_error_t **error,
310 int error_domain,
311 int error_code,
312 const char *,
313 format_string )
314 {
315 va_list argument_list;
316
317 libcerror_internal_error_t *internal_error = NULL;
318 system_character_t *error_string = NULL;
319 system_character_t *system_format_string = NULL;
320 void *reallocation = NULL;
321 size_t error_string_size = 0;
322 size_t format_string_length = 0;
323 size_t message_size = 0;
324 size_t next_message_size = LIBCERROR_MESSAGE_INCREMENT_SIZE;
325 int message_index = 0;
326 int print_count = 0;
327
328 if( error == NULL )
329 {
330 return;
331 }
332 if( format_string == NULL )
333 {
334 return;
335 }
336 format_string_length = narrow_string_length(
337 format_string );
338
339 #if defined( HAVE_WIDE_SYSTEM_CHARACTER )
340 libcerror_error_get_system_format_string(
341 format_string,
342 format_string_length,
343 &system_format_string );
344
345 if( system_format_string == NULL )
346 {
347 return;
348 }
349 #else
350 system_format_string = (system_character_t *) format_string;
351 #endif
352 if( *error == NULL )
353 {
354 if( libcerror_error_initialize(
355 error,
356 error_domain,
357 error_code ) != 1 )
358 {
359 goto on_error;
360 }
361 }
362 internal_error = (libcerror_internal_error_t *) *error;
363
364 if( libcerror_error_resize(
365 internal_error ) != 1 )
366 {
367 goto on_error;
368 }
369 if( format_string_length > next_message_size )
370 {
371 next_message_size = ( ( format_string_length / LIBCERROR_MESSAGE_INCREMENT_SIZE ) + 1 )
372 * LIBCERROR_MESSAGE_INCREMENT_SIZE;
373 }
374 do
375 {
376 if( next_message_size >= LIBCERROR_MESSAGE_MAXIMUM_SIZE )
377 {
378 next_message_size = LIBCERROR_MESSAGE_MAXIMUM_SIZE;
379 }
380 reallocation = memory_reallocate(
381 error_string,
382 sizeof( system_character_t ) * next_message_size );
383
384 if( reallocation == NULL )
385 {
386 memory_free(
387 error_string );
388
389 goto on_error;
390 }
391 error_string = (system_character_t *) reallocation;
392
393 message_size = next_message_size;
394
395 /* argument_list cannot be reused in successive calls to vsnprintf
396 */
397 VASTART(
398 argument_list,
399 const char *,
400 format_string );
401
402 print_count = system_string_vsnprintf(
403 error_string,
404 message_size,
405 system_format_string,
406 argument_list );
407
408 VAEND(
409 argument_list );
410
411 if( print_count <= -1 )
412 {
413 next_message_size += LIBCERROR_MESSAGE_INCREMENT_SIZE;
414 }
415 else if( ( (size_t) print_count >= message_size )
416 || ( error_string[ print_count ] != (system_character_t) 0 ) )
417 {
418 next_message_size = (size_t) ( print_count + 1 );
419 print_count = -1;
420 }
421 else
422 {
423 error_string_size = (size_t) print_count + 1;
424 }
425 if( message_size >= LIBCERROR_MESSAGE_MAXIMUM_SIZE )
426 {
427 break;
428 }
429 }
430 while( print_count <= -1 );
431
432 if( message_size >= LIBCERROR_MESSAGE_MAXIMUM_SIZE )
433 {
434 error_string[ LIBCERROR_MESSAGE_MAXIMUM_SIZE - 4 ] = (system_character_t) '.';
435 error_string[ LIBCERROR_MESSAGE_MAXIMUM_SIZE - 3 ] = (system_character_t) '.';
436 error_string[ LIBCERROR_MESSAGE_MAXIMUM_SIZE - 2 ] = (system_character_t) '.';
437 error_string[ LIBCERROR_MESSAGE_MAXIMUM_SIZE - 1 ] = 0;
438 error_string_size = (size_t) LIBCERROR_MESSAGE_MAXIMUM_SIZE;
439 }
440 message_index = internal_error->number_of_messages - 1;
441
442 internal_error->messages[ message_index ] = error_string;
443 internal_error->sizes[ message_index ] = error_string_size;
444
445 #if defined( HAVE_WIDE_SYSTEM_CHARACTER )
446 memory_free(
447 system_format_string );
448
449 system_format_string = NULL;
450 #endif
451 return;
452
453 on_error:
454 #if defined( HAVE_WIDE_SYSTEM_CHARACTER )
455 if( system_format_string != NULL )
456 {
457 memory_free(
458 system_format_string );
459 }
460 #endif
461 return;
462 }
463
464 #undef VARARGS
465 #undef VASTART
466 #undef VAEND
467
468 /* Determines if an error equals a certain error code of a domain
469 * Returns 1 if error matches or 0 if not
470 */
libcerror_error_matches(libcerror_error_t * error,int error_domain,int error_code)471 int libcerror_error_matches(
472 libcerror_error_t *error,
473 int error_domain,
474 int error_code )
475 {
476 if( error == NULL )
477 {
478 return( 0 );
479 }
480 if( ( ( (libcerror_internal_error_t *) error )->domain == error_domain )
481 && ( ( (libcerror_internal_error_t *) error )->code == error_code ) )
482 {
483 return( 1 );
484 }
485 return( 0 );
486 }
487
488 /* Prints a descriptive string of the error to the stream
489 * Returns the number of printed characters if successful or -1 on error
490 */
libcerror_error_fprint(libcerror_error_t * error,FILE * stream)491 int libcerror_error_fprint(
492 libcerror_error_t *error,
493 FILE *stream )
494 {
495 libcerror_internal_error_t *internal_error = NULL;
496 system_character_t *error_string = NULL;
497 int message_index = 0;
498 int print_count = 0;
499
500 #if defined( WINAPI )
501 const char *format_string = "%" PRIs_SYSTEM "\r\n";
502 #else
503 const char *format_string = "%" PRIs_SYSTEM "\n";
504 #endif
505
506 if( error == NULL )
507 {
508 return( -1 );
509 }
510 internal_error = (libcerror_internal_error_t *) error;
511
512 if( internal_error->messages == NULL )
513 {
514 return( -1 );
515 }
516 if( stream == NULL )
517 {
518 return( -1 );
519 }
520 message_index = internal_error->number_of_messages - 1;
521 error_string = internal_error->messages[ message_index ];
522
523 if( error_string != NULL )
524 {
525 print_count = fprintf(
526 stream,
527 format_string,
528 error_string );
529
530 if( print_count <= -1 )
531 {
532 return( -1 );
533 }
534 }
535 return( print_count );
536 }
537
538 /* Prints a descriptive string of the error to the string
539 * The end-of-string character is not included in the return value
540 * Returns the number of printed characters if successful or -1 on error
541 */
libcerror_error_sprint(libcerror_error_t * error,char * string,size_t size)542 int libcerror_error_sprint(
543 libcerror_error_t *error,
544 char *string,
545 size_t size )
546 {
547 libcerror_internal_error_t *internal_error = NULL;
548 system_character_t *error_string = NULL;
549 size_t message_index = 0;
550 size_t print_count = 0;
551
552 #if !defined( HAVE_WIDE_SYSTEM_CHARACTER )
553 size_t error_string_size = 0;
554 #endif
555
556 if( error == NULL )
557 {
558 return( -1 );
559 }
560 internal_error = (libcerror_internal_error_t *) error;
561
562 if( internal_error->messages == NULL )
563 {
564 return( -1 );
565 }
566 if( internal_error->sizes == NULL )
567 {
568 return( -1 );
569 }
570 if( string == NULL )
571 {
572 return( -1 );
573 }
574 #if INT_MAX < SSIZE_MAX
575 if( size > (size_t) INT_MAX )
576 #else
577 if( size > (size_t) SSIZE_MAX )
578 #endif
579 {
580 return( -1 );
581 }
582 message_index = internal_error->number_of_messages - 1;
583 error_string = internal_error->messages[ message_index ];
584
585 if( error_string != NULL )
586 {
587 #if defined( HAVE_WIDE_SYSTEM_CHARACTER )
588 #if defined( _MSC_VER )
589 if( wcstombs_s(
590 &print_count,
591 string,
592 size,
593 error_string,
594 _TRUNCATE ) != 0 )
595 {
596 return( -1 );
597 }
598 #else
599 print_count = wcstombs(
600 string,
601 error_string,
602 size );
603
604 if( print_count == (size_t) -1 )
605 {
606 return( -1 );
607 }
608 #endif /* defined( _MSC_VER ) */
609
610 if( print_count >= size )
611 {
612 return( -1 );
613 }
614 #else
615 error_string_size = internal_error->sizes[ message_index ];
616
617 if( size < ( error_string_size + 1 ) )
618 {
619 return( -1 );
620 }
621 if( narrow_string_copy(
622 string,
623 error_string,
624 error_string_size ) == NULL )
625 {
626 return( -1 );
627 }
628 print_count = error_string_size;
629
630 #endif /* defined( HAVE_WIDE_SYSTEM_CHARACTER ) */
631 }
632 if( print_count > (size_t) INT_MAX )
633 {
634 return( -1 );
635 }
636 return( (int) print_count );
637 }
638
639 /* Prints a backtrace of the error to the stream
640 * Returns the number of printed characters if successful or -1 on error
641 */
libcerror_error_backtrace_fprint(libcerror_error_t * error,FILE * stream)642 int libcerror_error_backtrace_fprint(
643 libcerror_error_t *error,
644 FILE *stream )
645 {
646 libcerror_internal_error_t *internal_error = NULL;
647 system_character_t *error_string = NULL;
648 int message_index = 0;
649 int print_count = 0;
650 int total_print_count = 0;
651
652 #if defined( WINAPI )
653 const char *format_string = "%" PRIs_SYSTEM "\r\n";
654 #else
655 const char *format_string = "%" PRIs_SYSTEM "\n";
656 #endif
657
658 if( error == NULL )
659 {
660 return( -1 );
661 }
662 internal_error = (libcerror_internal_error_t *) error;
663
664 if( internal_error->messages == NULL )
665 {
666 return( -1 );
667 }
668 if( stream == NULL )
669 {
670 return( -1 );
671 }
672 for( message_index = 0;
673 message_index < internal_error->number_of_messages;
674 message_index++ )
675 {
676 error_string = internal_error->messages[ message_index ];
677
678 if( error_string != NULL )
679 {
680 print_count = fprintf(
681 stream,
682 format_string,
683 error_string );
684
685 if( print_count <= -1 )
686 {
687 return( -1 );
688 }
689 total_print_count += print_count;
690 }
691 }
692 return( total_print_count );
693 }
694
695 /* Prints a backtrace of the error to the string
696 * The end-of-string character is not included in the return value
697 * Returns the number of printed characters if successful or -1 on error
698 */
libcerror_error_backtrace_sprint(libcerror_error_t * error,char * string,size_t size)699 int libcerror_error_backtrace_sprint(
700 libcerror_error_t *error,
701 char *string,
702 size_t size )
703 {
704 libcerror_internal_error_t *internal_error = NULL;
705 system_character_t *error_string = NULL;
706 size_t string_index = 0;
707 int message_index = 0;
708
709 #if defined( HAVE_WIDE_SYSTEM_CHARACTER )
710 size_t print_count = 0;
711 #else
712 size_t error_string_size = 0;
713 #endif
714
715 if( error == NULL )
716 {
717 return( -1 );
718 }
719 internal_error = (libcerror_internal_error_t *) error;
720
721 if( internal_error->messages == NULL )
722 {
723 return( -1 );
724 }
725 if( internal_error->sizes == NULL )
726 {
727 return( -1 );
728 }
729 if( string == NULL )
730 {
731 return( -1 );
732 }
733 #if INT_MAX < SSIZE_MAX
734 if( size > (size_t) INT_MAX )
735 #else
736 if( size > (size_t) SSIZE_MAX )
737 #endif
738 {
739 return( -1 );
740 }
741 for( message_index = 0;
742 message_index < internal_error->number_of_messages;
743 message_index++ )
744 {
745 error_string = internal_error->messages[ message_index ];
746
747 if( error_string != NULL )
748 {
749 if( string_index > 0 )
750 {
751 #if defined( WINAPI )
752 if( ( string_index + 2 ) >= size )
753 {
754 return( -1 );
755 }
756 string[ string_index++ ] = (system_character_t) '\r';
757 #else
758 if( ( string_index + 1 ) >= size )
759 {
760 return( -1 );
761 }
762 #endif /* defined( WINAPI ) */
763
764 string[ string_index++ ] = (system_character_t) '\n';
765 string[ string_index ] = (system_character_t) 0;
766 }
767 #if defined( HAVE_WIDE_SYSTEM_CHARACTER )
768 #if defined( _MSC_VER )
769 if( wcstombs_s(
770 &print_count,
771 &( string[ string_index ] ),
772 size - string_index,
773 error_string,
774 _TRUNCATE ) != 0 )
775 {
776 return( -1 );
777 }
778 #else
779 print_count = wcstombs(
780 &( string[ string_index ] ),
781 error_string,
782 size - string_index );
783
784 if( print_count == (size_t) -1 )
785 {
786 return( -1 );
787 }
788 #endif /*defined( _MSC_VER ) */
789
790 string_index += print_count;
791
792 if( string_index >= size )
793 {
794 return( -1 );
795 }
796 if( string[ string_index - 1 ] == 0 )
797 {
798 string_index--;
799 }
800 #else
801 error_string_size = internal_error->sizes[ message_index ];
802
803 if( size < ( string_index + error_string_size + 1 ) )
804 {
805 return( -1 );
806 }
807 if( narrow_string_copy(
808 &( string[ string_index ] ),
809 error_string,
810 error_string_size ) == NULL )
811 {
812 return( -1 );
813 }
814 string_index += error_string_size - 1;
815
816 #endif /* defined( HAVE_WIDE_SYSTEM_CHARACTER ) */
817 }
818 }
819 string_index++;
820
821 if( string_index > (size_t) INT_MAX )
822 {
823 return( -1 );
824 }
825 return( (int) string_index );
826 }
827
828