1228753Smm/*-
2232153Smm * Copyright (c) 2003-2010 Tim Kientzle
3228753Smm * All rights reserved.
4228753Smm *
5228753Smm * Redistribution and use in source and binary forms, with or without
6228753Smm * modification, are permitted provided that the following conditions
7228753Smm * are met:
8228753Smm * 1. Redistributions of source code must retain the above copyright
9228753Smm *    notice, this list of conditions and the following disclaimer.
10228753Smm * 2. Redistributions in binary form must reproduce the above copyright
11228753Smm *    notice, this list of conditions and the following disclaimer in the
12228753Smm *    documentation and/or other materials provided with the distribution.
13228753Smm *
14228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24228753Smm */
25228753Smm
26228753Smm#include "archive_platform.h"
27228763Smm__FBSDID("$FreeBSD$");
28228753Smm
29228753Smm#ifdef HAVE_SYS_TYPES_H
30228753Smm#include <sys/types.h>
31228753Smm#endif
32228753Smm
33228753Smm#include <stdio.h>
34228753Smm#ifdef HAVE_STDLIB_H
35228753Smm#include <stdlib.h>
36228753Smm#endif
37228753Smm#ifdef HAVE_STRING_H
38228753Smm#include <string.h>
39228753Smm#endif
40228753Smm#ifdef HAVE_UNISTD_H
41228753Smm#include <unistd.h>
42228753Smm#endif
43228753Smm#if defined(_WIN32) && !defined(__CYGWIN__)
44228753Smm#include <windows.h>
45228753Smm#include <winbase.h>
46228753Smm#endif
47228753Smm
48228753Smm#include "archive_private.h"
49228753Smm
50228753Smmstatic void
51228753Smmerrmsg(const char *m)
52228753Smm{
53228753Smm	size_t s = strlen(m);
54228753Smm	ssize_t written;
55228753Smm
56228753Smm	while (s > 0) {
57228753Smm		written = write(2, m, strlen(m));
58228753Smm		if (written <= 0)
59228753Smm			return;
60228753Smm		m += written;
61228753Smm		s -= written;
62228753Smm	}
63228753Smm}
64228753Smm
65228753Smmstatic void
66228753Smmdiediedie(void)
67228753Smm{
68228753Smm#if defined(_WIN32) && !defined(__CYGWIN__) && defined(_DEBUG)
69228753Smm	/* Cause a breakpoint exception  */
70228753Smm	DebugBreak();
71228753Smm#endif
72228753Smm	abort();        /* Terminate the program abnormally. */
73228753Smm}
74228753Smm
75228753Smmstatic const char *
76228753Smmstate_name(unsigned s)
77228753Smm{
78228753Smm	switch (s) {
79228753Smm	case ARCHIVE_STATE_NEW:		return ("new");
80228753Smm	case ARCHIVE_STATE_HEADER:	return ("header");
81228753Smm	case ARCHIVE_STATE_DATA:	return ("data");
82228753Smm	case ARCHIVE_STATE_EOF:		return ("eof");
83228753Smm	case ARCHIVE_STATE_CLOSED:	return ("closed");
84228753Smm	case ARCHIVE_STATE_FATAL:	return ("fatal");
85228753Smm	default:			return ("??");
86228753Smm	}
87228753Smm}
88228753Smm
89232153Smmstatic const char *
90232153Smmarchive_handle_type_name(unsigned m)
91232153Smm{
92232153Smm	switch (m) {
93232153Smm	case ARCHIVE_WRITE_MAGIC:	return ("archive_write");
94232153Smm	case ARCHIVE_READ_MAGIC:	return ("archive_read");
95232153Smm	case ARCHIVE_WRITE_DISK_MAGIC:	return ("archive_write_disk");
96232153Smm	case ARCHIVE_READ_DISK_MAGIC:	return ("archive_read_disk");
97238856Smm	case ARCHIVE_MATCH_MAGIC:	return ("archive_match");
98232153Smm	default:			return NULL;
99232153Smm	}
100232153Smm}
101228753Smm
102232153Smm
103232153Smmstatic char *
104232153Smmwrite_all_states(char *buff, unsigned int states)
105228753Smm{
106228753Smm	unsigned int lowbit;
107228753Smm
108232153Smm	buff[0] = '\0';
109232153Smm
110228753Smm	/* A trick for computing the lowest set bit. */
111228753Smm	while ((lowbit = states & (1 + ~states)) != 0) {
112228753Smm		states &= ~lowbit;		/* Clear the low bit. */
113232153Smm		strcat(buff, state_name(lowbit));
114228753Smm		if (states != 0)
115232153Smm			strcat(buff, "/");
116228753Smm	}
117232153Smm	return buff;
118228753Smm}
119228753Smm
120228753Smm/*
121232153Smm * Check magic value and current state.
122232153Smm *   Magic value mismatches are fatal and result in calls to abort().
123232153Smm *   State mismatches return ARCHIVE_FATAL.
124232153Smm *   Otherwise, returns ARCHIVE_OK.
125228753Smm *
126228753Smm * This is designed to catch serious programming errors that violate
127228753Smm * the libarchive API.
128228753Smm */
129232153Smmint
130228753Smm__archive_check_magic(struct archive *a, unsigned int magic,
131228753Smm    unsigned int state, const char *function)
132228753Smm{
133232153Smm	char states1[64];
134232153Smm	char states2[64];
135232153Smm	const char *handle_type;
136232153Smm
137232153Smm	/*
138232153Smm	 * If this isn't some form of archive handle,
139232153Smm	 * then the library user has screwed up so bad that
140232153Smm	 * we don't even have a reliable way to report an error.
141232153Smm	 */
142232153Smm	handle_type = archive_handle_type_name(a->magic);
143232153Smm
144232153Smm	if (!handle_type) {
145232153Smm		errmsg("PROGRAMMER ERROR: Function ");
146228753Smm		errmsg(function);
147232153Smm		errmsg(" invoked with invalid archive handle.\n");
148228753Smm		diediedie();
149228753Smm	}
150228753Smm
151232153Smm	if (a->magic != magic) {
152232153Smm		archive_set_error(a, -1,
153232153Smm		    "PROGRAMMER ERROR: Function '%s' invoked"
154232153Smm		    " on '%s' archive object, which is not supported.",
155232153Smm		    function,
156232153Smm		    handle_type);
157232153Smm		a->state = ARCHIVE_STATE_FATAL;
158232153Smm		return (ARCHIVE_FATAL);
159232153Smm	}
160228753Smm
161228753Smm	if ((a->state & state) == 0) {
162232153Smm		/* If we're already FATAL, don't overwrite the error. */
163232153Smm		if (a->state != ARCHIVE_STATE_FATAL)
164232153Smm			archive_set_error(a, -1,
165232153Smm			    "INTERNAL ERROR: Function '%s' invoked with"
166232153Smm			    " archive structure in state '%s',"
167232153Smm			    " should be in state '%s'",
168232153Smm			    function,
169232153Smm			    write_all_states(states1, a->state),
170232153Smm			    write_all_states(states2, state));
171232153Smm		a->state = ARCHIVE_STATE_FATAL;
172232153Smm		return (ARCHIVE_FATAL);
173228753Smm	}
174232153Smm	return ARCHIVE_OK;
175228753Smm}
176