📄 mod_autoindex.c
字号:
new->icon_list = ap_make_array(p, 4, sizeof(struct item)); new->alt_list = ap_make_array(p, 4, sizeof(struct item)); new->desc_list = ap_make_array(p, 4, sizeof(struct item)); new->ign_list = ap_make_array(p, 4, sizeof(struct item)); new->hdr_list = ap_make_array(p, 4, sizeof(struct item)); new->rdme_list = ap_make_array(p, 4, sizeof(struct item)); new->opts = 0; new->incremented_opts = 0; new->decremented_opts = 0; return (void *) new;}static void *merge_autoindex_configs(pool *p, void *basev, void *addv){ autoindex_config_rec *new; autoindex_config_rec *base = (autoindex_config_rec *) basev; autoindex_config_rec *add = (autoindex_config_rec *) addv; new = (autoindex_config_rec *) ap_pcalloc(p, sizeof(autoindex_config_rec)); new->default_icon = add->default_icon ? add->default_icon : base->default_icon; new->icon_height = add->icon_height ? add->icon_height : base->icon_height; new->icon_width = add->icon_width ? add->icon_width : base->icon_width; new->alt_list = ap_append_arrays(p, add->alt_list, base->alt_list); new->ign_list = ap_append_arrays(p, add->ign_list, base->ign_list); new->hdr_list = ap_append_arrays(p, add->hdr_list, base->hdr_list); new->desc_list = ap_append_arrays(p, add->desc_list, base->desc_list); new->icon_list = ap_append_arrays(p, add->icon_list, base->icon_list); new->rdme_list = ap_append_arrays(p, add->rdme_list, base->rdme_list); if (add->opts & NO_OPTIONS) { /* * If the current directory says 'no options' then we also * clear any incremental mods from being inheritable further down. */ new->opts = NO_OPTIONS; new->incremented_opts = 0; new->decremented_opts = 0; } else { /* * If there were any non-incremental options selected for * this directory, they dominate and we don't inherit *anything.* * Contrariwise, we *do* inherit if the only settings here are * incremental ones. */ if (add->opts == 0) { new->incremented_opts = (base->incremented_opts | add->incremented_opts) & ~add->decremented_opts; new->decremented_opts = (base->decremented_opts | add->decremented_opts); /* * We may have incremental settings, so make sure we don't * inadvertently inherit an IndexOptions None from above. */ new->opts = (base->opts & ~NO_OPTIONS); } else { /* * There are local non-incremental settings, which clear * all inheritance from above. They *are* the new base settings. */ new->opts = add->opts;; } /* * We're guaranteed that there'll be no overlap between * the add-options and the remove-options. */ new->opts |= new->incremented_opts; new->opts &= ~new->decremented_opts; } new->name_width = add->name_width; new->name_adjust = add->name_adjust; return new;}/**************************************************************** * * Looking things up in config entries... *//* Structure used to hold entries when we're actually building an index */struct ent { char *name; char *icon; char *alt; char *desc; off_t size; time_t lm; struct ent *next; int ascending; char key;};static char *find_item(request_rec *r, array_header *list, int path_only){ const char *content_type = r->content_type; const char *content_encoding = r->content_encoding; char *path = r->filename; struct item *items = (struct item *) list->elts; int i; for (i = 0; i < list->nelts; ++i) { struct item *p = &items[i]; /* Special cased for ^^DIRECTORY^^ and ^^BLANKICON^^ */ if ((path[0] == '^') || (!ap_strcmp_match(path, p->apply_path))) { if (!*(p->apply_to)) { return p->data; } else if (p->type == BY_PATH || path[0] == '^') { if (!ap_strcmp_match(path, p->apply_to)) { return p->data; } } else if (!path_only) { if (!content_encoding) { if (p->type == BY_TYPE) { if (content_type && !ap_strcasecmp_match(content_type, p->apply_to)) { return p->data; } } } else { if (p->type == BY_ENCODING) { if (!ap_strcasecmp_match(content_encoding, p->apply_to)) { return p->data; } } } } } } return NULL;}#define find_icon(d,p,t) find_item(p,d->icon_list,t)#define find_alt(d,p,t) find_item(p,d->alt_list,t)#define find_desc(d,p) find_item(p,d->desc_list,0)#define find_header(d,p) find_item(p,d->hdr_list,0)#define find_readme(d,p) find_item(p,d->rdme_list,0)static char *find_default_icon(autoindex_config_rec *d, char *bogus_name){ request_rec r; /* Bleah. I tried to clean up find_item, and it lead to this bit * of ugliness. Note that the fields initialized are precisely * those that find_item looks at... */ r.filename = bogus_name; r.content_type = r.content_encoding = NULL; return find_item(&r, d->icon_list, 1);}static int ignore_entry(autoindex_config_rec *d, char *path){ array_header *list = d->ign_list; struct item *items = (struct item *) list->elts; char *tt; int i; if ((tt = strrchr(path, '/')) == NULL) { tt = path; } else { tt++; } for (i = 0; i < list->nelts; ++i) { struct item *p = &items[i]; char *ap; if ((ap = strrchr(p->apply_to, '/')) == NULL) { ap = p->apply_to; } else { ap++; }#ifndef CASE_BLIND_FILESYSTEM if (!ap_strcmp_match(path, p->apply_path) && !ap_strcmp_match(tt, ap)) { return 1; }#else /* !CASE_BLIND_FILESYSTEM */ /* * On some platforms, the match must be case-blind. This is really * a factor of the filesystem involved, but we can't detect that * reliably - so we have to granularise at the OS level. */ if (!ap_strcasecmp_match(path, p->apply_path) && !ap_strcasecmp_match(tt, ap)) { return 1; }#endif /* !CASE_BLIND_FILESYSTEM */ } return 0;}/***************************************************************** * * Actually generating output *//* * Look for the specified file, and pump it into the response stream if we * find it. */static int insert_readme(char *name, char *readme_fname, char *title, int hrule, int whichend, request_rec *r){ char *fn; FILE *f; struct stat finfo; int plaintext = 0; request_rec *rr; autoindex_config_rec *cfg; int autoindex_opts; cfg = (autoindex_config_rec *) ap_get_module_config(r->per_dir_config, &autoindex_module); autoindex_opts = cfg->opts; /* XXX: this is a load of crap, it needs to do a full sub_req_lookup_uri */ fn = ap_make_full_path(r->pool, name, readme_fname); fn = ap_pstrcat(r->pool, fn, ".html", NULL); if (stat(fn, &finfo) == -1) { /* A brief fake multiviews search for README.html */ fn[strlen(fn) - 5] = '\0'; if (stat(fn, &finfo) == -1) { return 0; } plaintext = 1; if (hrule) { ap_rputs("<HR>\n", r); } } else if (hrule) { ap_rputs("<HR>\n", r); } /* XXX: when the above is rewritten properly, this necessary security * check will be redundant. -djg */ rr = ap_sub_req_lookup_file(fn, r); if (rr->status != HTTP_OK) { ap_destroy_sub_req(rr); return 0; } ap_destroy_sub_req(rr); if (!(f = ap_pfopen(r->pool, fn, "r"))) { return 0; } if ((whichend == FRONT_MATTER) && (!(autoindex_opts & SUPPRESS_PREAMBLE))) { emit_preamble(r, title); } if (!plaintext) { ap_send_fd(f, r); } else { char buf[IOBUFSIZE + 1]; int i, n, c, ch; ap_rputs("<PRE>\n", r); while (!feof(f)) { do { n = fread(buf, sizeof(char), IOBUFSIZE, f); } while (n == -1 && ferror(f) && errno == EINTR); if (n == -1 || n == 0) { break; } buf[n] = '\0'; c = 0; while (c < n) { for (i = c; i < n; i++) { if (buf[i] == '<' || buf[i] == '>' || buf[i] == '&') { break; } } ch = buf[i]; buf[i] = '\0'; ap_rputs(&buf[c], r); if (ch == '<') { ap_rputs("<", r); } else if (ch == '>') { ap_rputs(">", r); } else if (ch == '&') { ap_rputs("&", r); } c = i + 1; } } } ap_pfclose(r->pool, f); if (plaintext) { ap_rputs("</PRE>\n", r); } return 1;}static char *find_title(request_rec *r){ char titlebuf[MAX_STRING_LEN], *find = "<TITLE>"; FILE *thefile = NULL; int x, y, n, p; if (r->status != HTTP_OK) { return NULL; } if (r->content_type && (!strcmp(r->content_type, "text/html") || !strcmp(r->content_type, INCLUDES_MAGIC_TYPE)) && !r->content_encoding) { if (!(thefile = ap_pfopen(r->pool, r->filename, "r"))) { return NULL; } n = fread(titlebuf, sizeof(char), MAX_STRING_LEN - 1, thefile); if (n <= 0) { ap_pfclose(r->pool, thefile); return NULL; } titlebuf[n] = '\0'; for (x = 0, p = 0; titlebuf[x]; x++) { if (ap_toupper(titlebuf[x]) == find[p]) { if (!find[++p]) { if ((p = ap_ind(&titlebuf[++x], '<')) != -1) { titlebuf[x + p] = '\0'; } /* Scan for line breaks for Tanmoy's secretary */ for (y = x; titlebuf[y]; y++) { if ((titlebuf[y] == CR) || (titlebuf[y] == LF)) { if (y == x) { x++; } else { titlebuf[y] = ' '; } } } ap_pfclose(r->pool, thefile); return ap_pstrdup(r->pool, &titlebuf[x]); } } else { p = 0; } } ap_pfclose(r->pool, thefile); } return NULL;}static struct ent *make_autoindex_entry(char *name, int autoindex_opts, autoindex_config_rec *d, request_rec *r, char keyid, char direction){ struct ent *p; if ((name[0] == '.') && (!name[1])) { return (NULL); } if (ignore_entry(d, ap_make_full_path(r->pool, r->filename, name))) { return (NULL); } p = (struct ent *) ap_pcalloc(r->pool, sizeof(struct ent)); p->name = ap_pstrdup(r->pool, name); p->size = -1; p->icon = NULL; p->alt = NULL; p->desc = NULL; p->lm = -1; p->key = ap_toupper(keyid); p->ascending = (ap_toupper(direction) == D_ASCENDING); if (autoindex_opts & FANCY_INDEXING) { request_rec *rr = ap_sub_req_lookup_file(name, r); if (rr->finfo.st_mode != 0) { p->lm = rr->finfo.st_mtime; if (S_ISDIR(rr->finfo.st_mode)) { if (!(p->icon = find_icon(d, rr, 1))) { p->icon = find_default_icon(d, "^^DIRECTORY^^"); } if (!(p->alt = find_alt(d, rr, 1))) { p->alt = "DIR"; } p->size = -1; p->name = ap_pstrcat(r->pool, name, "/", NULL); } else { p->icon = find_icon(d, rr, 0); p->alt = find_alt(d, rr, 0); p->size = rr->finfo.st_size; } } p->desc = find_desc(d, rr); if ((!p->desc) && (autoindex_opts & SCAN_HTML_TITLES)) { p->desc = ap_pstrdup(r->pool, find_title(rr)); } ap_destroy_sub_req(rr); } /* * We don't need to take any special action for the file size key. If * we did, it would go here. */ if (keyid == K_LAST_MOD) { if (p->lm < 0) { p->lm = 0; } } return (p);}static char *terminate_description(autoindex_config_rec *d, char *desc, int autoindex_opts){ int maxsize = 23; register int x; if (autoindex_opts & SUPPRESS_LAST_MOD) { maxsize += 19; } if (autoindex_opts & SUPPRESS_SIZE) { maxsize += 7; } for (x = 0; desc[x] && (maxsize > 0 || desc[x]=='<'); x++) { if (desc[x] == '<') { while (desc[x] != '>') { if (!desc[x]) { maxsize = 0; break; } ++x; } } else if (desc[x] == '&') { /* entities like ä count as one character */ --maxsize; for ( ; desc[x] != ';'; ++x) { if (desc[x] == '\0') { maxsize = 0; break; } } } else { --maxsize; } } if (!maxsize && desc[x] != '\0') { desc[x - 1] = '>'; /* Grump. */ desc[x] = '\0'; /* Double Grump! */ } return desc;}/* * Emit the anchor for the specified field. If a field is the key for the * current request, the link changes its meaning to reverse the order when * selected again. Non-active fields always start in ascending order. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -