root/ext/fileinfo/libmagic/funcs.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. file_printf
  2. file_error_core
  3. file_error
  4. file_magerror
  5. file_oomem
  6. file_badseek
  7. file_badread
  8. file_buffer
  9. file_reset
  10. file_getbuffer
  11. file_check_mem
  12. file_printedlen
  13. file_replace

   1 /*
   2  * Copyright (c) Christos Zoulas 2003.
   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 immediately at the beginning of the file, without modification,
  10  *    this list of conditions, and the following disclaimer.
  11  * 2. Redistributions in binary form must reproduce the above copyright
  12  *    notice, this list of conditions and the following disclaimer in the
  13  *    documentation and/or other materials provided with the distribution.
  14  *
  15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
  19  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  25  * SUCH DAMAGE.
  26  */
  27 #include "file.h"
  28 
  29 #ifndef lint
  30 FILE_RCSID("@(#)$File: funcs.c,v 1.68 2014/02/18 11:09:31 kim Exp $")
  31 #endif  /* lint */
  32 
  33 #include "magic.h"
  34 #include <stdarg.h>
  35 #include <stdlib.h>
  36 #include <string.h>
  37 #include <ctype.h>
  38 #if defined(HAVE_WCHAR_H)
  39 #include <wchar.h>
  40 #endif
  41 #if defined(HAVE_WCTYPE_H)
  42 #include <wctype.h>
  43 #endif
  44 #if defined(HAVE_LOCALE_H)
  45 #include <locale.h>
  46 #endif
  47 
  48 #ifndef SIZE_MAX
  49 # define SIZE_MAX ((size_t) -1) 
  50 #endif
  51 
  52 #include "php.h"
  53 #include "main/php_network.h"
  54 
  55 #ifndef PREG_OFFSET_CAPTURE
  56 # define PREG_OFFSET_CAPTURE                 (1<<8)
  57 #endif
  58 
  59 extern public void convert_libmagic_pattern(zval *pattern, int options);
  60 
  61 protected int
  62 file_printf(struct magic_set *ms, const char *fmt, ...)
  63 {
  64         va_list ap;
  65         int len;
  66         char *buf = NULL, *newstr;
  67 
  68         va_start(ap, fmt);
  69         len = vspprintf(&buf, 0, fmt, ap);
  70         va_end(ap);
  71 
  72         if (ms->o.buf != NULL) {
  73                 len = spprintf(&newstr, 0, "%s%s", ms->o.buf, (buf ? buf : ""));
  74                 if (buf) {
  75                         efree(buf);
  76                 }
  77                 efree(ms->o.buf);
  78                 ms->o.buf = newstr;
  79         } else {
  80                 ms->o.buf = buf;
  81         }
  82         return 0;
  83 }
  84 
  85 /*
  86  * error - print best error message possible
  87  */
  88 /*VARARGS*/
  89 private void
  90 file_error_core(struct magic_set *ms, int error, const char *f, va_list va,
  91     size_t lineno)
  92 {
  93         char *buf = NULL;
  94         
  95         /* Only the first error is ok */
  96         if (ms->event_flags & EVENT_HAD_ERR)
  97                 return;
  98         if (lineno != 0) {
  99                 efree(ms->o.buf);
 100                 ms->o.buf = NULL;
 101                 file_printf(ms, "line %" SIZE_T_FORMAT "u: ", lineno);
 102         }
 103 
 104         vspprintf(&buf, 0, f, va);
 105         va_end(va);
 106         
 107         if (error > 0) {
 108                 file_printf(ms, "%s (%s)", (*buf ? buf : ""), strerror(error));
 109         } else if (*buf) {
 110                 file_printf(ms, "%s", buf);
 111         }
 112         
 113         if (buf) {
 114                 efree(buf);
 115         }
 116 
 117         ms->event_flags |= EVENT_HAD_ERR;
 118         ms->error = error;
 119 }
 120 
 121 /*VARARGS*/
 122 protected void
 123 file_error(struct magic_set *ms, int error, const char *f, ...)
 124 {
 125         va_list va;
 126         va_start(va, f);
 127         file_error_core(ms, error, f, va, 0);
 128         va_end(va);
 129 }
 130 
 131 /*
 132  * Print an error with magic line number.
 133  */
 134 /*VARARGS*/
 135 protected void
 136 file_magerror(struct magic_set *ms, const char *f, ...)
 137 {
 138         va_list va;
 139         va_start(va, f);
 140         file_error_core(ms, 0, f, va, ms->line);
 141         va_end(va);
 142 }
 143 
 144 protected void
 145 file_oomem(struct magic_set *ms, size_t len)
 146 {
 147         file_error(ms, errno, "cannot allocate %" SIZE_T_FORMAT "u bytes",
 148             len);
 149 }
 150 
 151 protected void
 152 file_badseek(struct magic_set *ms)
 153 {
 154         file_error(ms, errno, "error seeking");
 155 }
 156 
 157 protected void
 158 file_badread(struct magic_set *ms)
 159 {
 160         file_error(ms, errno, "error reading");
 161 }
 162 
 163 protected int
 164 file_buffer(struct magic_set *ms, php_stream *stream, const char *inname, const void *buf,
 165     size_t nb)
 166 {
 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;
 171         size_t ulen;
 172         const char *code = NULL;
 173         const char *code_mime = "binary";
 174         const char *type = "application/octet-stream";
 175         const char *def = "data";
 176         const char *ftype = NULL;
 177 
 178         if (nb == 0) {
 179                 def = "empty";
 180                 type = "application/x-empty";
 181                 goto simple;
 182         } else if (nb == 1) {
 183                 def = "very short file (no magic)";
 184                 goto simple;
 185         }
 186 
 187         if ((ms->flags & MAGIC_NO_CHECK_ENCODING) == 0) {
 188                 looks_text = file_encoding(ms, ubuf, nb, &u8buf, &ulen,
 189                     &code, &code_mime, &ftype);
 190         }
 191 
 192 #ifdef __EMX__
 193         if ((ms->flags & MAGIC_NO_CHECK_APPTYPE) == 0 && inname) {
 194                 switch (file_os2_apptype(ms, inname, buf, nb)) {
 195                 case -1:
 196                         return -1;
 197                 case 0:
 198                         break;
 199                 default:
 200                         return 1;
 201                 }
 202         }
 203 #endif
 204 
 205 #if PHP_FILEINFO_UNCOMPRESS
 206         if ((ms->flags & MAGIC_NO_CHECK_COMPRESS) == 0)
 207                 if ((m = file_zmagic(ms, stream, inname, ubuf, nb)) != 0) {
 208                         if ((ms->flags & MAGIC_DEBUG) != 0)
 209                                 (void)fprintf(stderr, "zmagic %d\n", m);
 210                         goto done_encoding;
 211                 }
 212 #endif
 213         /* Check if we have a tar file */
 214         if ((ms->flags & MAGIC_NO_CHECK_TAR) == 0)
 215                 if ((m = file_is_tar(ms, ubuf, nb)) != 0) {
 216                         if ((ms->flags & MAGIC_DEBUG) != 0)
 217                                 (void)fprintf(stderr, "tar %d\n", m);
 218                         goto done;
 219                 }
 220 
 221         /* Check if we have a CDF file */
 222         if ((ms->flags & MAGIC_NO_CHECK_CDF) == 0) {
 223                 php_socket_t fd;
 224                 TSRMLS_FETCH();
 225                 if (stream && SUCCESS == php_stream_cast(stream, PHP_STREAM_AS_FD, (void **)&fd, 0)) {
 226                         if ((m = file_trycdf(ms, fd, ubuf, nb)) != 0) {
 227                                 if ((ms->flags & MAGIC_DEBUG) != 0)
 228                                         (void)fprintf(stderr, "cdf %d\n", m);
 229                                 goto done;
 230                         }
 231                 }
 232         }
 233 
 234         /* try soft magic tests */
 235         if ((ms->flags & MAGIC_NO_CHECK_SOFT) == 0)
 236                 if ((m = file_softmagic(ms, ubuf, nb, 0, BINTEST,
 237                     looks_text)) != 0) {
 238                         if ((ms->flags & MAGIC_DEBUG) != 0)
 239                                 (void)fprintf(stderr, "softmagic %d\n", m);
 240 #ifdef BUILTIN_ELF
 241                         if ((ms->flags & MAGIC_NO_CHECK_ELF) == 0 && m == 1 &&
 242                             nb > 5 && fd != -1) {
 243                                 /*
 244                                  * We matched something in the file, so this
 245                                  * *might* be an ELF file, and the file is at
 246                                  * least 5 bytes long, so if it's an ELF file
 247                                  * it has at least one byte past the ELF magic
 248                                  * number - try extracting information from the
 249                                  * ELF headers that cannot easily * be
 250                                  * extracted with rules in the magic file.
 251                                  */
 252                                 if ((m = file_tryelf(ms, fd, ubuf, nb)) != 0)
 253                                         if ((ms->flags & MAGIC_DEBUG) != 0)
 254                                                 (void)fprintf(stderr,
 255                                                     "elf %d\n", m);
 256                         }
 257 #endif
 258                         goto done;
 259                 }
 260 
 261         /* try text properties */
 262         if ((ms->flags & MAGIC_NO_CHECK_TEXT) == 0) {
 263 
 264                 if ((m = file_ascmagic(ms, ubuf, nb, looks_text)) != 0) {
 265                         if ((ms->flags & MAGIC_DEBUG) != 0)
 266                                 (void)fprintf(stderr, "ascmagic %d\n", m);
 267                         goto done;
 268                 }
 269 
 270                 /* try to discover text encoding */
 271                 if ((ms->flags & MAGIC_NO_CHECK_ENCODING) == 0) {
 272                         if (looks_text == 0)
 273                                 if ((m = file_ascmagic_with_encoding( ms, ubuf,
 274                                     nb, u8buf, ulen, code, ftype, looks_text))
 275                                     != 0) {
 276                                         if ((ms->flags & MAGIC_DEBUG) != 0)
 277                                                 (void)fprintf(stderr,
 278                                                     "ascmagic/enc %d\n", m);
 279                                         goto done;
 280                                 }
 281                 }
 282         }
 283 
 284 simple:
 285         /* give up */
 286         m = 1;
 287         if ((!mime || (mime & MAGIC_MIME_TYPE)) &&
 288             file_printf(ms, "%s", mime ? type : def) == -1) {
 289             rv = -1;
 290         }
 291  done:
 292         if ((ms->flags & MAGIC_MIME_ENCODING) != 0) {
 293                 if (ms->flags & MAGIC_MIME_TYPE)
 294                         if (file_printf(ms, "; charset=") == -1)
 295                                 rv = -1;
 296                 if (file_printf(ms, "%s", code_mime) == -1)
 297                         rv = -1;
 298         }
 299  done_encoding:
 300         free(u8buf);
 301         if (rv)
 302                 return rv;
 303 
 304         return m;
 305 }
 306 
 307 protected int
 308 file_reset(struct magic_set *ms)
 309 {
 310         if (ms->mlist[0] == NULL) {
 311                 file_error(ms, 0, "no magic files loaded");
 312                 return -1;
 313         }
 314         if (ms->o.buf) {
 315                 efree(ms->o.buf);
 316                 ms->o.buf = NULL;
 317         }
 318         if (ms->o.pbuf) {
 319                 efree(ms->o.pbuf);
 320                 ms->o.pbuf = NULL;
 321         }
 322         ms->event_flags &= ~EVENT_HAD_ERR;
 323         ms->error = -1;
 324         return 0;
 325 }
 326 
 327 #define OCTALIFY(n, o)  \
 328         /*LINTED*/ \
 329         (void)(*(n)++ = '\\', \
 330         *(n)++ = (((uint32_t)*(o) >> 6) & 3) + '0', \
 331         *(n)++ = (((uint32_t)*(o) >> 3) & 7) + '0', \
 332         *(n)++ = (((uint32_t)*(o) >> 0) & 7) + '0', \
 333         (o)++)
 334 
 335 protected const char *
 336 file_getbuffer(struct magic_set *ms)
 337 {
 338         char *op, *np;
 339         size_t psize, len;
 340 
 341         if (ms->event_flags & EVENT_HAD_ERR)
 342                 return NULL;
 343 
 344         if (ms->flags & MAGIC_RAW)
 345                 return ms->o.buf;
 346 
 347         if (ms->o.buf == NULL)
 348                 return NULL;
 349 
 350         /* * 4 is for octal representation, + 1 is for NUL */
 351         len = strlen(ms->o.buf);
 352         if (len > (SIZE_MAX - 1) / 4) {
 353                 return NULL;
 354         }
 355         psize = len * 4 + 1;
 356         if ((ms->o.pbuf = CAST(char *, erealloc(ms->o.pbuf, psize))) == NULL) {
 357                 file_oomem(ms, psize);
 358                 return NULL;
 359         }
 360 
 361 #if defined(HAVE_WCHAR_H) && defined(HAVE_MBRTOWC) && defined(HAVE_WCWIDTH)
 362         {
 363                 mbstate_t state;
 364                 wchar_t nextchar;
 365                 int mb_conv = 1;
 366                 size_t bytesconsumed;
 367                 char *eop;
 368                 (void)memset(&state, 0, sizeof(mbstate_t));
 369 
 370                 np = ms->o.pbuf;
 371                 op = ms->o.buf;
 372                 eop = op + len;
 373 
 374                 while (op < eop) {
 375                         bytesconsumed = mbrtowc(&nextchar, op,
 376                             (size_t)(eop - op), &state);
 377                         if (bytesconsumed == (size_t)(-1) ||
 378                             bytesconsumed == (size_t)(-2)) {
 379                                 mb_conv = 0;
 380                                 break;
 381                         }
 382 
 383                         if (iswprint(nextchar)) {
 384                                 (void)memcpy(np, op, bytesconsumed);
 385                                 op += bytesconsumed;
 386                                 np += bytesconsumed;
 387                         } else {
 388                                 while (bytesconsumed-- > 0)
 389                                         OCTALIFY(np, op);
 390                         }
 391                 }
 392                 *np = '\0';
 393 
 394                 /* Parsing succeeded as a multi-byte sequence */
 395                 if (mb_conv != 0)
 396                         return ms->o.pbuf;
 397         }
 398 #endif
 399 
 400         for (np = ms->o.pbuf, op = ms->o.buf; *op;) {
 401                 if (isprint((unsigned char)*op)) {
 402                         *np++ = *op++;
 403                 } else {
 404                         OCTALIFY(np, op);
 405                 }
 406         }
 407         *np = '\0';
 408         return ms->o.pbuf;
 409 }
 410 
 411 protected int
 412 file_check_mem(struct magic_set *ms, unsigned int level)
 413 {
 414         size_t len;
 415 
 416         if (level >= ms->c.len) {
 417                 len = (ms->c.len += 20 + level) * sizeof(*ms->c.li);
 418                 ms->c.li = CAST(struct level_info *, (ms->c.li == NULL) ?
 419                     emalloc(len) :
 420                     erealloc(ms->c.li, len));
 421                 if (ms->c.li == NULL) {
 422                         file_oomem(ms, len);
 423                         return -1;
 424                 }
 425         }
 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 */
 431         return 0;
 432 }
 433 
 434 protected size_t
 435 file_printedlen(const struct magic_set *ms)
 436 {
 437         return ms->o.buf == NULL ? 0 : strlen(ms->o.buf);
 438 }
 439 
 440 file_replace(struct magic_set *ms, const char *pat, const char *rep)
 441 {
 442         zval *patt;
 443         int opts = 0;
 444         pcre_cache_entry *pce;
 445         char *res;
 446         zval *repl;
 447         int res_len, rep_cnt = 0;
 448         TSRMLS_FETCH();
 449 
 450         (void)setlocale(LC_CTYPE, "C");
 451 
 452         MAKE_STD_ZVAL(patt);
 453         ZVAL_STRINGL(patt, pat, strlen(pat), 0);
 454         opts |= PCRE_MULTILINE;
 455         convert_libmagic_pattern(patt, opts);
 456         if ((pce = pcre_get_compiled_regex_cache(Z_STRVAL_P(patt), Z_STRLEN_P(patt) TSRMLS_CC)) == NULL) {
 457                 zval_dtor(patt);
 458                 FREE_ZVAL(patt);
 459                 rep_cnt = -1;
 460                 goto out;
 461         }
 462 
 463         MAKE_STD_ZVAL(repl);
 464         ZVAL_STRINGL(repl, rep, strlen(rep), 0);
 465 
 466         res = php_pcre_replace_impl(pce, ms->o.buf, strlen(ms->o.buf), repl,
 467                         0, &res_len, -1, &rep_cnt TSRMLS_CC);
 468 
 469         FREE_ZVAL(repl);
 470         zval_dtor(patt);
 471         FREE_ZVAL(patt);
 472 
 473         if (NULL == res) {
 474                 rep_cnt = -1;
 475                 goto out;
 476         }
 477 
 478         strncpy(ms->o.buf, res, res_len);
 479         ms->o.buf[res_len] = '\0';
 480 
 481         efree(res);
 482 
 483 out:
 484         (void)setlocale(LC_CTYPE, "");
 485         return rep_cnt;
 486 }

/* [<][>][^][v][top][bottom][index][help] */