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
  14. file_push_buffer
  15. file_pop_buffer
  16. file_printable

   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.79 2014/12/16 20:52:49 christos 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)~0)
  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, char *val, int len, 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                         if (stream && SUCCESS == php_stream_cast(stream, PHP_STREAM_AS_FD, (void **)&fd, 0)) {
 225                         if ((m = file_trycdf(ms, fd, ubuf, nb)) != 0) {
 226                                 if ((ms->flags & MAGIC_DEBUG) != 0)
 227                                         (void)fprintf(stderr, "cdf %d\n", m);
 228                                 goto done;
 229                         }
 230                 }
 231         }
 232 
 233         /* try soft magic tests */
 234         if ((ms->flags & MAGIC_NO_CHECK_SOFT) == 0)
 235                 if ((m = file_softmagic(ms, ubuf, nb, 0, NULL, BINTEST,
 236                     looks_text)) != 0) {
 237                         if ((ms->flags & MAGIC_DEBUG) != 0)
 238                                 (void)fprintf(stderr, "softmagic %d\n", m);
 239 #ifdef BUILTIN_ELF
 240                         if ((ms->flags & MAGIC_NO_CHECK_ELF) == 0 && m == 1 &&
 241                             nb > 5 && fd != -1) {
 242                                 /*
 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.
 250                                  */
 251                                 if ((m = file_tryelf(ms, fd, ubuf, nb)) != 0)
 252                                         if ((ms->flags & MAGIC_DEBUG) != 0)
 253                                                 (void)fprintf(stderr,
 254                                                     "elf %d\n", m);
 255                         }
 256 #endif
 257                         goto done;
 258                 }
 259 
 260         /* try text properties */
 261         if ((ms->flags & MAGIC_NO_CHECK_TEXT) == 0) {
 262 
 263                 if ((m = file_ascmagic(ms, ubuf, nb, looks_text)) != 0) {
 264                         if ((ms->flags & MAGIC_DEBUG) != 0)
 265                                 (void)fprintf(stderr, "ascmagic %d\n", m);
 266                         goto done;
 267                 }
 268         }
 269 
 270 simple:
 271         /* give up */
 272         m = 1;
 273         if ((!mime || (mime & MAGIC_MIME_TYPE)) &&
 274             file_printf(ms, "%s", mime ? type : def) == -1) {
 275             rv = -1;
 276         }
 277  done:
 278         if ((ms->flags & MAGIC_MIME_ENCODING) != 0) {
 279                 if (ms->flags & MAGIC_MIME_TYPE)
 280                         if (file_printf(ms, "; charset=") == -1)
 281                                 rv = -1;
 282                 if (file_printf(ms, "%s", code_mime) == -1)
 283                         rv = -1;
 284         }
 285 #if PHP_FILEINFO_UNCOMPRESS
 286  done_encoding:
 287 #endif
 288         free(u8buf);
 289         if (rv)
 290                 return rv;
 291 
 292         return m;
 293 }
 294 
 295 protected int
 296 file_reset(struct magic_set *ms)
 297 {
 298         if (ms->mlist[0] == NULL) {
 299                 file_error(ms, 0, "no magic files loaded");
 300                 return -1;
 301         }
 302         if (ms->o.buf) {
 303                 efree(ms->o.buf);
 304                 ms->o.buf = NULL;
 305         }
 306         if (ms->o.pbuf) {
 307                 efree(ms->o.pbuf);
 308                 ms->o.pbuf = NULL;
 309         }
 310         ms->event_flags &= ~EVENT_HAD_ERR;
 311         ms->error = -1;
 312         return 0;
 313 }
 314 
 315 #define OCTALIFY(n, o)  \
 316         /*LINTED*/ \
 317         (void)(*(n)++ = '\\', \
 318         *(n)++ = (((uint32_t)*(o) >> 6) & 3) + '0', \
 319         *(n)++ = (((uint32_t)*(o) >> 3) & 7) + '0', \
 320         *(n)++ = (((uint32_t)*(o) >> 0) & 7) + '0', \
 321         (o)++)
 322 
 323 protected const char *
 324 file_getbuffer(struct magic_set *ms)
 325 {
 326         char *op, *np;
 327         size_t psize, len;
 328 
 329         if (ms->event_flags & EVENT_HAD_ERR)
 330                 return NULL;
 331 
 332         if (ms->flags & MAGIC_RAW)
 333                 return ms->o.buf;
 334 
 335         if (ms->o.buf == NULL)
 336                 return NULL;
 337 
 338         /* * 4 is for octal representation, + 1 is for NUL */
 339         len = strlen(ms->o.buf);
 340         if (len > (SIZE_MAX - 1) / 4) {
 341                 file_oomem(ms, len);
 342                 return NULL;
 343         }
 344         psize = len * 4 + 1;
 345         if ((ms->o.pbuf = CAST(char *, erealloc(ms->o.pbuf, psize))) == NULL) {
 346                 file_oomem(ms, psize);
 347                 return NULL;
 348         }
 349 
 350 #if defined(HAVE_WCHAR_H) && defined(HAVE_MBRTOWC) && defined(HAVE_WCWIDTH)
 351         {
 352                 mbstate_t state;
 353                 wchar_t nextchar;
 354                 int mb_conv = 1;
 355                 size_t bytesconsumed;
 356                 char *eop;
 357                 (void)memset(&state, 0, sizeof(mbstate_t));
 358 
 359                 np = ms->o.pbuf;
 360                 op = ms->o.buf;
 361                 eop = op + len;
 362 
 363                 while (op < eop) {
 364                         bytesconsumed = mbrtowc(&nextchar, op,
 365                             (size_t)(eop - op), &state);
 366                         if (bytesconsumed == (size_t)(-1) ||
 367                             bytesconsumed == (size_t)(-2)) {
 368                                 mb_conv = 0;
 369                                 break;
 370                         }
 371 
 372                         if (iswprint(nextchar)) {
 373                                 (void)memcpy(np, op, bytesconsumed);
 374                                 op += bytesconsumed;
 375                                 np += bytesconsumed;
 376                         } else {
 377                                 while (bytesconsumed-- > 0)
 378                                         OCTALIFY(np, op);
 379                         }
 380                 }
 381                 *np = '\0';
 382 
 383                 /* Parsing succeeded as a multi-byte sequence */
 384                 if (mb_conv != 0)
 385                         return ms->o.pbuf;
 386         }
 387 #endif
 388 
 389         for (np = ms->o.pbuf, op = ms->o.buf; *op;) {
 390                 if (isprint((unsigned char)*op)) {
 391                         *np++ = *op++;
 392                 } else {
 393                         OCTALIFY(np, op);
 394                 }
 395         }
 396         *np = '\0';
 397         return ms->o.pbuf;
 398 }
 399 
 400 protected int
 401 file_check_mem(struct magic_set *ms, unsigned int level)
 402 {
 403         size_t len;
 404 
 405         if (level >= ms->c.len) {
 406                 len = (ms->c.len += 20 + level) * sizeof(*ms->c.li);
 407                 ms->c.li = CAST(struct level_info *, (ms->c.li == NULL) ?
 408                     emalloc(len) :
 409                     erealloc(ms->c.li, len));
 410                 if (ms->c.li == NULL) {
 411                         file_oomem(ms, len);
 412                         return -1;
 413                 }
 414         }
 415         ms->c.li[level].got_match = 0;
 416 #ifdef ENABLE_CONDITIONALS
 417         ms->c.li[level].last_match = 0;
 418         ms->c.li[level].last_cond = COND_NONE;
 419 #endif /* ENABLE_CONDITIONALS */
 420         return 0;
 421 }
 422 
 423 protected size_t
 424 file_printedlen(const struct magic_set *ms)
 425 {
 426         return ms->o.buf == NULL ? 0 : strlen(ms->o.buf);
 427 }
 428 
 429 protected int
 430 file_replace(struct magic_set *ms, const char *pat, const char *rep)
 431 {
 432         zval patt;
 433         int opts = 0;
 434         pcre_cache_entry *pce;
 435         zend_string *res;
 436         zval repl;
 437         int  rep_cnt = 0;
 438 
 439         (void)setlocale(LC_CTYPE, "C");
 440 
 441         opts |= PCRE_MULTILINE;
 442         convert_libmagic_pattern(&patt, (char*)pat, strlen(pat), opts);
 443         if ((pce = pcre_get_compiled_regex_cache(Z_STR(patt))) == NULL) {
 444                 zval_ptr_dtor(&patt);
 445                 rep_cnt = -1;
 446                 goto out;
 447         }
 448         zval_ptr_dtor(&patt);
 449 
 450         ZVAL_STRING(&repl, rep);
 451         res = php_pcre_replace_impl(pce, NULL, ms->o.buf, strlen(ms->o.buf), &repl, 0, -1, &rep_cnt);
 452 
 453         zval_ptr_dtor(&repl);
 454         if (NULL == res) {
 455                 rep_cnt = -1;
 456                 goto out;
 457         }
 458 
 459         strncpy(ms->o.buf, ZSTR_VAL(res), ZSTR_LEN(res));
 460         ms->o.buf[ZSTR_LEN(res)] = '\0';
 461 
 462         zend_string_release(res);
 463 
 464 out:
 465         (void)setlocale(LC_CTYPE, "");
 466         return rep_cnt;
 467 }
 468 
 469 protected file_pushbuf_t *
 470 file_push_buffer(struct magic_set *ms)
 471 {
 472         file_pushbuf_t *pb;
 473 
 474         if (ms->event_flags & EVENT_HAD_ERR)
 475                 return NULL;
 476 
 477         if ((pb = (CAST(file_pushbuf_t *, emalloc(sizeof(*pb))))) == NULL)
 478                 return NULL;
 479 
 480         pb->buf = ms->o.buf;
 481         pb->offset = ms->offset;
 482 
 483         ms->o.buf = NULL;
 484         ms->offset = 0;
 485 
 486         return pb;
 487 }
 488 
 489 protected char *
 490 file_pop_buffer(struct magic_set *ms, file_pushbuf_t *pb)
 491 {
 492         char *rbuf;
 493 
 494         if (ms->event_flags & EVENT_HAD_ERR) {
 495                 efree(pb->buf);
 496                 efree(pb);
 497                 return NULL;
 498         }
 499 
 500         rbuf = ms->o.buf;
 501 
 502         ms->o.buf = pb->buf;
 503         ms->offset = pb->offset;
 504 
 505         efree(pb);
 506         return rbuf;
 507 }
 508 
 509 /*
 510  * convert string to ascii printable format.
 511  */
 512 protected char *
 513 file_printable(char *buf, size_t bufsiz, const char *str)
 514 {
 515         char *ptr, *eptr;
 516         const unsigned char *s = (const unsigned char *)str;
 517 
 518         for (ptr = buf, eptr = ptr + bufsiz - 1; ptr < eptr && *s; s++) {
 519                 if (isprint(*s)) {
 520                         *ptr++ = *s;
 521                         continue;
 522                 }
 523                 if (ptr >= eptr - 3)
 524                         break;
 525                 *ptr++ = '\\';
 526                 *ptr++ = ((*s >> 6) & 7) + '0';
 527                 *ptr++ = ((*s >> 3) & 7) + '0';
 528                 *ptr++ = ((*s >> 0) & 7) + '0';
 529         }
 530         *ptr = '\0';
 531         return buf;
 532 }
 533 

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