91229557a35dcf12abe654dd6c50e232e3a80853
[dragonfly.git] / contrib / libarchive / libarchive / archive_check_magic.c
1 /*-
2  * Copyright (c) 2003-2010 Tim Kientzle
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "archive_platform.h"
27 __FBSDID("$FreeBSD: head/lib/libarchive/archive_check_magic.c 201089 2009-12-28 02:20:23Z kientzle $");
28
29 #ifdef HAVE_SYS_TYPES_H
30 #include <sys/types.h>
31 #endif
32
33 #include <stdio.h>
34 #ifdef HAVE_STDLIB_H
35 #include <stdlib.h>
36 #endif
37 #ifdef HAVE_STRING_H
38 #include <string.h>
39 #endif
40 #ifdef HAVE_UNISTD_H
41 #include <unistd.h>
42 #endif
43 #if defined(_WIN32) && !defined(__CYGWIN__)
44 #include <windows.h>
45 #include <winbase.h>
46 #endif
47
48 #include "archive_private.h"
49
50 static void
51 errmsg(const char *m)
52 {
53         size_t s = strlen(m);
54         ssize_t written;
55
56         while (s > 0) {
57                 written = write(2, m, strlen(m));
58                 if (written <= 0)
59                         return;
60                 m += written;
61                 s -= written;
62         }
63 }
64
65 static void
66 diediedie(void)
67 {
68 #if defined(_WIN32) && !defined(__CYGWIN__) && defined(_DEBUG)
69         /* Cause a breakpoint exception  */
70         DebugBreak();
71 #endif
72         abort();        /* Terminate the program abnormally. */
73 }
74
75 static const char *
76 state_name(unsigned s)
77 {
78         switch (s) {
79         case ARCHIVE_STATE_NEW:         return ("new");
80         case ARCHIVE_STATE_HEADER:      return ("header");
81         case ARCHIVE_STATE_DATA:        return ("data");
82         case ARCHIVE_STATE_EOF:         return ("eof");
83         case ARCHIVE_STATE_CLOSED:      return ("closed");
84         case ARCHIVE_STATE_FATAL:       return ("fatal");
85         default:                        return ("??");
86         }
87 }
88
89 static const char *
90 archive_handle_type_name(unsigned m)
91 {
92         switch (m) {
93         case ARCHIVE_WRITE_MAGIC:       return ("archive_write");
94         case ARCHIVE_READ_MAGIC:        return ("archive_read");
95         case ARCHIVE_WRITE_DISK_MAGIC:  return ("archive_write_disk");
96         case ARCHIVE_READ_DISK_MAGIC:   return ("archive_read_disk");
97         default:                        return NULL;
98         }
99 }
100
101
102 static char *
103 write_all_states(char *buff, unsigned int states)
104 {
105         unsigned int lowbit;
106
107         buff[0] = '\0';
108
109         /* A trick for computing the lowest set bit. */
110         while ((lowbit = states & (1 + ~states)) != 0) {
111                 states &= ~lowbit;              /* Clear the low bit. */
112                 strcat(buff, state_name(lowbit));
113                 if (states != 0)
114                         strcat(buff, "/");
115         }
116         return buff;
117 }
118
119 /*
120  * Check magic value and current state.
121  *   Magic value mismatches are fatal and result in calls to abort().
122  *   State mismatches return ARCHIVE_FATAL.
123  *   Otherwise, returns ARCHIVE_OK.
124  *
125  * This is designed to catch serious programming errors that violate
126  * the libarchive API.
127  */
128 int
129 __archive_check_magic(struct archive *a, unsigned int magic,
130     unsigned int state, const char *function)
131 {
132         char states1[64];
133         char states2[64];
134         const char *handle_type;
135
136         /*
137          * If this isn't some form of archive handle,
138          * then the library user has screwed up so bad that
139          * we don't even have a reliable way to report an error.
140          */
141         handle_type = archive_handle_type_name(a->magic);
142
143         if (!handle_type) {
144                 errmsg("PROGRAMMER ERROR: Function ");
145                 errmsg(function);
146                 errmsg(" invoked with invalid archive handle.\n");
147                 diediedie();
148         }
149
150         if (a->magic != magic) {
151                 archive_set_error(a, -1,
152                     "PROGRAMMER ERROR: Function '%s' invoked"
153                     " on '%s' archive object, which is not supported.",
154                     function,
155                     handle_type);
156                 a->state = ARCHIVE_STATE_FATAL;
157                 return (ARCHIVE_FATAL);
158         }
159
160         if ((a->state & state) == 0) {
161                 /* If we're already FATAL, don't overwrite the error. */
162                 if (a->state != ARCHIVE_STATE_FATAL)
163                         archive_set_error(a, -1,
164                             "INTERNAL ERROR: Function '%s' invoked with"
165                             " archive structure in state '%s',"
166                             " should be in state '%s'",
167                             function,
168                             write_all_states(states1, a->state),
169                             write_all_states(states2, state));
170                 a->state = ARCHIVE_STATE_FATAL;
171                 return (ARCHIVE_FATAL);
172         }
173         return ARCHIVE_OK;
174 }