aboutsummaryrefslogblamecommitdiffstats
path: root/copy_error.c
blob: ebf71b4c7c5d656865e11c4134a656f56a704bfc (plain) (tree)
1
2
3
4
5
6



                                                         

                                          













                                                       
 








                                                                       


























                                                                                                        


                            




                                  
 
/* See LICENSE file for copyright and license details. */
#include "internal.h"


#define STRDUP(S) ((S) ? strdup(S) : NULL)

struct liberror_error *
liberror_copy_error(struct liberror_error *src)
{
	struct liberror_error *dest;
	int saved_errno;
	if (!src)
		return NULL;
	saved_errno = errno;
	dest = malloc(sizeof(*dest));
	if (dest) {
		memcpy(dest, src, sizeof(*src));
		if (dest->backtrace)
			dest->backtrace->refcount += 1;
		dest->dynamically_allocated = 1;

		if (src->cause) {
			dest->cause = liberror_copy_error(src->cause);
			if (!dest->cause) {
				if (dest->backtrace)
					dest->backtrace->refcount -= 1;
				free(dest);
				dest = NULL;
			}
		}

		switch (dest->details_type) {
		case LIBERROR_DETAILS_USER:
			dest->details.user.data = dest->details.user.copy_data(dest->details.user.data);
			if (!dest->details.user.data)
				goto fail;
			break;

		case LIBERROR_DETAILS_ONE_FILE:
			dest->details.one_file.name = STRDUP(src->details.one_file.name);
			if (src->details.one_file.name && !dest->details.one_file.name)
				goto fail;
			break;

		case LIBERROR_DETAILS_TWO_FILES:
			dest->details.two_files.name1 = STRDUP(src->details.two_files.name1);
			dest->details.two_files.name2 = STRDUP(src->details.two_files.name2);
			if (src->details.two_files.name1 && !dest->details.two_files.name1)
				goto fail;
			if (src->details.two_files.name2 && !dest->details.two_files.name2)
				goto fail;
			break;

		case LIBERROR_DETAILS_NONE:
		default:
			break;
		}
	}
	errno = saved_errno;
	return dest;

fail:
	liberror_free_error(dest);
	errno = saved_errno;
	return NULL;
}