📄 mime_magic.c
字号:
if (cur_frag < start_frag) continue; /* loop through and collect chars */ for (cur_pos = (cur_frag == start_frag) ? start_pos : 0; frag->str[cur_pos]; cur_pos++) { if (cur_frag >= start_frag && cur_pos >= start_pos && res_pos <= len) { result[res_pos++] = frag->str[cur_pos]; if (res_pos > len) { break; } } } } /* clean up and return */ result[res_pos] = 0; return result;}/* * magic_process - process input file r Apache API request record * (formerly called "process" in file command, prefix added for clarity) Opens * the file and reads a fixed-size buffer to begin processing the contents. */static int magic_process(char *filename TSRMLS_DC){ php_stream *stream; unsigned char buf[HOWMANY + 1]; /* one extra for terminating '\0' */ int nbytes = 0; /* number of bytes read from a datafile */ int result; /* * first try judging the file based on its filesystem status */ switch ((result = fsmagic(filename TSRMLS_CC))) { case MIME_MAGIC_DONE: magic_rsl_putchar('\n'); return MIME_MAGIC_OK; case MIME_MAGIC_OK: break; default: /* fatal error, bail out */ return result; } stream = php_stream_open_wrapper(filename, "rb", IGNORE_PATH | ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL); if (stream == NULL) { /* We can't open it, but we were able to stat it. */ php_error(E_WARNING, MODNAME ": can't read `%s'", filename); /* let some other handler decide what the problem is */ return MIME_MAGIC_DECLINED; } /* * try looking at the first HOWMANY bytes */ if ((nbytes = php_stream_read(stream, (char *) buf, sizeof(buf) - 1)) == -1) { php_error(E_WARNING, MODNAME ": read failed: %s", filename); return MIME_MAGIC_ERROR; } if (nbytes == 0) magic_rsl_puts(MIME_TEXT_UNKNOWN); else { buf[nbytes++] = '\0'; /* null-terminate it */ tryit(buf, nbytes, 1); } (void) php_stream_close(stream); (void) magic_rsl_putchar('\n'); return MIME_MAGIC_OK;}static void tryit(unsigned char *buf, int nb, int checkzmagic){ /* * Try compression stuff */#if HAVE_ZLIB && !defined(COMPILE_DL_ZLIB) if (checkzmagic == 1) { if (zmagic(buf, nb) == 1) return; }#endif /* * try tests in /etc/magic (or surrogate magic file) */ if (softmagic(buf, nb) == 1) return; /* * try known keywords, check for ascii-ness too. */ if (ascmagic(buf, nb) == 1) return; /* * abandon hope, all ye who remain here */ magic_rsl_puts(MIME_BINARY_UNKNOWN);}/* * return MIME_MAGIC_DONE to indicate it's been handled * return MIME_MAGIC_OK to indicate it's a regular file still needing handling * other returns indicate a failure of some sort */static int fsmagic(char *filename TSRMLS_DC){ php_stream_statbuf stat_ssb; if(!php_stream_stat_path(filename, &stat_ssb)) { return MIME_MAGIC_OK; } switch (stat_ssb.sb.st_mode & S_IFMT) { case S_IFDIR: magic_rsl_puts(DIR_MAGIC_TYPE); return MIME_MAGIC_DONE; case S_IFCHR: /* * (void) magic_rsl_printf(r,"character special (%d/%d)", * major(sb->st_rdev), minor(sb->st_rdev)); */ (void) magic_rsl_puts(MIME_BINARY_UNKNOWN); return MIME_MAGIC_DONE;#ifdef S_IFBLK case S_IFBLK: /* * (void) magic_rsl_printf(r,"block special (%d/%d)", * major(sb->st_rdev), minor(sb->st_rdev)); */ (void) magic_rsl_puts(MIME_BINARY_UNKNOWN); return MIME_MAGIC_DONE; /* TODO add code to handle V7 MUX and Blit MUX files */#endif#ifdef S_IFIFO case S_IFIFO: /* * magic_rsl_puts(r,"fifo (named pipe)"); */ (void) magic_rsl_puts(MIME_BINARY_UNKNOWN); return MIME_MAGIC_DONE;#endif#ifdef S_IFLNK case S_IFLNK: /* We used stat(), the only possible reason for this is that the * symlink is broken. */ php_error(E_WARNING, MODNAME ": broken symlink (%s)", filename); return MIME_MAGIC_ERROR;#endif#ifdef S_IFSOCK#ifndef __COHERENT__ case S_IFSOCK: magic_rsl_puts(MIME_BINARY_UNKNOWN); return MIME_MAGIC_DONE;#endif#endif case S_IFREG: break; case 0: break; default: php_error(E_WARNING, MODNAME ": invalid mode 0%o.", (unsigned int)stat_ssb.sb.st_mode); return MIME_MAGIC_ERROR; } /* * regular file, check next possibility */ if (stat_ssb.sb.st_size == 0) { magic_rsl_puts(MIME_TEXT_UNKNOWN); return MIME_MAGIC_DONE; } return MIME_MAGIC_OK;}/* * softmagic - lookup one file in database (already read from /etc/magic by * apprentice.c). Passed the name and FILE * of one file to be typed. *//* ARGSUSED1 *//* nbytes passed for regularity, maybe need later */static int softmagic(unsigned char *buf, int nbytes){ if (match(buf, nbytes)) return 1; return 0;}/* * Go through the whole list, stopping if you find a match. Process all the * continuations of that match before returning. * * We support multi-level continuations: * * At any time when processing a successful top-level match, there is a current * continuation level; it represents the level of the last successfully * matched continuation. * * Continuations above that level are skipped as, if we see one, it means that * the continuation that controls them - i.e, the lower-level continuation * preceding them - failed to match. * * Continuations below that level are processed as, if we see one, it means * we've finished processing or skipping higher-level continuations under the * control of a successful or unsuccessful lower-level continuation, and are * now seeing the next lower-level continuation and should process it. The * current continuation level reverts to the level of the one we're seeing. * * Continuations at the current level are processed as, if we see one, there's * no lower-level continuation that may have failed. * * If a continuation matches, we bump the current continuation level so that * higher-level continuations are processed. */static int match(unsigned char *s, int nbytes){ int cont_level = 0; int need_separator = 0; union VALUETYPE p; magic_server_config_rec *conf = &mime_global; struct magic *m; for (m = conf->magic; m; m = m->next) { /* check if main entry matches */ if (!mget(&p, s, m, nbytes) || !mcheck(&p, m)) { struct magic *m_cont; /* * main entry didn't match, flush its continuations */ if (!m->next || (m->next->cont_level == 0)) { continue; } m_cont = m->next; while (m_cont && (m_cont->cont_level != 0)) { /* * this trick allows us to keep *m in sync when the continue * advances the pointer */ m = m_cont; m_cont = m_cont->next; } continue; } /* if we get here, the main entry rule was a match */ /* this will be the last run through the loop */ /* print the match */ mprint(&p, m); /* * If we printed something, we'll need to print a blank before we * print something else. */ if (m->desc[0]) need_separator = 1; /* and any continuations that match */ cont_level++; /* * while (m && m->next && m->next->cont_level != 0 && ( m = m->next * )) */ m = m->next; while (m && (m->cont_level != 0)) { if (cont_level >= m->cont_level) { if (cont_level > m->cont_level) { /* * We're at the end of the level "cont_level" * continuations. */ cont_level = m->cont_level; } if (mget(&p, s, m, nbytes) && mcheck(&p, m)) { /* * This continuation matched. Print its message, with a * blank before it if the previous item printed and this * item isn't empty. */ /* space if previous printed */ if (need_separator && (m->nospflag == 0) && (m->desc[0] != '\0') ) { (void) magic_rsl_putchar(' '); need_separator = 0; } mprint(&p, m); if (m->desc[0]) need_separator = 1; /* * If we see any continuations at a higher level, process * them. */ cont_level++; } } /* move to next continuation record */ m = m->next; } return 1; /* all through */ } return 0; /* no match at all */}/* an optimization over plain strcmp() */#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)static int ascmagic(unsigned char *buf, int nbytes){ int has_escapes = 0; unsigned char *s; char nbuf[HOWMANY + 1]; /* one extra for terminating '\0' */ char *token; register struct names *p; int small_nbytes; /* these are easy, do them first */ /* * for troff, look for . + letter + letter or .\"; this must be done to * disambiguate tar archives' ./file and other trash from real troff * input. */ if (*buf == '.') { unsigned char *tp = buf + 1; while (isspace(*tp)) ++tp; /* skip leading whitespace */ if ((isalnum(*tp) || *tp == '\\') && (isalnum(*(tp + 1)) || *tp == '"')) { magic_rsl_puts("application/x-troff"); return 1; } } if ((*buf == 'c' || *buf == 'C') && isspace(*(buf + 1))) { /* Fortran */ magic_rsl_puts("text/plain"); return 1; } /* look for tokens from names.h - this is expensive!, so we'll limit * ourselves to only SMALL_HOWMANY bytes */ small_nbytes = (nbytes > SMALL_HOWMANY) ? SMALL_HOWMANY : nbytes; /* make a copy of the buffer here because strtok() will destroy it */ s = (unsigned char *) memcpy(nbuf, buf, small_nbytes); s[small_nbytes] = '\0'; has_escapes = (memchr(s, '\033', small_nbytes) != NULL); /* XXX: not multithread safe */ while ((token = strtok((char *) s, " \t\n\r\f")) != NULL) { s = NULL; /* make strtok() keep on tokin' */ for (p = names; p < names + NNAMES; p++) { if (STREQ(p->name, token)) { magic_rsl_puts(types[p->type]); if (has_escapes) magic_rsl_puts(" (with escape sequences)"); return 1; } } } switch (is_tar(buf, nbytes)) { case 1: /* V7 tar archive */ magic_rsl_puts("application/x-tar"); return 1; case 2: /* POSIX tar archive */ magic_rsl_puts("application/x-tar"); return 1; } /* all else fails, but it is ascii... */ if (has_escapes) { /* text with escape sequences */ /* we leave this open for further differentiation later */ magic_rsl_puts("text/plain"); } else { /* plain text */ magic_rsl_puts("text/plain"); } return 1;}/* * is_tar() -- figure out whether file is a tar archive. * * Stolen (by author of file utility) from the public domain tar program: Public * Domain version written 26 Aug 1985 John Gilmore (ihnp4!hoptoad!gnu). * * @(#)list.c 1.18 9/23/86 Public Domain - gnu $Id: mod_mime_magic.c,v 1.7 * 1997/06/24 00:41:02 ikluft Exp ikluft $ * * Comments changed and some code/comments reformatted for file command by Ian * Darwin. */#define isodigit(c) ( ((c) >= '0') && ((c) <= '7') )/* * Return 0 if the checksum is bad (i.e., probably not a tar archive), 1 for * old UNIX tar file, 2 for Unix Std (POSIX) tar file. */static int is_tar(unsigned char *buf, int nbytes){ register union record *header = (union record *) buf; register int i; register long sum, recsum; register char *p; if (nbytes < sizeof(union record)) return 0; recsum = from_oct(8, header->header.chksum); sum = 0; p = header->charptr; for (i = sizeof(union record); --i >= 0;) { /* * We can't use unsigned char here because of old compilers, e.g. V7. */ sum += 0xFF & *p++; } /* Adjust checksum to count the "chksum" field as blanks. */ for (i = sizeof(header->header.chksum); --i >= 0;) sum -= 0xFF & header->header.chksum[i]; sum += ' ' * sizeof header->header.chksum; if (sum != recsum) return 0; /* Not a tar archive */ if (0 == strcmp(header->header.magic, TMAGIC)) return 2; /* Unix Standard tar archive */ return 1; /* Old fashioned tar archive */}/* * Quick and dirty octal conversion. * * Result is -1 if the field is invalid (all blank, or nonoctal). */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -