📄 mod_autoindex.c
字号:
return "DescriptionWidth value must be greater than 12"; } d_cfg->desc_width = width; d_cfg->desc_adjust = K_NOADJUST; } } else { return "Invalid directory indexing option"; } if (action == '\0') { opts |= option; opts_add = 0; opts_remove = 0; } else if (action == '+') { opts_add |= option; opts_remove &= ~option; } else { opts_remove |= option; opts_add &= ~option; } } if ((opts & NO_OPTIONS) && (opts & ~NO_OPTIONS)) { return "Cannot combine other IndexOptions keywords with 'None'"; } d_cfg->incremented_opts = opts_add; d_cfg->decremented_opts = opts_remove; d_cfg->opts = opts; return NULL;}static const char *set_default_order(cmd_parms *cmd, void *m, char *direction, char *key){ char temp[4]; autoindex_config_rec *d_cfg = (autoindex_config_rec *) m; ap_cpystrn(temp, "k=d", sizeof(temp)); if (!strcasecmp(direction, "Ascending")) { temp[2] = D_ASCENDING; } else if (!strcasecmp(direction, "Descending")) { temp[2] = D_DESCENDING; } else { return "First keyword must be 'Ascending' or 'Descending'"; } if (!strcasecmp(key, "Name")) { temp[0] = K_NAME; } else if (!strcasecmp(key, "Date")) { temp[0] = K_LAST_MOD; } else if (!strcasecmp(key, "Size")) { temp[0] = K_SIZE; } else if (!strcasecmp(key, "Description")) { temp[0] = K_DESC; } else { return "Second keyword must be 'Name', 'Date', 'Size', or " "'Description'"; } if (d_cfg->default_order == NULL) { d_cfg->default_order = ap_palloc(cmd->pool, 4); d_cfg->default_order[3] = '\0'; } ap_cpystrn(d_cfg->default_order, temp, sizeof(temp)); return NULL;}#define DIR_CMD_PERMS OR_INDEXESstatic const command_rec autoindex_cmds[] ={ {"AddIcon", add_icon, BY_PATH, DIR_CMD_PERMS, ITERATE2, "an icon URL followed by one or more filenames"}, {"AddIconByType", add_icon, BY_TYPE, DIR_CMD_PERMS, ITERATE2, "an icon URL followed by one or more MIME types"}, {"AddIconByEncoding", add_icon, BY_ENCODING, DIR_CMD_PERMS, ITERATE2, "an icon URL followed by one or more content encodings"}, {"AddAlt", add_alt, BY_PATH, DIR_CMD_PERMS, ITERATE2, "alternate descriptive text followed by one or more filenames"}, {"AddAltByType", add_alt, BY_TYPE, DIR_CMD_PERMS, ITERATE2, "alternate descriptive text followed by one or more MIME types"}, {"AddAltByEncoding", add_alt, BY_ENCODING, DIR_CMD_PERMS, ITERATE2, "alternate descriptive text followed by one or more content encodings"}, {"IndexOptions", add_opts, NULL, DIR_CMD_PERMS, RAW_ARGS, "one or more index options"}, {"IndexOrderDefault", set_default_order, NULL, DIR_CMD_PERMS, TAKE2, "{Ascending,Descending} {Name,Size,Description,Date}"}, {"IndexIgnore", add_ignore, NULL, DIR_CMD_PERMS, ITERATE, "one or more file extensions"}, {"AddDescription", add_desc, BY_PATH, DIR_CMD_PERMS, ITERATE2, "Descriptive text followed by one or more filenames"}, {"HeaderName", add_header, NULL, DIR_CMD_PERMS, TAKE1, "a filename"}, {"ReadmeName", add_readme, NULL, DIR_CMD_PERMS, TAKE1, "a filename"}, {"FancyIndexing", fancy_indexing, NULL, DIR_CMD_PERMS, FLAG, "Limited to 'on' or 'off' (superseded by IndexOptions FancyIndexing)"}, {"DefaultIcon", ap_set_string_slot, (void *) XtOffsetOf(autoindex_config_rec, default_icon), DIR_CMD_PERMS, TAKE1, "an icon URL"}, {NULL}};static void *create_autoindex_config(pool *p, char *dummy){ autoindex_config_rec *new = (autoindex_config_rec *) ap_pcalloc(p, sizeof(autoindex_config_rec)); new->icon_width = 0; new->icon_height = 0; new->name_width = DEFAULT_NAME_WIDTH; new->name_adjust = K_UNSET; new->desc_width = DEFAULT_DESC_WIDTH; new->desc_adjust = K_UNSET; 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(ai_desc_t)); 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; new->default_order = NULL; 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; } /* * Inherit the NameWidth settings if there aren't any specific to * the new location; otherwise we'll end up using the defaults set in the * config-rec creation routine. */ if (add->name_adjust == K_UNSET) { new->name_width = base->name_width; new->name_adjust = base->name_adjust; } else { new->name_width = add->name_width; new->name_adjust = add->name_adjust; } /* * Likewise for DescriptionWidth. */ if (add->desc_adjust == K_UNSET) { new->desc_width = base->desc_width; new->desc_adjust = base->desc_adjust; } else { new->desc_width = add->desc_width; new->desc_adjust = add->desc_adjust; } new->default_order = (add->default_order != NULL) ? add->default_order : base->default_order; 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; int isdir; int checkdir; int ignorecase; char key;};static char *find_item(request_rec *r, array_header *list, int path_only){ const char *content_type = ap_field_noparam(r->pool, 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_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);}/* * Look through the list of pattern/description pairs and return the first one * if any) that matches the filename in the request. If multiple patterns * match, only the first one is used; since the order in the array is the * same as the order in which directives were processed, earlier matching * directives will dominate. */#ifdef CASE_BLIND_FILESYSTEM#define MATCH_FLAGS FNM_CASE_BLIND#else#define MATCH_FLAGS 0#endifstatic char *find_desc(autoindex_config_rec *dcfg, request_rec *r){ int i; ai_desc_t *list = (ai_desc_t *) dcfg->desc_list->elts; const char *filename_full = r->filename; const char *filename_only; const char *filename; /* * If the filename includes a path, extract just the name itself * for the simple matches. */ if ((filename_only = strrchr(filename_full, '/')) == NULL) { filename_only = filename_full; } else { filename_only++; } for (i = 0; i < dcfg->desc_list->nelts; ++i) { ai_desc_t *tuple = &list[i]; int found; /* * Only use the full-path filename if the pattern contains '/'s. */ filename = (tuple->full_path) ? filename_full : filename_only; /* * Make the comparison using the cheapest method; only do * wildcard checking if we must. */ if (tuple->wildcards) { found = (ap_fnmatch(tuple->pattern, filename, MATCH_FLAGS) == 0); } else { found = (strstr(filename, tuple->pattern) != NULL); } if (found) { return tuple->description; } } return NULL;}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 *//* * Elements of the emitted document: * Preamble * Emitted unless SUPPRESS_PREAMBLE is set AND ap_run_sub_req * succeeds for the (content_type == text/html) header file. * Header file * Emitted if found (and able). * H1 tag line * Emitted if a header file is NOT emitted. * Directory stuff * Always emitted. * HR * Emitted if FANCY_INDEXING is set. * Readme file * Emitted if found (and able). * ServerSig * Emitted if ServerSignature is not Off AND a readme file * is NOT emitted. * Postamble * Emitted unless SUPPRESS_PREAMBLE is set AND ap_run_sub_req * succeeds for the (content_type == text/html) readme file. *//* * emit a plain text file */static void do_emit_plain(request_rec *r, FILE *f){ 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); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -