/src/libarchive/libarchive/archive_check_magic.c
Line | Count | Source (jump to first uncovered line) |
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 | | |
28 | | #ifdef HAVE_SYS_TYPES_H |
29 | | #include <sys/types.h> |
30 | | #endif |
31 | | |
32 | | #include <stdio.h> |
33 | | #include <errno.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 | 0 | { |
53 | 0 | size_t s = strlen(m); |
54 | 0 | ssize_t written; |
55 | |
|
56 | 0 | while (s > 0) { |
57 | 0 | written = write(2, m, s); |
58 | 0 | if (written == 0) |
59 | 0 | return; |
60 | 0 | if (written < 0) |
61 | 0 | { |
62 | 0 | if (errno == EINTR) |
63 | 0 | continue; |
64 | 0 | return; |
65 | 0 | } |
66 | 0 | m += written; |
67 | 0 | s -= written; |
68 | 0 | } |
69 | 0 | } |
70 | | |
71 | | static __LA_NORETURN void |
72 | | diediedie(void) |
73 | 0 | { |
74 | | #if defined(_WIN32) && !defined(__CYGWIN__) && defined(_DEBUG) |
75 | | /* Cause a breakpoint exception */ |
76 | | DebugBreak(); |
77 | | #endif |
78 | 0 | abort(); /* Terminate the program abnormally. */ |
79 | 0 | } |
80 | | |
81 | | static const char * |
82 | | state_name(unsigned s) |
83 | 3.81k | { |
84 | 3.81k | switch (s) { |
85 | 0 | case ARCHIVE_STATE_NEW: return ("new"); |
86 | 9 | case ARCHIVE_STATE_HEADER: return ("header"); |
87 | 1.90k | case ARCHIVE_STATE_DATA: return ("data"); |
88 | 1.90k | case ARCHIVE_STATE_EOF: return ("eof"); |
89 | 0 | case ARCHIVE_STATE_CLOSED: return ("closed"); |
90 | 0 | case ARCHIVE_STATE_FATAL: return ("fatal"); |
91 | 0 | default: return ("??"); |
92 | 3.81k | } |
93 | 3.81k | } |
94 | | |
95 | | static const char * |
96 | | archive_handle_type_name(unsigned m) |
97 | 1.97M | { |
98 | 1.97M | switch (m) { |
99 | 0 | case ARCHIVE_WRITE_MAGIC: return ("archive_write"); |
100 | 1.97M | case ARCHIVE_READ_MAGIC: return ("archive_read"); |
101 | 0 | case ARCHIVE_WRITE_DISK_MAGIC: return ("archive_write_disk"); |
102 | 0 | case ARCHIVE_READ_DISK_MAGIC: return ("archive_read_disk"); |
103 | 0 | case ARCHIVE_MATCH_MAGIC: return ("archive_match"); |
104 | 0 | default: return NULL; |
105 | 1.97M | } |
106 | 1.97M | } |
107 | | |
108 | | static void |
109 | | write_all_states(char *buff, unsigned int states) |
110 | 3.81k | { |
111 | 3.81k | unsigned int lowbit; |
112 | | |
113 | 3.81k | *buff = '\0'; |
114 | | |
115 | | /* A trick for computing the lowest set bit. */ |
116 | 7.63k | while ((lowbit = states & (1 + ~states)) != 0) { |
117 | 3.81k | states &= ~lowbit; /* Clear the low bit. */ |
118 | 3.81k | strcat(buff, state_name(lowbit)); |
119 | 3.81k | if (states != 0) |
120 | 0 | strcat(buff, "/"); |
121 | 3.81k | } |
122 | 3.81k | } |
123 | | |
124 | | /* |
125 | | * Check magic value and current state. |
126 | | * Magic value mismatches are fatal and result in calls to abort(). |
127 | | * State mismatches return ARCHIVE_FATAL. |
128 | | * Otherwise, returns ARCHIVE_OK. |
129 | | * |
130 | | * This is designed to catch serious programming errors that violate |
131 | | * the libarchive API. |
132 | | */ |
133 | | int |
134 | | __archive_check_magic(struct archive *a, unsigned int magic, |
135 | | unsigned int state, const char *function) |
136 | 1.97M | { |
137 | 1.97M | char states1[64]; |
138 | 1.97M | char states2[64]; |
139 | 1.97M | const char *handle_type; |
140 | | |
141 | | /* |
142 | | * If this isn't some form of archive handle, |
143 | | * then the library user has screwed up so bad that |
144 | | * we don't even have a reliable way to report an error. |
145 | | */ |
146 | 1.97M | handle_type = archive_handle_type_name(a->magic); |
147 | | |
148 | 1.97M | if (!handle_type) { |
149 | 0 | errmsg("PROGRAMMER ERROR: Function "); |
150 | 0 | errmsg(function); |
151 | 0 | errmsg(" invoked with invalid archive handle.\n"); |
152 | 0 | diediedie(); |
153 | 0 | } |
154 | | |
155 | 1.97M | if (a->magic != magic) { |
156 | 0 | archive_set_error(a, -1, |
157 | 0 | "PROGRAMMER ERROR: Function '%s' invoked" |
158 | 0 | " on '%s' archive object, which is not supported.", |
159 | 0 | function, |
160 | 0 | handle_type); |
161 | 0 | a->state = ARCHIVE_STATE_FATAL; |
162 | 0 | return (ARCHIVE_FATAL); |
163 | 0 | } |
164 | | |
165 | 1.97M | if ((a->state & state) == 0) { |
166 | | /* If we're already FATAL, don't overwrite the error. */ |
167 | 8.67k | if (a->state != ARCHIVE_STATE_FATAL) { |
168 | 1.90k | write_all_states(states1, a->state); |
169 | 1.90k | write_all_states(states2, state); |
170 | 1.90k | archive_set_error(a, -1, |
171 | 1.90k | "INTERNAL ERROR: Function '%s' invoked with" |
172 | 1.90k | " archive structure in state '%s'," |
173 | 1.90k | " should be in state '%s'", |
174 | 1.90k | function, |
175 | 1.90k | states1, |
176 | 1.90k | states2); |
177 | 1.90k | } |
178 | 8.67k | a->state = ARCHIVE_STATE_FATAL; |
179 | 8.67k | return (ARCHIVE_FATAL); |
180 | 8.67k | } |
181 | 1.96M | return (ARCHIVE_OK); |
182 | 1.97M | } |