📄 mod_mime_magic.c
字号:
MODNAME ": broken symlink (%s)", fn); return HTTP_INTERNAL_SERVER_ERROR;#endif#ifdef S_IFSOCK#ifndef __COHERENT__ case S_IFSOCK: magic_rsl_puts(r, MIME_BINARY_UNKNOWN); return DONE;#endif#endif case S_IFREG: break; default: ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, r, MODNAME ": invalid mode 0%o.", (unsigned int)r->finfo.st_mode); return HTTP_INTERNAL_SERVER_ERROR; } /* * regular file, check next possibility */ if (r->finfo.st_size == 0) { magic_rsl_puts(r, MIME_TEXT_UNKNOWN); return DONE; } return 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(request_rec *r, unsigned char *buf, int nbytes){ if (match(r, 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(request_rec *r, unsigned char *s, int nbytes){#if MIME_MAGIC_DEBUG int rule_counter = 0;#endif int cont_level = 0; int need_separator = 0; union VALUETYPE p; magic_server_config_rec *conf = (magic_server_config_rec *) ap_get_module_config(r->server->module_config, &mime_magic_module); struct magic *m;#if MIME_MAGIC_DEBUG ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, r, MODNAME ": match conf=%x file=%s m=%s m->next=%s last=%s", conf, conf->magicfile ? conf->magicfile : "NULL", conf->magic ? "set" : "NULL", (conf->magic && conf->magic->next) ? "set" : "NULL", conf->last ? "set" : "NULL");#endif#if MIME_MAGIC_DEBUG for (m = conf->magic; m; m = m->next) { if (ap_isprint((((unsigned long) m) >> 24) & 255) && ap_isprint((((unsigned long) m) >> 16) & 255) && ap_isprint((((unsigned long) m) >> 8) & 255) && ap_isprint(((unsigned long) m) & 255)) { ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, r, MODNAME ": match: POINTER CLOBBERED! " "m=\"%c%c%c%c\"", (((unsigned long) m) >> 24) & 255, (((unsigned long) m) >> 16) & 255, (((unsigned long) m) >> 8) & 255, ((unsigned long) m) & 255); break; } }#endif for (m = conf->magic; m; m = m->next) {#if MIME_MAGIC_DEBUG rule_counter++; ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, r, MODNAME ": line=%d desc=%s", m->lineno, m->desc);#endif /* check if main entry matches */ if (!mget(r, &p, s, m, nbytes) || !mcheck(r, &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)) {#if MIME_MAGIC_DEBUG rule_counter++; ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, r, MODNAME ": line=%d mc=%x mc->next=%x cont=%d desc=%s", m_cont->lineno, m_cont, m_cont->next, m_cont->cont_level, m_cont->desc);#endif /* * 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 */#if MIME_MAGIC_DEBUG ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, r, MODNAME ": rule matched, line=%d type=%d %s", m->lineno, m->type, (m->type == STRING) ? m->value.s : "");#endif /* print the match */ mprint(r, &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 MIME_MAGIC_DEBUG ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, r, MODNAME ": match line=%d cont=%d type=%d %s", m->lineno, m->cont_level, m->type, (m->type == STRING) ? m->value.s : "");#endif 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(r, &p, s, m, nbytes) && mcheck(r, &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(r, ' '); need_separator = 0; } mprint(r, &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; }#if MIME_MAGIC_DEBUG ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, r, MODNAME ": matched after %d rules", rule_counter);#endif return 1; /* all through */ }#if MIME_MAGIC_DEBUG ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, r, MODNAME ": failed after %d rules", rule_counter);#endif return 0; /* no match at all */}static void mprint(request_rec *r, union VALUETYPE *p, struct magic *m){ char *pp, *rt; unsigned long v; switch (m->type) { case BYTE: v = p->b; break; case SHORT: case BESHORT: case LESHORT: v = p->h; break; case LONG: case BELONG: case LELONG: v = p->l; break; case STRING: if (m->reln == '=') { (void) magic_rsl_printf(r, m->desc, m->value.s); } else { (void) magic_rsl_printf(r, m->desc, p->s); } return; case DATE: case BEDATE: case LEDATE: /* XXX: not multithread safe */ pp = ctime((time_t *) & p->l); if ((rt = strchr(pp, '\n')) != NULL) *rt = '\0'; (void) magic_rsl_printf(r, m->desc, pp); return; default: ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, r, MODNAME ": invalid m->type (%d) in mprint().", m->type); return; } v = signextend(r->server, m, v) & m->mask; (void) magic_rsl_printf(r, m->desc, (unsigned long) v);}/* * Convert the byte order of the data we are looking at */static int mconvert(request_rec *r, union VALUETYPE *p, struct magic *m){ char *rt; switch (m->type) { case BYTE: case SHORT: case LONG: case DATE: return 1; case STRING: /* Null terminate and eat the return */ p->s[sizeof(p->s) - 1] = '\0'; if ((rt = strchr(p->s, '\n')) != NULL) *rt = '\0'; return 1; case BESHORT: p->h = (short) ((p->hs[0] << 8) | (p->hs[1])); return 1; case BELONG: case BEDATE: p->l = (long) ((p->hl[0] << 24) | (p->hl[1] << 16) | (p->hl[2] << 8) | (p->hl[3])); return 1; case LESHORT: p->h = (short) ((p->hs[1] << 8) | (p->hs[0])); return 1; case LELONG: case LEDATE: p->l = (long) ((p->hl[3] << 24) | (p->hl[2] << 16) | (p->hl[1] << 8) | (p->hl[0])); return 1; default: ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, r, MODNAME ": invalid type %d in mconvert().", m->type); return 0; }}static int mget(request_rec *r, union VALUETYPE *p, unsigned char *s, struct magic *m, int nbytes){ long offset = m->offset; if (offset + sizeof(union VALUETYPE) > nbytes) return 0; memcpy(p, s + offset, sizeof(union VALUETYPE)); if (!mconvert(r, p, m)) return 0; if (m->flag & INDIR) { switch (m->in.type) { case BYTE: offset = p->b + m->in.offset; break; case SHORT: offset = p->h + m->in.offset; break; case LONG: offset = p->l + m->in.offset; break; } if (offset + sizeof(union VALUETYPE) > nbytes) return 0; memcpy(p, s + offset, sizeof(union VALUETYPE)); if (!mconvert(r, p, m)) return 0; } return 1;}static int mcheck(request_rec *r, union VALUETYPE *p, struct magic *m){ register unsigned long l = m->value.l; register unsigned long v; int matched; if ((m->value.s[0] == 'x') && (m->value.s[1] == '\0')) { ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, r, MODNAME ": BOINK"); return 1; } switch (m->type) { case BYTE: v = p->b; break; case SHORT: case BESHORT: case LESHORT: v = p->h; break; case LONG: case BELONG: case LELONG: case DATE: case BEDATE: case LEDATE: v = p->l; break; case STRING: l = 0; /* * What we want here is: v = strncmp(m->value.s, p->s, m->vallen); * but ignoring any nulls. bcmp doesn't give -/+/0 and isn't * universally available anyway. */ v = 0; { register unsigned char *a = (unsigned char *) m->value.s; register unsigned char *b = (unsigned char *) p->s; register int len = m->vallen; while (--len >= 0) if ((v = *b++ - *a++) != 0) break; } break; default: /* bogosity, pretend that it just wasn't a match */ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, r, MODNAME ": invalid type %d in mcheck().", m->type); return 0; } v = signextend(r->server, m, v) & m->mask; switch (m->reln) { case 'x':#if MIME_MAGIC_DEBUG ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, r, "%lu == *any* = 1", v);#endif matched = 1; break; case '!': matched = v != l;#if MIME_MAGIC_DEBUG ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, r, "%lu != %lu = %d", v, l, matched);#endif break; case '=': matched = v == l;#if MIME_MAGIC_DEBUG ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, r, "%lu == %lu = %d", v, l, matched);#endif break; case '>': if (m->flag & UNSIGNED) { matched = v > l;#if MIME_MAGIC_DEBUG ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, r, "%lu > %lu = %d", v, l, matched);#endif } else { matched = (long) v > (long) l;#if MIME_MAGIC_DEBUG ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, r, "%ld > %ld = %d", v, l, matched);#endif } break; case '<': if (m->flag & UNSIGNED) { matched = v < l;#if MIME_MAGIC_DEBUG ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, r, "%lu < %lu = %d", v, l, matched);#endif } else { matched = (long) v < (long) l;#if MIME_MAGIC_DEBUG ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, r, "%ld < %ld = %d", v, l, matched);#endif } break; case '&': matched = (v & l) == l;#if MIME_MAGIC_DEBUG ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, r, "((%lx & %lx) == %lx) = %d", v, l, l, matched);#endif break; case '^': matched = (v & l) != l;#if MIME_MAGIC_DEBUG ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, r, "((%lx & %lx) != %lx) = %d", v, l, l, matched);#endif break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -