file/src/funcs.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) Christos Zoulas 2003.
00003  * All Rights Reserved.
00004  * 
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice immediately at the beginning of the file, without modification,
00010  *    this list of conditions, and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  *  
00015  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
00016  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00017  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00018  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
00019  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00020  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00021  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00022  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00023  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00024  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00025  * SUCH DAMAGE.
00026  */
00027 #include "file.h"
00028 #include "magic.h"
00029 #include <assert.h>
00030 #include <stdarg.h>
00031 #include <stdlib.h>
00032 #include <string.h>
00033 #include <ctype.h>
00034 #if defined(HAVE_WCHAR_H)
00035 #include <wchar.h>
00036 #endif
00037 #if defined(HAVE_WCTYPE_H)
00038 #include <wctype.h>
00039 #endif
00040 
00041 #ifndef lint
00042 FILE_RCSID("@(#)$File: funcs.c,v 1.28 2007/03/01 22:14:54 christos Exp $")
00043 #endif  /* lint */
00044 
00045 #ifndef HAVE_VSNPRINTF
00046 int vsnprintf(char *, size_t, const char *, va_list)
00047         /*@*/;
00048 #endif
00049 
00050 /*
00051  * Like printf, only we print to a buffer and advance it.
00052  */
00053 protected int
00054 file_printf(struct magic_set *ms, const char *fmt, ...)
00055 {
00056         va_list ap;
00057         size_t len, size;
00058         char *buf;
00059 
00060         va_start(ap, fmt);
00061 
00062         if ((len = vsnprintf(ms->o.ptr, ms->o.left, fmt, ap)) >= ms->o.left) {
00063                 long diff;      /* XXX: really ptrdiff_t */
00064 
00065                 va_end(ap);
00066                 size = (ms->o.size - ms->o.left) + len + 1024;
00067                 if ((buf = realloc(ms->o.buf, size)) == NULL) {
00068                         file_oomem(ms, size);
00069                         return -1;
00070                 }
00071                 diff = ms->o.ptr - ms->o.buf;
00072                 ms->o.ptr = buf + diff;
00073                 ms->o.buf = buf;
00074                 ms->o.left = size - diff;
00075                 ms->o.size = size;
00076 
00077                 va_start(ap, fmt);
00078                 len = vsnprintf(ms->o.ptr, ms->o.left, fmt, ap);
00079         }
00080         va_end(ap);
00081         ms->o.ptr += len;
00082         ms->o.left -= len;
00083         return 0;
00084 }
00085 
00086 /*
00087  * error - print best error message possible
00088  */
00089 /*VARARGS*/
00090 private void
00091 file_error_core(struct magic_set *ms, int error, const char *f, va_list va,
00092     uint32_t lineno)
00093         /*@modifies ms @*/
00094 {
00095         size_t len;
00096         /* Only the first error is ok */
00097         if (ms->haderr)
00098                 return;
00099         len = 0;
00100         if (lineno != 0) {
00101                 (void)snprintf(ms->o.buf, ms->o.size, "line %u: ", lineno);
00102                 len = strlen(ms->o.buf);
00103         }
00104         (void)vsnprintf(ms->o.buf + len, ms->o.size - len, f, va);
00105         if (error > 0) {
00106                 len = strlen(ms->o.buf);
00107                 (void)snprintf(ms->o.buf + len, ms->o.size - len, " (%s)",
00108                     strerror(error));
00109         }
00110         ms->haderr++;
00111         ms->error = error;
00112 }
00113 
00114 /*VARARGS*/
00115 protected void
00116 file_error(struct magic_set *ms, int error, const char *f, ...)
00117 {
00118         va_list va;
00119         va_start(va, f);
00120         file_error_core(ms, error, f, va, 0);
00121         va_end(va);
00122 }
00123 
00124 /*
00125  * Print an error with magic line number.
00126  */
00127 /*VARARGS*/
00128 protected void
00129 file_magerror(struct magic_set *ms, const char *f, ...)
00130 {
00131         va_list va;
00132         va_start(va, f);
00133         file_error_core(ms, 0, f, va, ms->line);
00134         va_end(va);
00135 }
00136 
00137 protected void
00138 file_oomem(struct magic_set *ms, size_t len)
00139 {
00140         file_error(ms, errno, "cannot allocate %zu bytes", len);
00141 }
00142 
00143 protected void
00144 file_badseek(struct magic_set *ms)
00145 {
00146         file_error(ms, errno, "error seeking");
00147 }
00148 
00149 protected void
00150 file_badread(struct magic_set *ms)
00151 {
00152         file_error(ms, errno, "error reading");
00153 }
00154 
00155 #ifndef COMPILE_ONLY
00156 protected int
00157 file_buffer(struct magic_set *ms, int fd, const char *inname, const void *buf,
00158     size_t nb)
00159 {
00160     int m;
00161 
00162 #ifdef __EMX__
00163     if ((ms->flags & MAGIC_NO_CHECK_APPTYPE) == 0 && inname) {
00164         switch (file_os2_apptype(ms, inname, buf, nb)) {
00165         case -1:
00166             return -1;
00167         case 0:
00168             break;
00169         default:
00170             return 1;
00171         }
00172     }
00173 #endif
00174 
00175     /* try compression stuff */
00176     if ((ms->flags & MAGIC_NO_CHECK_COMPRESS) != 0 ||
00177         (m = file_zmagic(ms, fd, inname, buf, nb)) == 0) {
00178         /* Check if we have a tar file */
00179         if ((ms->flags & MAGIC_NO_CHECK_TAR) != 0 ||
00180             (m = file_is_tar(ms, buf, nb)) == 0) {
00181             /* try tests in /etc/magic (or surrogate magic file) */
00182             if ((ms->flags & MAGIC_NO_CHECK_SOFT) != 0 ||
00183                 (m = file_softmagic(ms, buf, nb)) == 0) {
00184                 /* try known keywords, check whether it is ASCII */
00185                 if ((ms->flags & MAGIC_NO_CHECK_ASCII) != 0 ||
00186                     (m = file_ascmagic(ms, buf, nb)) == 0) {
00187                     /* abandon hope, all ye who remain here */
00188                     if (file_printf(ms, ms->flags & MAGIC_MIME ?
00189                         (nb ? "application/octet-stream" :
00190                             "application/empty") :
00191                         (nb ? "data" :
00192                             "empty")) == -1)
00193                             return -1;
00194                     m = 1;
00195                 }
00196             }
00197         }
00198     }
00199 #ifdef BUILTIN_ELF
00200     if ((ms->flags & MAGIC_NO_CHECK_ELF) == 0 && m == 1 && nb > 5 && fd != -1) {
00201         /*
00202          * We matched something in the file, so this *might*
00203          * be an ELF file, and the file is at least 5 bytes
00204          * long, so if it's an ELF file it has at least one
00205          * byte past the ELF magic number - try extracting
00206          * information from the ELF headers that cannot easily
00207          * be extracted with rules in the magic file.
00208          */
00209         (void)file_tryelf(ms, fd, buf, nb);
00210     }
00211 #endif
00212     return m;
00213 }
00214 #endif
00215 
00216 protected int
00217 file_reset(struct magic_set *ms)
00218 {
00219         if (ms->mlist == NULL) {
00220                 file_error(ms, 0, "no magic files loaded");
00221                 return -1;
00222         }
00223         ms->o.ptr = ms->o.buf;
00224         ms->haderr = 0;
00225         ms->error = -1;
00226         return 0;
00227 }
00228 
00229 #define OCTALIFY(n, o)  \
00230         /*LINTED*/ \
00231         (void)(*(n)++ = '\\', \
00232         *(n)++ = (((uint32_t)*(o) >> 6) & 3) + '0', \
00233         *(n)++ = (((uint32_t)*(o) >> 3) & 7) + '0', \
00234         *(n)++ = (((uint32_t)*(o) >> 0) & 7) + '0', \
00235         (o)++)
00236 
00237 protected const char *
00238 file_getbuffer(struct magic_set *ms)
00239 {
00240         char *pbuf, *op, *np;
00241         size_t psize, len;
00242 
00243         if (ms->haderr)
00244                 return NULL;
00245 
00246         if (ms->flags & MAGIC_RAW)
00247                 return ms->o.buf;
00248 
00249         len = ms->o.size - ms->o.left;
00250         /* * 4 is for octal representation, + 1 is for NUL */
00251         psize = len * 4 + 1;
00252         assert(psize > len);
00253         if (ms->o.psize < psize) {
00254                 if ((pbuf = realloc(ms->o.pbuf, psize)) == NULL) {
00255                         file_oomem(ms, psize);
00256                         return NULL;
00257                 }
00258                 ms->o.psize = psize;
00259                 ms->o.pbuf = pbuf;
00260         }
00261 
00262 #if defined(HAVE_WCHAR_H) && defined(HAVE_MBRTOWC) && defined(HAVE_WCWIDTH)
00263         {
00264                 mbstate_t state;
00265                 wchar_t nextchar;
00266                 int mb_conv = 1;
00267                 size_t bytesconsumed;
00268                 char *eop;
00269                 (void)memset(&state, 0, sizeof(mbstate_t));
00270 
00271                 np = ms->o.pbuf;
00272                 op = ms->o.buf;
00273                 eop = op + strlen(ms->o.buf);
00274 
00275                 while (op < eop) {
00276                         bytesconsumed = mbrtowc(&nextchar, op,
00277                             (size_t)(eop - op), &state);
00278                         if (bytesconsumed == (size_t)(-1) ||
00279                             bytesconsumed == (size_t)(-2)) {
00280                                 mb_conv = 0;
00281                                 break;
00282                         }
00283 
00284                         if (iswprint(nextchar)) {
00285                                 (void)memcpy(np, op, bytesconsumed);
00286                                 op += bytesconsumed;
00287                                 np += bytesconsumed;
00288                         } else {
00289                                 while (bytesconsumed-- > 0)
00290                                         OCTALIFY(np, op);
00291         }
00292                 }
00293                 *np = '\0';
00294 
00295                 /* Parsing succeeded as a multi-byte sequence */
00296                 if (mb_conv != 0)
00297                         return ms->o.pbuf;
00298         }
00299 #endif
00300 
00301         for (np = ms->o.pbuf, op = ms->o.buf; *op; op++) {
00302                 if (isprint((unsigned char)*op)) {
00303                         *np++ = *op;    
00304                 } else {
00305                         OCTALIFY(np, op);
00306                 }
00307         }
00308         *np = '\0';
00309         return ms->o.pbuf;
00310 }
00311 
00312 /*
00313  * Yes these wrappers suffer from buffer overflows, but if your OS does not
00314  * have the real functions, maybe you should consider replacing your OS?
00315  */
00316 #ifndef HAVE_VSNPRINTF
00317 int
00318 vsnprintf(char *buf, size_t len, const char *fmt, va_list ap)
00319 {
00320         return vsprintf(buf, fmt, ap);
00321 }
00322 #endif
00323 
00324 #ifndef HAVE_SNPRINTF
00325 /*ARGSUSED*/
00326 int
00327 snprintf(char *buf, size_t len, const char *fmt, ...)
00328 {
00329         int rv;
00330         va_list ap;
00331         va_start(ap, fmt);
00332         rv = vsprintf(buf, fmt, ap);
00333         va_end(ap);
00334         return rv;
00335 }
00336 #endif

Generated on Fri May 25 21:18:11 2007 for rpm by  doxygen 1.5.2