X-Git-Url: http://www.dolda2000.com/gitweb/?a=blobdiff_plain;f=src%2Fdirplex.c;h=60f0859ddcb86d41560fcd4b75fdbb9d54472e45;hb=13975be5892675874bea8c86d7d8140f5790e7e6;hp=7216d9523019f7fb850c6d482a36fccbbb2e543f;hpb=624f637dd0eb621353222dac371ab9672ffe62b1;p=ashd.git diff --git a/src/dirplex.c b/src/dirplex.c index 7216d95..60f0859 100644 --- a/src/dirplex.c +++ b/src/dirplex.c @@ -43,21 +43,26 @@ #define PAT_ALL 2 #define PAT_DEFAULT 3 +#define PT_FILE 0 +#define PT_DIR 1 + struct config { struct config *next, *prev; char *path; time_t mtime, lastck; struct child *children; struct pattern *patterns; + char **index; }; struct rule { int type; - char *pattern; + char **patterns; }; struct pattern { struct pattern *next; + int type; char *childnm; char **fchild; struct rule **rules; @@ -67,15 +72,18 @@ static struct config *cflist; static struct config *gconfig, *lconfig; static time_t now; +static void freerule(struct rule *rule) +{ + freeca(rule->patterns); + free(rule); +} + static void freepattern(struct pattern *pat) { struct rule **rule; - for(rule = pat->rules; *rule; rule++) { - if((*rule)->pattern != NULL) - free((*rule)->pattern); - free(*rule); - } + for(rule = pat->rules; *rule; rule++) + freerule(*rule); if(pat->childnm != NULL) free(pat->childnm); freeca(pat->fchild); @@ -103,6 +111,7 @@ static void freeconfig(struct config *cf) npat = pat->next; freepattern(pat); } + freeca(cf->index); free(cf); } @@ -138,11 +147,24 @@ static struct pattern *newpattern(void) return(pat); } +static char **cadup(char **w) +{ + char **ret; + int i, l; + + l = calen(w); + ret = smalloc(sizeof(*ret) * (l + 1)); + for(i = 0; i < l; i++) + ret[i] = sstrdup(w[i]); + ret[i] = NULL; + return(ret); +} + static struct pattern *parsepattern(struct cfstate *s) { struct pattern *pat; struct rule *rule; - int sl, i; + int sl; if(!strcmp(s->argv[0], "match")) { s->expstart = 1; @@ -151,6 +173,8 @@ static struct pattern *parsepattern(struct cfstate *s) return(NULL); } + if((s->argc > 1) && !strcmp(s->argv[1], "directory")) + pat->type = PT_DIR; sl = s->lno; while(1) { getcfline(s); @@ -161,7 +185,7 @@ static struct pattern *parsepattern(struct cfstate *s) } rule = newrule(pat); rule->type = PAT_BASENAME; - rule->pattern = sstrdup(s->argv[1]); + rule->patterns = cadup(s->argv + 1); } else if(!strcmp(s->argv[0], "pathname")) { if(s->argc < 2) { flog(LOG_WARNING, "%s:%i: missing pattern for `pathname' match", s->file, s->lno); @@ -169,7 +193,7 @@ static struct pattern *parsepattern(struct cfstate *s) } rule = newrule(pat); rule->type = PAT_PATHNAME; - rule->pattern = sstrdup(s->argv[1]); + rule->patterns = cadup(s->argv + 1); } else if(!strcmp(s->argv[0], "all")) { newrule(pat)->type = PAT_ALL; } else if(!strcmp(s->argv[0], "default")) { @@ -183,10 +207,7 @@ static struct pattern *parsepattern(struct cfstate *s) free(pat->childnm); pat->childnm = sstrdup(s->argv[1]); } else if(!strcmp(s->argv[0], "fork")) { - pat->fchild = smalloc(sizeof(*pat->fchild) * s->argc); - for(i = 0; i < s->argc - 1; i++) - pat->fchild[i] = sstrdup(s->argv[i + 1]); - pat->fchild[i] = 0; + pat->fchild = cadup(s->argv + 1); } else if(!strcmp(s->argv[0], "end") || !strcmp(s->argv[0], "eof")) { break; } else { @@ -238,6 +259,11 @@ static struct config *readconfig(char *file) } else if((pat = parsepattern(s)) != NULL) { pat->next = cf->patterns; cf->patterns = pat; + } else if(!strcmp(s->argv[0], "index-file")) { + freeca(cf->index); + cf->index = NULL; + if(s->argc > 1) + cf->index = cadup(s->argv + 1); } else if(!strcmp(s->argv[0], "eof")) { break; } else { @@ -282,6 +308,9 @@ static struct config *getconfig(char *path) cf->mtime = mtime; cf->lastck = now; cf->next = cflist; + cf->prev = NULL; + if(cflist != NULL) + cflist->prev = cf; cflist = cf; return(cf); } @@ -332,9 +361,9 @@ static struct child *findchild(char *file, char *name) return(ch); } -static struct pattern *findmatch(char *file, int trydefault) +static struct pattern *findmatch(char *file, int trydefault, int dir) { - int i, c; + int i, o, c; char *bn; struct config **cfs; struct pattern *pat; @@ -347,12 +376,24 @@ static struct pattern *findmatch(char *file, int trydefault) cfs = getconfigs(file); for(c = 0; cfs[c] != NULL; c++) { for(pat = cfs[c]->patterns; pat != NULL; pat = pat->next) { + if(!dir && (pat->type == PT_DIR)) + continue; + if(dir && (pat->type != PT_DIR)) + continue; for(i = 0; (rule = pat->rules[i]) != NULL; i++) { if(rule->type == PAT_BASENAME) { - if(fnmatch(rule->pattern, bn, 0)) + for(o = 0; rule->patterns[o] != NULL; o++) { + if(!fnmatch(rule->patterns[o], bn, 0)) + break; + } + if(rule->patterns[o] == NULL) break; } else if(rule->type == PAT_PATHNAME) { - if(fnmatch(rule->pattern, file, FNM_PATHNAME)) + for(o = 0; rule->patterns[o] != NULL; o++) { + if(!fnmatch(rule->patterns[o], file, FNM_PATHNAME)) + break; + } + if(rule->patterns[o] == NULL) break; } else if(rule->type == PAT_ALL) { } else if(rule->type == PAT_DEFAULT) { @@ -364,19 +405,16 @@ static struct pattern *findmatch(char *file, int trydefault) return(pat); } } + if(!trydefault) + return(findmatch(file, 1, dir)); return(NULL); } -static void handlefile(struct hthead *req, int fd, char *path) +static void handle(struct hthead *req, int fd, char *path, struct pattern *pat) { - struct pattern *pat; struct child *ch; headappheader(req, "X-Ash-File", path); - if(((pat = findmatch(path, 0)) == NULL) && ((pat = findmatch(path, 1)) == NULL)) { - simpleerror(fd, 404, "Not Found", "The requested URL has no corresponding resource."); - return; - } if(pat->fchild) { stdforkserve(pat->fchild, req, fd); } else { @@ -390,10 +428,75 @@ static void handlefile(struct hthead *req, int fd, char *path) } } +static void handlefile(struct hthead *req, int fd, char *path) +{ + struct pattern *pat; + + if((pat = findmatch(path, 0, 0)) == NULL) { + simpleerror(fd, 404, "Not Found", "The requested URL has no corresponding resource."); + return; + } + handle(req, fd, path, pat); +} + static void handledir(struct hthead *req, int fd, char *path) { - /* XXX: Todo */ - simpleerror(fd, 403, "Not Authorized", "Will not send directory listings or indices yet."); + struct config **cfs; + int i, o; + struct stat sb; + char *inm, *ipath, *p; + DIR *dir; + struct dirent *dent; + struct pattern *pat; + + path = sprintf2("%s/", path); + cfs = getconfigs(path); + for(i = 0; cfs[i] != NULL; i++) { + if(cfs[i]->index != NULL) { + for(o = 0; cfs[i]->index[o] != NULL; o++) { + inm = cfs[i]->index[o]; + ipath = sprintf2("%s/%s", path, inm); + if(!stat(ipath, &sb) && S_ISREG(sb.st_mode)) { + handlefile(req, fd, ipath); + free(ipath); + goto out; + } + free(ipath); + + ipath = NULL; + if(!strchr(inm, '.') && ((dir = opendir(path)) != NULL)) { + while((dent = readdir(dir)) != NULL) { + if((p = strchr(dent->d_name, '.')) == NULL) + continue; + if(strncmp(dent->d_name, inm, strlen(inm))) + continue; + ipath = sprintf2("%s/%s", path, dent->d_name); + if(stat(ipath, &sb) || !S_ISREG(sb.st_mode)) { + free(ipath); + ipath = NULL; + continue; + } + break; + } + closedir(dir); + } + if(ipath != NULL) { + handlefile(req, fd, ipath); + free(ipath); + goto out; + } + } + break; + } + } + if((pat = findmatch(path, 0, 1)) != NULL) { + handle(req, fd, path, pat); + goto out; + } + simpleerror(fd, 403, "Not Authorized", "Will not send listings for this directory."); + +out: + free(path); } static int checkdir(struct hthead *req, int fd, char *path) @@ -417,6 +520,12 @@ static void serve(struct hthead *req, int fd) } else { *(p2++) = 0; } + if((tmp = unquoteurl(p)) == NULL) { + simpleerror(fd, 400, "Bad Request", "The requested URL contains an invalid escape sequence."); + goto fail; + } + strcpy(p, tmp); + free(tmp); if(!*p) { if(p2 == NULL) { @@ -531,7 +640,7 @@ int main(int argc, char **argv) { int c; int nodef; - char *gcf, *lcf; + char *gcf, *lcf, *clcf; struct hthead *req; int fd; @@ -564,8 +673,18 @@ int main(int argc, char **argv) } } if(lcf != NULL) { - if((lconfig = readconfig(lcf)) == NULL) - exit(1); + if(strchr(lcf, '/') == NULL) { + if((clcf = findstdconf(sprintf3("ashd/%s", lcf))) == NULL) { + flog(LOG_ERR, "could not find requested configuration `%s'", lcf); + exit(1); + } + if((lconfig = readconfig(clcf)) == NULL) + exit(1); + free(clcf); + } else { + if((lconfig = readconfig(lcf)) == NULL) + exit(1); + } } if(chdir(argv[optind])) { flog(LOG_ERR, "could not change directory to %s: %s", argv[optind], strerror(errno));