1 /* $NetBSD: funcs.c,v 1.1.1.1 2009/05/08 16:35:06 christos Exp $ */
4 * Copyright (c) Christos Zoulas 2003.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice immediately at the beginning of the file, without modification,
12 * this list of conditions, and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
21 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 FILE_RCSID("@(#)$File: funcs.c,v 1.53 2009/04/07 11:07:00 christos Exp $")
35 __RCSID("$NetBSD: funcs.c,v 1.1.1.1 2009/05/08 16:35:06 christos Exp $");
44 #if defined(HAVE_WCHAR_H)
47 #if defined(HAVE_WCTYPE_H)
50 #if defined(HAVE_LIMITS_H)
55 #define SIZE_MAX ((size_t)~0)
59 * Like printf, only we append to a buffer.
62 file_vprintf(struct magic_set
*ms
, const char *fmt
, va_list ap
)
67 len
= vasprintf(&buf
, fmt
, ap
);
71 if (ms
->o
.buf
!= NULL
) {
72 len
= asprintf(&newstr
, "%s%s", ms
->o
.buf
, buf
);
82 file_error(ms
, errno
, "vasprintf failed");
87 file_printf(struct magic_set
*ms
, const char *fmt
, ...)
93 rv
= file_vprintf(ms
, fmt
, ap
);
99 * error - print best error message possible
103 file_error_core(struct magic_set
*ms
, int error
, const char *f
, va_list va
,
106 /* Only the first error is ok */
107 if (ms
->event_flags
& EVENT_HAD_ERR
)
112 file_printf(ms
, "line %zu: ", lineno
);
114 file_vprintf(ms
, f
, va
);
116 file_printf(ms
, " (%s)", strerror(error
));
117 ms
->event_flags
|= EVENT_HAD_ERR
;
123 file_error(struct magic_set
*ms
, int error
, const char *f
, ...)
127 file_error_core(ms
, error
, f
, va
, 0);
132 * Print an error with magic line number.
136 file_magerror(struct magic_set
*ms
, const char *f
, ...)
140 file_error_core(ms
, 0, f
, va
, ms
->line
);
145 file_oomem(struct magic_set
*ms
, size_t len
)
147 file_error(ms
, errno
, "cannot allocate %zu bytes", len
);
151 file_badseek(struct magic_set
*ms
)
153 file_error(ms
, errno
, "error seeking");
157 file_badread(struct magic_set
*ms
)
159 file_error(ms
, errno
, "error reading");
164 file_buffer(struct magic_set
*ms
, int fd
, const char *inname
, const void *buf
,
167 int m
= 0, rv
= 0, looks_text
= 0;
168 int mime
= ms
->flags
& MAGIC_MIME
;
169 const unsigned char *ubuf
= CAST(const unsigned char *, buf
);
170 unichar
*u8buf
= NULL
;
172 const char *code
= NULL
;
173 const char *code_mime
= "binary";
174 const char *type
= NULL
;
179 if ((!mime
|| (mime
& MAGIC_MIME_TYPE
)) &&
180 file_printf(ms
, mime
? "application/x-empty" :
184 } else if (nb
== 1) {
185 if ((!mime
|| (mime
& MAGIC_MIME_TYPE
)) &&
186 file_printf(ms
, mime
? "application/octet-stream" :
187 "very short file (no magic)") == -1)
192 if ((ms
->flags
& MAGIC_NO_CHECK_ENCODING
) == 0) {
193 looks_text
= file_encoding(ms
, ubuf
, nb
, &u8buf
, &ulen
,
194 &code
, &code_mime
, &type
);
198 if ((ms
->flags
& MAGIC_NO_CHECK_APPTYPE
) == 0 && inname
) {
199 switch (file_os2_apptype(ms
, inname
, buf
, nb
)) {
210 /* try compression stuff */
211 if ((ms
->flags
& MAGIC_NO_CHECK_COMPRESS
) == 0)
212 if ((m
= file_zmagic(ms
, fd
, inname
, ubuf
, nb
)) != 0) {
213 if ((ms
->flags
& MAGIC_DEBUG
) != 0)
214 (void)fprintf(stderr
, "zmagic %d\n", m
);
218 /* Check if we have a tar file */
219 if ((ms
->flags
& MAGIC_NO_CHECK_TAR
) == 0)
220 if ((m
= file_is_tar(ms
, ubuf
, nb
)) != 0) {
221 if ((ms
->flags
& MAGIC_DEBUG
) != 0)
222 (void)fprintf(stderr
, "tar %d\n", m
);
226 /* Check if we have a CDF file */
227 if ((ms
->flags
& MAGIC_NO_CHECK_CDF
) == 0)
228 if ((m
= file_trycdf(ms
, fd
, ubuf
, nb
)) != 0) {
229 if ((ms
->flags
& MAGIC_DEBUG
) != 0)
230 (void)fprintf(stderr
, "cdf %d\n", m
);
234 /* try soft magic tests */
235 if ((ms
->flags
& MAGIC_NO_CHECK_SOFT
) == 0)
236 if ((m
= file_softmagic(ms
, ubuf
, nb
, BINTEST
)) != 0) {
237 if ((ms
->flags
& MAGIC_DEBUG
) != 0)
238 (void)fprintf(stderr
, "softmagic %d\n", m
);
240 if ((ms
->flags
& MAGIC_NO_CHECK_ELF
) == 0 && m
== 1 &&
241 nb
> 5 && fd
!= -1) {
243 * We matched something in the file, so this
244 * *might* be an ELF file, and the file is at
245 * least 5 bytes long, so if it's an ELF file
246 * it has at least one byte past the ELF magic
247 * number - try extracting information from the
248 * ELF headers that cannot easily * be
249 * extracted with rules in the magic file.
251 if ((m
= file_tryelf(ms
, fd
, ubuf
, nb
)) != 0)
252 if ((ms
->flags
& MAGIC_DEBUG
) != 0)
253 (void)fprintf(stderr
,
260 /* try text properties (and possibly text tokens) */
261 if ((ms
->flags
& MAGIC_NO_CHECK_TEXT
) == 0) {
263 if ((m
= file_ascmagic(ms
, ubuf
, nb
)) != 0) {
264 if ((ms
->flags
& MAGIC_DEBUG
) != 0)
265 (void)fprintf(stderr
, "ascmagic %d\n", m
);
269 /* try to discover text encoding */
270 if ((ms
->flags
& MAGIC_NO_CHECK_ENCODING
) == 0) {
272 if ((m
= file_ascmagic_with_encoding( ms
, ubuf
,
273 nb
, u8buf
, ulen
, code
, type
)) != 0) {
274 if ((ms
->flags
& MAGIC_DEBUG
) != 0)
275 (void)fprintf(stderr
,
276 "ascmagic/enc %d\n", m
);
284 if ((!mime
|| (mime
& MAGIC_MIME_TYPE
)) &&
285 file_printf(ms
, mime
? "application/octet-stream" : "data") == -1) {
289 if ((ms
->flags
& MAGIC_MIME_ENCODING
) != 0) {
290 if (ms
->flags
& MAGIC_MIME_TYPE
)
291 if (file_printf(ms
, "; charset=") == -1)
293 if (file_printf(ms
, "%s", code_mime
) == -1)
306 file_reset(struct magic_set
*ms
)
308 if (ms
->mlist
== NULL
) {
309 file_error(ms
, 0, "no magic files loaded");
320 ms
->event_flags
&= ~EVENT_HAD_ERR
;
325 #define OCTALIFY(n, o) \
327 (void)(*(n)++ = '\\', \
328 *(n)++ = (((uint32_t)*(o) >> 6) & 3) + '0', \
329 *(n)++ = (((uint32_t)*(o) >> 3) & 7) + '0', \
330 *(n)++ = (((uint32_t)*(o) >> 0) & 7) + '0', \
333 protected const char *
334 file_getbuffer(struct magic_set
*ms
)
336 char *pbuf
, *op
, *np
;
339 if (ms
->event_flags
& EVENT_HAD_ERR
)
342 if (ms
->flags
& MAGIC_RAW
)
345 if (ms
->o
.buf
== NULL
)
348 /* * 4 is for octal representation, + 1 is for NUL */
349 len
= strlen(ms
->o
.buf
);
350 if (len
> (SIZE_MAX
- 1) / 4) {
355 if ((pbuf
= CAST(char *, realloc(ms
->o
.pbuf
, psize
))) == NULL
) {
356 file_oomem(ms
, psize
);
361 #if defined(HAVE_WCHAR_H) && defined(HAVE_MBRTOWC) && defined(HAVE_WCWIDTH)
366 size_t bytesconsumed
;
368 (void)memset(&state
, 0, sizeof(mbstate_t));
375 bytesconsumed
= mbrtowc(&nextchar
, op
,
376 (size_t)(eop
- op
), &state
);
377 if (bytesconsumed
== (size_t)(-1) ||
378 bytesconsumed
== (size_t)(-2)) {
383 if (iswprint(nextchar
)) {
384 (void)memcpy(np
, op
, bytesconsumed
);
388 while (bytesconsumed
-- > 0)
394 /* Parsing succeeded as a multi-byte sequence */
400 for (np
= ms
->o
.pbuf
, op
= ms
->o
.buf
; *op
; op
++) {
401 if (isprint((unsigned char)*op
)) {
412 file_check_mem(struct magic_set
*ms
, unsigned int level
)
416 if (level
>= ms
->c
.len
) {
417 len
= (ms
->c
.len
+= 20) * sizeof(*ms
->c
.li
);
418 ms
->c
.li
= CAST(struct level_info
*, (ms
->c
.li
== NULL
) ?
420 realloc(ms
->c
.li
, len
));
421 if (ms
->c
.li
== NULL
) {
426 ms
->c
.li
[level
].got_match
= 0;
427 #ifdef ENABLE_CONDITIONALS
428 ms
->c
.li
[level
].last_match
= 0;
429 ms
->c
.li
[level
].last_cond
= COND_NONE
;
430 #endif /* ENABLE_CONDITIONALS */