⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 remap.c

📁 非常流行而且必须的网络功能
💻 C
字号:
/* $Id$ *//* ----------------------------------------------------------------------- * *    *   Copyright 2001-2004 H. Peter Anvin - All Rights Reserved * *   This program is free software available under the same license *   as the "OpenBSD" operating system, distributed at *   http://www.openbsd.org/. * * ----------------------------------------------------------------------- *//* * remap.c * * Perform regular-expression based filename remapping. */#include "config.h"		/* Must be included first! */#include <ctype.h>#include <syslog.h>#include <regex.h>#include "tftpd.h"#include "remap.h"#define DEADMAN_MAX_STEPS	1024    /* Timeout after this many steps */#define MAXLINE 		16384   /* Truncate a line at this many bytes */#define RULE_REWRITE	0x01	/* This is a rewrite rule */#define RULE_GLOBAL	0x02	/* Global rule (repeat until no match) */#define RULE_EXIT	0x04	/* Exit after matching this rule */#define RULE_RESTART	0x08	/* Restart at the top after matching this rule */#define RULE_ABORT	0x10	/* Terminate processing with an error */#define RULE_GETONLY	0x20	/* Applicable to GET only */#define RULE_PUTONLY	0x40	/* Applicable to PUT only */#define RULE_INVERSE	0x80	/* Execute if regex *doesn't* match */struct rule {  struct rule *next;  int nrule;  int rule_flags;  regex_t rx;  const char *pattern;};static int xform_null(int c){  return c;}static int xform_toupper(int c){  return toupper(c);}static int xform_tolower(int c){  return tolower(c);}/* Do \-substitution.  Call with string == NULL to get length only. */static int genmatchstring(char *string, const char *pattern, const char *input,			  const regmatch_t *pmatch, match_pattern_callback macrosub){  int (*xform)(int) = xform_null;  int len = 0;  int n, mlen, sublen;  int endbytes;  /* Get section before match; note pmatch[0] is the whole match */  endbytes = strlen(input) - pmatch[0].rm_eo;  len = pmatch[0].rm_so + endbytes;  if ( string ) {    memcpy(string, input, pmatch[0].rm_so);    string += pmatch[0].rm_so;  }  /* Transform matched section */  while ( *pattern ) {    mlen = 0;    if ( *pattern == '\\' && pattern[1] != '\0' ) {      char macro = pattern[1];      switch ( macro ) {      case '0': case '1': case '2': case '3': case '4':      case '5': case '6': case '7': case '8': case '9':	n = pattern[1] - '0';		if ( pmatch[n].rm_so != -1 ) {	  mlen = pmatch[n].rm_eo - pmatch[n].rm_so;	  len += mlen;	  if ( string ) {	    const char *p = input+pmatch[n].rm_so;	    while ( mlen-- )	      *string++ = xform(*p++);	  }	}	break;      case 'L':	xform = xform_tolower;	break;      case 'U':	xform = xform_toupper;	break;      case 'E':	xform = xform_null;	break;      default:	if ( macrosub &&	     (sublen = macrosub(macro, string)) >= 0 ) {	  while ( sublen-- ) {	    len++;	    if ( string ) {	      *string = xform(*string);	      string++;	    }	  }	} else {	  len++;	  if ( string )	    *string++ = xform(pattern[1]);	}      }      pattern += 2;    } else {      len++;      if ( string )	*string++ = xform(*pattern);      pattern++;    }  }  /* Copy section after match */  if ( string ) {    memcpy(string, input+pmatch[0].rm_eo, endbytes);    string[endbytes] = '\0';  }  return len;}/* * Extract a string terminated by non-escaped whitespace; ignoring * leading whitespace.  Consider an unescaped # to be a comment marker, * functionally \n. */static int readescstring(char *buf, char **str){  char *p = *str;  int wasbs = 0, len = 0;  while ( *p && isspace(*p) )    p++;  if ( ! *p ) {    *buf = '\0';    *str = p;    return 0;  }  while ( *p ) {    if ( !wasbs && (isspace(*p) || *p == '#') ) {      *buf = '\0';      *str = p;      return len;    }    /* Important: two backslashes leave us in the !wasbs state! */    wasbs = !wasbs && ( *p == '\\' );    *buf++ = *p++;    len++;  }  *buf = '\0';  *str = p;  return len;}/* Parse a line into a set of instructions */static int parseline(char *line, struct rule *r, int lineno){  char buffer[MAXLINE];  char *p;  int rv;  int rxflags = REG_EXTENDED;  static int nrule;  memset(r, 0, sizeof *r);  r->nrule = nrule;  if ( !readescstring(buffer, &line) )    return 0;			/* No rule found */  for ( p = buffer ; *p ; p++ ) {    switch(*p) {    case 'r':      r->rule_flags |= RULE_REWRITE;      break;    case 'g':      r->rule_flags |= RULE_GLOBAL;      break;    case 'e':      r->rule_flags |= RULE_EXIT;      break;    case 's':      r->rule_flags |= RULE_RESTART;      break;    case 'a':      r->rule_flags |= RULE_ABORT;      break;    case 'i':      rxflags |= REG_ICASE;      break;    case 'G':      r->rule_flags |= RULE_GETONLY;      break;    case 'P':      r->rule_flags |= RULE_PUTONLY;      break;    case '~':      r->rule_flags |= RULE_INVERSE;      break;    default:      syslog(LOG_ERR, "Remap command \"%s\" on line %d contains invalid char \"%c\"",	     buffer, lineno, *p);      return -1;		/* Error */      break;    }  }  /* RULE_GLOBAL only applies when RULE_REWRITE specified */  if ( !(r->rule_flags & RULE_REWRITE) )    r->rule_flags &= ~RULE_GLOBAL;  if ( (r->rule_flags & (RULE_INVERSE|RULE_REWRITE)) ==       (RULE_INVERSE|RULE_REWRITE) ) {    syslog(LOG_ERR, "r rules cannot be inverted, line %d: %s\n", lineno, line);    return -1;			/* Error */  }  /* Read and compile the regex */  if ( !readescstring(buffer, &line) ) {    syslog(LOG_ERR, "No regex on remap line %d: %s\n", lineno, line);    return -1;			/* Error */  }  if ( (rv = regcomp(&r->rx, buffer, rxflags)) != 0 ) {    char errbuf[BUFSIZ];    regerror(rv, &r->rx, errbuf, BUFSIZ);    syslog(LOG_ERR, "Bad regex in remap line %d: %s\n", lineno, errbuf);    return -1;			/* Error */  }  /* Read the rewrite pattern, if any */  if ( readescstring(buffer, &line) ) {    r->pattern = tfstrdup(buffer);  } else {    r->pattern = "";  }  nrule++;  return 1;			/* Rule found */}/* Read a rule file */struct rule *parserulefile(FILE *f){  char line[MAXLINE];  struct rule *first_rule = NULL;  struct rule **last_rule = &first_rule;  struct rule *this_rule  = tfmalloc(sizeof(struct rule));  int rv;  int lineno = 0;  int err = 0;  while ( lineno++, fgets(line, MAXLINE, f) ) {    rv = parseline(line, this_rule, lineno);    if ( rv < 0 )      err = 1;    if ( rv > 0 ) {      *last_rule = this_rule;      last_rule = &this_rule->next;      this_rule = tfmalloc(sizeof(struct rule));    }  }  free(this_rule);		/* Last one is always unused */  if ( err ) {    /* Bail on error, we have already logged an error message */    exit(EX_CONFIG);  }  return first_rule;}/* Destroy a rule file data structure */void freerules(struct rule *r){  struct rule *next;  while ( r ) {    next = r->next;    regfree(&r->rx);    /* "" patterns aren't allocated by malloc() */    if ( r->pattern && *r->pattern )      free((void *)r->pattern);      free(r);    r = next;  }}/* Execute a rule set on a string; returns a malloc'd new string. */char *rewrite_string(const char *input, const struct rule *rules,		     int is_put, match_pattern_callback macrosub,		     const char **errmsg){  char *current = tfstrdup(input);  char *newstr;  const struct rule *ruleptr = rules;  regmatch_t pmatch[10];  int len;  int was_match = 0;  int deadman = DEADMAN_MAX_STEPS;  /* Default error */  *errmsg = "Remap table failure";  if ( verbosity >= 3 ) {    syslog(LOG_INFO, "remap: input: %s", current);  }  for ( ruleptr = rules ; ruleptr ; ruleptr = ruleptr->next ) {    if ( ((ruleptr->rule_flags & RULE_GETONLY) && is_put) ||	 ((ruleptr->rule_flags & RULE_PUTONLY) && !is_put) ) {      continue;			/* Rule not applicable, try next */    }    if ( ! deadman-- ) {      syslog(LOG_WARNING, "remap: Breaking loop, input = %s, last = %s",	     input, current);      free(current);      return NULL;		/* Did not terminate! */    }    do {      if ( regexec(&ruleptr->rx, current, 10, pmatch, 0) ==	   (ruleptr->rule_flags & RULE_INVERSE ? REG_NOMATCH : 0) ) {	/* Match on this rule */	was_match = 1;	if ( ruleptr->rule_flags & RULE_INVERSE ) {	  /* No actual match, so clear out the pmatch array */	  int i;	  for ( i = 0 ; i < 10 ; i++ )	    pmatch[i].rm_so = pmatch[i].rm_eo = -1;	}	if ( ruleptr->rule_flags & RULE_ABORT ) {	  if ( verbosity >= 3 ) {	    syslog(LOG_INFO, "remap: rule %d: abort: %s",		   ruleptr->nrule, current);	  }	  if ( ruleptr->pattern[0] ) {	    /* Custom error message */	    len = genmatchstring(NULL, ruleptr->pattern, current,				 pmatch, macrosub);	    newstr = tfmalloc(len+1);	    genmatchstring(newstr, ruleptr->pattern, current,			   pmatch, macrosub);	    *errmsg = newstr;	  } else {	    *errmsg = NULL;	  }	  free(current);	  return(NULL);	}		if ( ruleptr->rule_flags & RULE_REWRITE ) {	  len = genmatchstring(NULL, ruleptr->pattern, current,			       pmatch, macrosub);	  newstr = tfmalloc(len+1);	  genmatchstring(newstr, ruleptr->pattern, current,			 pmatch, macrosub);	  free(current);	  current = newstr;	  if ( verbosity >= 3 ) {	    syslog(LOG_INFO, "remap: rule %d: rewrite: %s",		   ruleptr->nrule, current);	  }	}      } else {	break;			/* No match, terminate unconditionally */      }      /* If the rule is global, keep going until no match */    } while ( ruleptr->rule_flags & RULE_GLOBAL );        if ( was_match ) {      was_match = 0;      if ( ruleptr->rule_flags & RULE_EXIT ) {	if ( verbosity >= 3 ) {	  syslog(LOG_INFO, "remap: rule %d: exit", ruleptr->nrule);	}	return current;		/* Exit here, we're done */      } else if ( ruleptr->rule_flags & RULE_RESTART ) {	ruleptr = rules;	/* Start from the top */	if ( verbosity >= 3 ) {	  syslog(LOG_INFO, "remap: rule %d: restart", ruleptr->nrule);	}      }    }  }  if ( verbosity >= 3 ) {    syslog(LOG_INFO, "remap: done");  }  return current;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -