📄 mod_autoindex.c
字号:
static void emit_link(request_rec *r, char *anchor, char fname, char curkey, char curdirection, int nosort){ char qvalue[5]; int reverse; if (!nosort) { qvalue[0] = '?'; qvalue[1] = fname; qvalue[2] = '='; qvalue[4] = '\0'; reverse = ((curkey == fname) && (curdirection == D_ASCENDING)); qvalue[3] = reverse ? D_DESCENDING : D_ASCENDING; ap_rvputs(r, "<A HREF=\"", qvalue, "\">", anchor, "</A>", NULL); } else { ap_rputs(anchor, r); }}/* * Fit a string into a specified buffer width, marking any * truncation. The size argument is the actual buffer size, including * the \0 termination byte. The buffer will be prefilled with blanks. * If the pad argument is false, any extra spaces at the end of the * buffer are omitted. (Used when constructing anchors.) */static ap_inline char *widthify(const char *s, char *buff, int size, int pad){ int s_len; memset(buff, ' ', size); buff[size - 1] = '\0'; s_len = strlen(s); if (s_len > (size - 1)) { ap_cpystrn(buff, s, size); if (size > 1) { buff[size - 2] = '>'; } if (size > 2) { buff[size - 3] = '.'; } if (size > 3) { buff[size - 4] = '.'; } } else { ap_cpystrn(buff, s, s_len + 1); if (pad) { buff[s_len] = ' '; } } return buff;}static void output_directories(struct ent **ar, int n, autoindex_config_rec *d, request_rec *r, int autoindex_opts, char keyid, char direction){ int x; char *name = r->uri; char *tp; int static_columns = (autoindex_opts & SUPPRESS_COLSORT); pool *scratch = ap_make_sub_pool(r->pool); int name_width; char *name_scratch; if (name[0] == '\0') { name = "/"; } name_width = d->name_width; if (d->name_adjust) { for (x = 0; x < n; x++) { int t = strlen(ar[x]->name); if (t > name_width) { name_width = t; } } } ++name_width; name_scratch = ap_palloc(r->pool, name_width + 1); memset(name_scratch, ' ', name_width); name_scratch[name_width] = '\0'; if (autoindex_opts & FANCY_INDEXING) { ap_rputs("<PRE>", r); if ((tp = find_default_icon(d, "^^BLANKICON^^"))) { ap_rvputs(r, "<IMG SRC=\"", ap_escape_html(scratch, tp), "\" ALT=\" \"", NULL); if (d->icon_width && d->icon_height) { ap_rprintf ( r, " HEIGHT=\"%d\" WIDTH=\"%d\"", d->icon_height, d->icon_width ); } ap_rputs("> ", r); } emit_link(r, widthify("Name", name_scratch, (name_width > 5) ? 5 : name_width, K_NOPAD), K_NAME, keyid, direction, static_columns); if (name_width > 5) { memset(name_scratch, ' ', name_width); name_scratch[name_width] = '\0'; ap_rputs(&name_scratch[5], r); } /* * Emit the guaranteed-at-least-one-space-between-columns byte. */ ap_rputs(" ", r); if (!(autoindex_opts & SUPPRESS_LAST_MOD)) { emit_link(r, "Last modified", K_LAST_MOD, keyid, direction, static_columns); ap_rputs(" ", r); } if (!(autoindex_opts & SUPPRESS_SIZE)) { emit_link(r, "Size", K_SIZE, keyid, direction, static_columns); ap_rputs(" ", r); } if (!(autoindex_opts & SUPPRESS_DESC)) { emit_link(r, "Description", K_DESC, keyid, direction, static_columns); } ap_rputs("\n<HR>\n", r); } else { ap_rputs("<UL>", r); } for (x = 0; x < n; x++) { char *anchor, *t, *t2; char *pad; int nwidth; ap_clear_pool(scratch); if (is_parent(ar[x]->name)) { t = ap_make_full_path(scratch, name, "../"); ap_getparents(t); if (t[0] == '\0') { t = "/"; } /* 1234567890123456 */ t2 = "Parent Directory"; pad = name_scratch + 16; anchor = ap_escape_html(scratch, ap_os_escape_path(scratch, t, 0)); } else { t = ar[x]->name; pad = name_scratch + strlen(t); t2 = ap_escape_html(scratch, t); anchor = ap_escape_html(scratch, ap_os_escape_path(scratch, t, 0)); } if (autoindex_opts & FANCY_INDEXING) { if (autoindex_opts & ICONS_ARE_LINKS) { ap_rvputs(r, "<A HREF=\"", anchor, "\">", NULL); } if ((ar[x]->icon) || d->default_icon) { ap_rvputs(r, "<IMG SRC=\"", ap_escape_html(scratch, ar[x]->icon ? ar[x]->icon : d->default_icon), "\" ALT=\"[", (ar[x]->alt ? ar[x]->alt : " "), "]\"", NULL); if (d->icon_width && d->icon_height) { ap_rprintf(r, " HEIGHT=\"%d\" WIDTH=\"%d\"", d->icon_height, d->icon_width); } ap_rputs(">", r); } if (autoindex_opts & ICONS_ARE_LINKS) { ap_rputs("</A>", r); } ap_rvputs(r, " <A HREF=\"", anchor, "\">", widthify(t2, name_scratch, name_width, K_NOPAD), "</A>", NULL); /* * We know that widthify() prefilled the buffer with spaces * before doing its thing, so use them. */ nwidth = strlen(t2); if (nwidth < (name_width - 1)) { name_scratch[nwidth] = ' '; ap_rputs(&name_scratch[nwidth], r); } /* * The blank before the storm.. er, before the next field. */ ap_rputs(" ", r); if (!(autoindex_opts & SUPPRESS_LAST_MOD)) { if (ar[x]->lm != -1) { char time_str[MAX_STRING_LEN]; struct tm *ts = localtime(&ar[x]->lm); strftime(time_str, MAX_STRING_LEN, "%d-%b-%Y %H:%M ", ts); ap_rputs(time_str, r); } else { ap_rputs(" ", r); } } if (!(autoindex_opts & SUPPRESS_SIZE)) { ap_send_size(ar[x]->size, r); ap_rputs(" ", r); } if (!(autoindex_opts & SUPPRESS_DESC)) { if (ar[x]->desc) { ap_rputs(terminate_description(d, ar[x]->desc, autoindex_opts), r); } } } else { ap_rvputs(r, "<LI><A HREF=\"", anchor, "\"> ", t2, "</A>", pad, NULL); } ap_rputc('\n', r); } if (autoindex_opts & FANCY_INDEXING) { ap_rputs("</PRE>", r); } else { ap_rputs("</UL>", r); }}/* * Compare two file entries according to the sort criteria. The return * is essentially a signum function value. */static int dsortf(struct ent **e1, struct ent **e2){ struct ent *c1; struct ent *c2; int result = 0; /* * First, see if either of the entries is for the parent directory. * If so, that *always* sorts lower than anything else. */ if (is_parent((*e1)->name)) { return -1; } if (is_parent((*e2)->name)) { return 1; } /* * All of our comparisons will be of the c1 entry against the c2 one, * so assign them appropriately to take care of the ordering. */ if ((*e1)->ascending) { c1 = *e1; c2 = *e2; } else { c1 = *e2; c2 = *e1; } switch (c1->key) { case K_LAST_MOD: if (c1->lm > c2->lm) { return 1; } else if (c1->lm < c2->lm) { return -1; } break; case K_SIZE: if (c1->size > c2->size) { return 1; } else if (c1->size < c2->size) { return -1; } break; case K_DESC: result = strcmp(c1->desc ? c1->desc : "", c2->desc ? c2->desc : ""); if (result) { return result; } break; } return strcmp(c1->name, c2->name);}static int index_directory(request_rec *r, autoindex_config_rec *autoindex_conf){ char *title_name = ap_escape_html(r->pool, r->uri); char *title_endp; char *name = r->filename; DIR *d; struct DIR_TYPE *dstruct; int num_ent = 0, x; struct ent *head, *p; struct ent **ar = NULL; char *tmp; const char *qstring; int autoindex_opts = autoindex_conf->opts; char keyid; char direction; if (!(d = ap_popendir(r->pool, name))) { ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "Can't open directory for index: %s", r->filename); return HTTP_FORBIDDEN; } r->content_type = "text/html"; ap_send_http_header(r); if (r->header_only) { ap_pclosedir(r->pool, d); return 0; } ap_hard_timeout("send directory", r); /* Spew HTML preamble */ title_endp = title_name + strlen(title_name) - 1; while (title_endp > title_name && *title_endp == '/') { *title_endp-- = '\0'; } if ((!(tmp = find_header(autoindex_conf, r))) || (!(insert_readme(name, tmp, title_name, NO_HRULE, FRONT_MATTER, r))) ) { emit_preamble(r, title_name); ap_rvputs(r, "<H1>Index of ", title_name, "</H1>\n", NULL); } /* * Figure out what sort of indexing (if any) we're supposed to use. */ if (autoindex_opts & SUPPRESS_COLSORT) { keyid = K_NAME; direction = D_ASCENDING; } else { qstring = r->args; /* * If no QUERY_STRING was specified, we use the default: ascending * by name. */ if ((qstring == NULL) || (*qstring == '\0')) { keyid = K_NAME; direction = D_ASCENDING; } else { keyid = *qstring; ap_getword(r->pool, &qstring, '='); if (qstring != '\0') { direction = *qstring; } else { direction = D_ASCENDING; } } } /* * Since we don't know how many dir. entries there are, put them into a * linked list and then arrayificate them so qsort can use them. */ head = NULL; while ((dstruct = readdir(d))) { p = make_autoindex_entry(dstruct->d_name, autoindex_opts, autoindex_conf, r, keyid, direction); if (p != NULL) { p->next = head; head = p; num_ent++; } } if (num_ent > 0) { ar = (struct ent **) ap_palloc(r->pool, num_ent * sizeof(struct ent *)); p = head; x = 0; while (p) { ar[x++] = p; p = p->next; } qsort((void *) ar, num_ent, sizeof(struct ent *), (int (*)(const void *, const void *)) dsortf); } output_directories(ar, num_ent, autoindex_conf, r, autoindex_opts, keyid, direction); ap_pclosedir(r->pool, d); if ((tmp = find_readme(autoindex_conf, r))) { if (!insert_readme(name, tmp, "", ((autoindex_opts & FANCY_INDEXING) ? HRULE : NO_HRULE), END_MATTER, r)) { ap_rputs(ap_psignature("<HR>\n", r), r); } } ap_rputs("</BODY></HTML>\n", r); ap_kill_timeout(r); return 0;}/* The formal handler... */static int handle_autoindex(request_rec *r){ autoindex_config_rec *d; int allow_opts = ap_allow_options(r); d = (autoindex_config_rec *) ap_get_module_config(r->per_dir_config, &autoindex_module); r->allowed |= (1 << M_GET); if (r->method_number != M_GET) { return DECLINED; } /* OK, nothing easy. Trot out the heavy artillery... */ if (allow_opts & OPT_INDEXES) { /* KLUDGE --- make the sub_req lookups happen in the right directory. * Fixing this in the sub_req_lookup functions themselves is difficult, * and would probably break virtual includes... */ if (r->filename[strlen(r->filename) - 1] != '/') { r->filename = ap_pstrcat(r->pool, r->filename, "/", NULL); } return index_directory(r, d); } else { ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r, "Directory index forbidden by rule: %s", r->filename); return HTTP_FORBIDDEN; }}static const handler_rec autoindex_handlers[] ={ {DIR_MAGIC_TYPE, handle_autoindex}, {NULL}};module MODULE_VAR_EXPORT autoindex_module ={ STANDARD_MODULE_STUFF, NULL, /* initializer */ create_autoindex_config, /* dir config creater */ merge_autoindex_configs, /* dir merger --- default is to override */ NULL, /* server config */ NULL, /* merge server config */ autoindex_cmds, /* command table */ autoindex_handlers, /* handlers */ NULL, /* filename translation */ NULL, /* check_user_id */ NULL, /* check auth */ NULL, /* check access */ NULL, /* type_checker */ NULL, /* fixups */ NULL, /* logger */ NULL, /* header parser */ NULL, /* child_init */ NULL, /* child_exit */ NULL /* post read-request */};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -