mod_autoindex.c revision 26a4456dd6f1a5d7d7fff766551461a578687c4a
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2000-2004 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
*
* Portions of this software are based upon public domain software
* originally written at the National Center for Supercomputing Applications,
* University of Illinois, Urbana-Champaign.
*/
/*
* mod_autoindex.c: Handles the on-the-fly html index generation
*
* Rob McCool
* 3/23/93
*
* Adapted to Apache by rst.
*
* Version sort added by Martin Pool <mbp@humbug.org.au>.
*/
#include "apr_strings.h"
#include "apr_fnmatch.h"
#include "apr_strings.h"
#include "apr_lib.h"
#define APR_WANT_STRFUNC
#include "apr_want.h"
#include "ap_config.h"
#include "httpd.h"
#include "http_config.h"
#include "http_core.h"
#include "http_request.h"
#include "http_protocol.h"
#include "http_log.h"
#include "http_main.h"
#include "util_script.h"
#include "mod_core.h"
/****************************************************************
*
* Handling configuration directives...
*/
#define K_NOADJUST 0
#define K_ADJUST 1
#define K_UNSET 2
/*
* Define keys for sorting.
*/
#define D_ASCENDING 'A'
#define D_DESCENDING 'D'
/*
* These are the dimensions of the default icons supplied with Apache.
*/
#define DEFAULT_ICON_WIDTH 20
#define DEFAULT_ICON_HEIGHT 22
/*
* Other default dimensions.
*/
#define DEFAULT_NAME_WIDTH 23
#define DEFAULT_DESC_WIDTH 23
struct item {
char *type;
char *apply_to;
char *apply_path;
char *data;
};
typedef struct ai_desc_t {
char *pattern;
char *description;
int full_path;
int wildcards;
} ai_desc_t;
typedef struct autoindex_config_struct {
char *default_icon;
char *style_sheet;
int name_width;
int name_adjust;
int desc_width;
int desc_adjust;
int icon_width;
int icon_height;
char default_keyid;
char default_direction;
#define BY_ENCODING &c_by_encoding
/*
* This routine puts the standard HTML header at the top of the index page.
* We include the DOCTYPE because we may be using features therefrom (i.e.,
* HEIGHT and WIDTH attributes on the icons if we're FancyIndexing).
*/
{
"<html>\n <head>\n <title>Index of ", title,
"</title>\n", NULL);
if (d->style_sheet != NULL) {
}
}
{
if (!to) {
to = "";
}
if (!path) {
path = "";
}
}
else if (to) {
}
else {
}
}
const char *to)
{
to = "^^DIRECTORY^^";
}
}
}
return NULL;
}
const char *to)
{
if (icon[0] == '(') {
char *alt;
return "missing closing paren";
}
}
to = "^^DIRECTORY^^";
}
}
}
return NULL;
}
/*
* Add description text for a filename pattern. If the pattern has
* wildcards already (or we need to add them), add leading and
* trailing wildcards to it to ensure substring processing. If the
* pattern contains a '/' anywhere, force wildcard matching mode,
* the matching routine simplifies to just the actual filename
* whenever it can. This allows definitions in parent directories
* to be made for files in subordinate ones using relative paths.
*/
/*
* Absent a strcasestr() function, we have to force wildcards on
* systems for which "AAA" and "aaa" mean the same file.
*/
#ifdef CASE_BLIND_FILESYSTEM
#define WILDCARDS_REQUIRED 1
#else
#define WILDCARDS_REQUIRED 0
#endif
const char *to)
{
char *prefix = "";
|| desc_entry->full_path
|| apr_fnmatch_test(to));
if (desc_entry->wildcards) {
}
else {
}
return NULL;
}
{
return NULL;
}
{
name);
return NULL;
}
{
name);
return NULL;
}
{
char *w;
char action;
while (optstr[0]) {
int option = 0;
if ((*w == '+') || (*w == '-')) {
action = *(w++);
}
else {
action = '\0';
}
if (!strcasecmp(w, "FancyIndexing")) {
}
else if (!strcasecmp(w, "FoldersFirst")) {
}
else if (!strcasecmp(w, "HTMLTable")) {
}
else if (!strcasecmp(w, "IconsAreLinks")) {
}
else if (!strcasecmp(w, "IgnoreCase")) {
}
else if (!strcasecmp(w, "IgnoreClient")) {
}
else if (!strcasecmp(w, "ScanHTMLTitles")) {
}
else if (!strcasecmp(w, "SuppressColumnSorting")) {
}
else if (!strcasecmp(w, "SuppressDescription")) {
}
else if (!strcasecmp(w, "SuppressHTMLPreamble")) {
}
else if (!strcasecmp(w, "SuppressIcon")) {
}
else if (!strcasecmp(w, "SuppressLastModified")) {
}
else if (!strcasecmp(w, "SuppressSize")) {
}
else if (!strcasecmp(w, "SuppressRules")) {
}
else if (!strcasecmp(w, "TrackModified")) {
}
else if (!strcasecmp(w, "VersionSort")) {
}
else if (!strcasecmp(w, "XHTML")) {
option = EMIT_XHTML;
}
else if (!strcasecmp(w, "None")) {
if (action != '\0') {
return "Cannot combine '+' or '-' with 'None' keyword";
}
opts = NO_OPTIONS;
opts_add = 0;
opts_remove = 0;
}
else if (!strcasecmp(w, "IconWidth")) {
if (action != '-') {
}
else {
d_cfg->icon_width = 0;
}
}
if (action == '-') {
return "Cannot combine '-' with IconWidth=n";
}
}
else if (!strcasecmp(w, "IconHeight")) {
if (action != '-') {
}
else {
d_cfg->icon_height = 0;
}
}
if (action == '-') {
return "Cannot combine '-' with IconHeight=n";
}
}
else if (!strcasecmp(w, "NameWidth")) {
if (action != '-') {
return "NameWidth with no value may only appear as "
"'-NameWidth'";
}
}
if (action == '-') {
return "Cannot combine '-' with NameWidth=n";
}
if (w[10] == '*') {
}
else {
return "NameWidth value must be greater than 5";
}
}
}
else if (!strcasecmp(w, "DescriptionWidth")) {
if (action != '-') {
return "DescriptionWidth with no value may only appear as "
"'-DescriptionWidth'";
}
}
if (action == '-') {
return "Cannot combine '-' with DescriptionWidth=n";
}
if (w[17] == '*') {
}
else {
return "DescriptionWidth value must be greater than 12";
}
}
}
else {
return "Invalid directory indexing option";
}
if (action == '\0') {
opts_add = 0;
opts_remove = 0;
}
else if (action == '+') {
opts_remove &= ~option;
}
else {
opts_remove |= option;
}
}
return "Cannot combine other IndexOptions keywords with 'None'";
}
return NULL;
}
{
}
}
else {
return "First keyword must be 'Ascending' or 'Descending'";
}
}
}
}
}
else {
return "Second keyword must be 'Name', 'Date', 'Size', or "
"'Description'";
}
return NULL;
}
#define DIR_CMD_PERMS OR_INDEXES
static const command_rec autoindex_cmds[] =
{
"an icon URL followed by one or more filenames"),
"an icon URL followed by one or more MIME types"),
"an icon URL followed by one or more content encodings"),
"alternate descriptive text followed by one or more "
"filenames"),
"alternate descriptive text followed by one or more MIME "
"types"),
"alternate descriptive text followed by one or more "
"content encodings"),
"one or more index options [+|-][]"),
"{Ascending,Descending} {Name,Size,Description,Date}"),
"one or more file extensions"),
"Descriptive text followed by one or more filenames"),
"a filename"),
"a filename"),
"The FancyIndexing directive is no longer supported. "
"Use IndexOptions FancyIndexing."),
DIR_CMD_PERMS, "an icon URL"),
DIR_CMD_PERMS, "URL to style sheet"),
{NULL}
};
{
new->icon_width = 0;
new->icon_height = 0;
new->incremented_opts = 0;
new->decremented_opts = 0;
return (void *) new;
}
{
: base->default_icon;
: base->style_sheet;
/*
* If the current directory says 'no options' then we also
* clear any incremental mods from being inheritable further down.
*/
new->incremented_opts = 0;
new->decremented_opts = 0;
}
else {
/*
* If there were any nonincremental 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.
*/
| add->incremented_opts)
& ~add->decremented_opts;
| add->decremented_opts);
/*
* We may have incremental settings, so make sure we don't
* inadvertently inherit an IndexOptions None from above.
*/
}
else {
/*
* There are local nonincremental settings, which clear
* all inheritance from above. They *are* the new base settings.
*/
}
/*
* We're guaranteed that there'll be no overlap between
* the add-options and the remove-options.
*/
}
/*
* 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.
*/
}
else {
}
/*
* Likewise for DescriptionWidth.
*/
}
else {
}
: base->default_keyid;
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;
char key;
int isdir;
};
{
const char *content_encoding = r->content_encoding;
int i;
/* Special cased for ^^DIRECTORY^^ and ^^BLANKICON^^ */
if (!*(p->apply_to)) {
return p->data;
}
return p->data;
}
}
else if (!path_only) {
if (!content_encoding) {
if (content_type
p->apply_to)) {
return p->data;
}
}
}
else {
if (p->type == BY_ENCODING) {
p->apply_to)) {
return p->data;
}
}
}
}
}
}
return NULL;
}
{
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;
}
/*
* 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 APR_FNM_CASE_BLIND
#else
#define MATCH_FLAGS 0
#endif
{
int i;
const char *filename_only;
const char *filename;
/*
* If the filename includes a path, extract just the name itself
* for the simple matches.
*/
}
else {
}
int found;
/*
* Only use the full-path filename if the pattern contains '/'s.
*/
/*
* Make the comparison using the cheapest method; only do
* wildcard checking if we must.
*/
}
else {
}
if (found) {
return tuple->description;
}
}
return NULL;
}
{
char *tt;
int i;
}
else {
tt++;
}
char *ap;
}
else {
ap++;
}
#ifndef CASE_BLIND_FILESYSTEM
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.
*/
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
* 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
*/
/*
* emit a plain text file
*/
{
int ch;
apr_size_t i, c, n;
ap_rputs("<pre>\n", r);
while (!apr_file_eof(f)) {
do {
n = sizeof(char) * AP_IOBUFSIZE;
} while (APR_STATUS_IS_EINTR(rv));
if (n == 0 || rv != APR_SUCCESS) {
/* ###: better error here? */
break;
}
buf[n] = '\0';
c = 0;
while (c < n) {
for (i = c; i < n; i++) {
break;
}
}
buf[i] = '\0';
if (ch == '<') {
ap_rputs("<", r);
}
else if (ch == '>') {
ap_rputs(">", r);
}
else if (ch == '&') {
ap_rputs("&", r);
}
c = i + 1;
}
}
ap_rputs("</pre>\n", r);
}
/*
* Handle the preamble through the H1 tag line, inclusive. Locate
* and any other content type is ignored. This means that a non-text
* document (such as HEADER.gif) might get multiviewed as the result
* instead of a text document, meaning nothing will be displayed, but
* oh well.
*/
int emit_xhtml, char *title)
{
apr_file_t *f = NULL;
int emit_amble = 1;
int emit_H1 = 1;
const char *r_accept;
const char *r_accept_enc;
/*
* If there's a header file, send a subrequest to look for it. If it's
* found and html do the subrequest, otherwise handle it
*/
}
if ((header_fname != NULL)
/*
* text/anything-else. The former is allowed to be processed for
* SSIs.
*/
ap_filter_t *f;
/* Hope everything will work... */
emit_amble = 0;
emit_H1 = 0;
if (! suppress_amble) {
}
/* This is a hack, but I can't find any better way to do this.
* The problem is that we have already created the sub-request,
* but we just inserted the OLD_WRITE filter, and the
* sub-request needs to pass its data through the OLD_WRITE
* filter, or things go horribly wrong (missing data, data in
* the wrong order, etc). To fix it, if you create a
* sub-request and then insert the OLD_WRITE filter before you
* run the request, you need to make sure that the sub-request
* data goes through the OLD_WRITE filter. Just steal this
* code. The long-term solution is to remove the ap_r*
* functions.
*/
for (f=rr->output_filters;
f->next = r->output_filters;
/*
* If there's a problem running the subrequest, display the
* preamble if we didn't do it before -- the header file
* didn't get displayed.
*/
/* It didn't work */
emit_H1 = 1;
}
}
/*
* If we can open the file, prefix it with the preamble
* regardless; since we'll be sending a <pre> block around
* the file's contents, any HTML header it had won't end up
* where it belongs.
*/
emit_amble = 0;
do_emit_plain(r, f);
apr_file_close(f);
emit_H1 = 0;
}
}
}
}
if (r_accept) {
}
else {
}
if (r_accept_enc) {
}
if (emit_amble) {
}
if (emit_H1) {
}
}
}
/*
* Handle the Readme file through the postamble, inclusive. Locate
* and any other content type is ignored. This means that a non-text
* document (such as FOOTER.gif) might get multiviewed as the result
* instead of a text document, meaning nothing will be displayed, but
* oh well.
*/
{
apr_file_t *f = NULL;
int suppress_post = 0;
int suppress_sig = 0;
/*
* If there's a readme file, send a subrequest to look for it. If it's
* found and a text file, handle it -- otherwise fall through and
* pretend there's nothing there.
*/
if ((readme_fname != NULL)
/*
* text/anything-else. The former is allowed to be processed for
* SSIs.
*/
ap_filter_t *f;
for (f=rr->output_filters;
f->next = r->output_filters;
/* worked... */
suppress_sig = 1;
}
}
/*
* If we can open the file, suppress the signature.
*/
do_emit_plain(r, f);
apr_file_close(f);
suppress_sig = 1;
}
}
}
}
if (!suppress_sig) {
}
if (!suppress_post) {
ap_rputs("</body></html>\n", r);
}
}
}
static char *find_title(request_rec *r)
{
int x, y, p;
apr_size_t n;
return NULL;
}
if ((r->content_type != NULL)
&& !r->content_encoding) {
return NULL;
}
n = sizeof(char) * (MAX_STRING_LEN - 1);
if (n <= 0) {
return NULL;
}
titlebuf[n] = '\0';
for (x = 0, p = 0; titlebuf[x]; x++) {
if (!find[++p]) {
titlebuf[x + p] = '\0';
}
/* Scan for line breaks for Tanmoy's secretary */
for (y = x; titlebuf[y]; y++) {
if (y == x) {
x++;
}
else {
titlebuf[y] = ' ';
}
}
}
}
}
else {
p = 0;
}
}
}
return NULL;
}
request_rec *r, char keyid,
char direction)
{
char *testpath;
/*
* p->name is now the true parent URI.
* testpath is a crafted lie, so that the syntax '/some/..'
* (or simply '..')be used to describe 'up' from '/some/'
* when processeing IndexIgnore, and Icon|Alt|Desc configs.
*/
/* The output has always been to the parent. Don't make ourself
* our own parent (worthless cyclical reference).
*/
return (NULL);
}
ap_getparents(p->name);
if (!*p->name) {
return (NULL);
}
/* IndexIgnore has always compared "/thispath/.." */
if (ignore_entry(d, testpath)) {
return (NULL);
}
p->size = -1;
p->lm = -1;
if (autoindex_opts & FANCY_INDEXING) {
}
p->alt = "DIR";
}
}
}
return p;
}
int autoindex_opts,
request_rec *r, char keyid,
char direction,
const char *pattern)
{
struct ent *p;
/* Dot is ignored, Parent is handled by make_parent_entry() */
return (NULL);
/*
* 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.
*/
#ifdef CASE_BLIND_FILESYSTEM
#endif
)
!= APR_SUCCESS)) {
return (NULL);
}
return (NULL);
}
return (NULL);
}
return (NULL);
}
}
else {
}
p->size = -1;
p->lm = -1;
p->isdir = 0;
if (autoindex_opts & FOLDERS_FIRST) {
p->isdir = 1;
}
/* omit the trailing slash (1.3 compat) */
}
p->alt = "DIR";
}
}
}
else {
}
}
}
/*
* 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);
}
{
int maxsize = desc_width;
register int x;
/*
* If there's no DescriptionWidth in effect, default to the old
* behaviour of adjusting the description size depending upon
* what else is being displayed. Otherwise, stick with the
* setting.
*/
if (d->desc_adjust == K_UNSET) {
if (autoindex_opts & SUPPRESS_ICON) {
maxsize += 6;
}
if (autoindex_opts & SUPPRESS_LAST_MOD) {
maxsize += 19;
}
if (autoindex_opts & SUPPRESS_SIZE) {
maxsize += 7;
}
}
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;
}
}
}
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.
*/
char curkey, char curdirection,
{
if (!nosort) {
char qvalue[9];
qvalue[0] = '?';
/* reverse? */
? D_DESCENDING : D_ASCENDING;
}
else {
}
}
autoindex_config_rec *d, request_rec *r,
{
int x;
char *tp;
int name_width;
int desc_width;
char *name_scratch;
char *pad_scratch;
char *breakrow = "";
if (name[0] == '\0') {
name = "/";
}
name_width = d->name_width;
desc_width = d->desc_width;
== FANCY_INDEXING) {
if (d->name_adjust == K_ADJUST) {
for (x = 0; x < n; x++) {
if (t > name_width) {
name_width = t;
}
}
}
if (d->desc_adjust == K_ADJUST) {
for (x = 0; x < n; x++) {
if (t > desc_width) {
desc_width = t;
}
}
}
}
}
if (autoindex_opts & TABLE_INDEXING) {
int cols = 1;
ap_rputs("<table><tr>", r);
if (!(autoindex_opts & SUPPRESS_ICON)) {
ap_rputs("<th>", r);
"\" alt=\"[ICO]\"", NULL);
if (d->icon_width) {
}
if (d->icon_height) {
}
if (autoindex_opts & EMIT_XHTML) {
ap_rputs(" /", r);
}
ap_rputs("></th>", r);
}
else {
ap_rputs(" </th>", r);
}
++cols;
}
ap_rputs("<th>", r);
if (!(autoindex_opts & SUPPRESS_LAST_MOD)) {
ap_rputs("</th><th>", r);
++cols;
}
if (!(autoindex_opts & SUPPRESS_SIZE)) {
ap_rputs("</th><th>", r);
++cols;
}
if (!(autoindex_opts & SUPPRESS_DESC)) {
ap_rputs("</th><th>", r);
++cols;
}
if (!(autoindex_opts & SUPPRESS_RULES)) {
"<tr><th colspan=\"%d\">"
"<hr%s></th></tr>\n", cols,
}
}
else if (autoindex_opts & FANCY_INDEXING) {
ap_rputs("<pre>", r);
if (!(autoindex_opts & SUPPRESS_ICON)) {
"\" alt=\"Icon \"", NULL);
if (d->icon_width) {
}
if (d->icon_height) {
}
if (autoindex_opts & EMIT_XHTML) {
ap_rputs(" /", r);
}
ap_rputs("> ", r);
}
else {
ap_rputs(" ", r);
}
}
/*
* Emit the guaranteed-at-least-one-space-between-columns byte.
*/
ap_rputs(" ", r);
if (!(autoindex_opts & SUPPRESS_LAST_MOD)) {
ap_rputs(" ", r);
}
if (!(autoindex_opts & SUPPRESS_SIZE)) {
ap_rputs(" ", r);
}
if (!(autoindex_opts & SUPPRESS_DESC)) {
}
if (!(autoindex_opts & SUPPRESS_RULES)) {
ap_rputs("<hr", r);
if (autoindex_opts & EMIT_XHTML) {
ap_rputs(" /", r);
}
ap_rputs(">", r);
}
else {
ap_rputc('\n', r);
}
}
else {
ap_rputs("<ul>", r);
}
for (x = 0; x < n; x++) {
int nwidth;
if (!x && t[0] == '/') {
t2 = "Parent Directory";
}
else {
t2 = t;
}
if (autoindex_opts & TABLE_INDEXING) {
ap_rputs("<tr>", r);
if (!(autoindex_opts & SUPPRESS_ICON)) {
ap_rputs("<td valign=\"top\">", r);
if (autoindex_opts & ICONS_ARE_LINKS) {
}
ap_rvputs(r, "<img src=\"",
: d->default_icon),
"]\"", NULL);
if (d->icon_width) {
}
if (d->icon_height) {
}
if (autoindex_opts & EMIT_XHTML) {
ap_rputs(" /", r);
}
ap_rputs(">", r);
}
else {
ap_rputs(" ", r);
}
if (autoindex_opts & ICONS_ARE_LINKS) {
ap_rputs("</a></td>", r);
}
else {
ap_rputs("</td>", r);
}
}
if (d->name_adjust == K_ADJUST) {
}
else {
if (nwidth > name_width) {
name_scratch[name_width] = 0;
t2 = name_scratch;
nwidth = name_width;
}
}
if (!(autoindex_opts & SUPPRESS_LAST_MOD)) {
char time_str[MAX_STRING_LEN];
"</td><td align=\"right\">%d-%b-%Y %H:%M ",
&ts);
}
else {
ap_rputs("</td><td> ", r);
}
}
if (!(autoindex_opts & SUPPRESS_SIZE)) {
char buf[5];
ap_rvputs(r, "</td><td align=\"right\">",
}
if (!(autoindex_opts & SUPPRESS_DESC)) {
if (d->desc_adjust == K_ADJUST) {
}
else {
ap_rvputs(r, "</td><td>",
desc_width), NULL);
}
}
}
else {
ap_rputs("</td><td> ", r);
}
ap_rputs("</td></tr>\n", r);
}
else if (autoindex_opts & FANCY_INDEXING) {
if (!(autoindex_opts & SUPPRESS_ICON)) {
if (autoindex_opts & ICONS_ARE_LINKS) {
}
ap_rvputs(r, "<img src=\"",
: d->default_icon),
"]\"", NULL);
if (d->icon_width) {
}
if (d->icon_height) {
}
if (autoindex_opts & EMIT_XHTML) {
ap_rputs(" /", r);
}
ap_rputs(">", r);
}
else {
ap_rputs(" ", r);
}
if (autoindex_opts & ICONS_ARE_LINKS) {
ap_rputs("</a> ", r);
}
else {
ap_rputc(' ', r);
}
}
if (nwidth > name_width) {
name_scratch[name_width] = 0;
t2 = name_scratch;
nwidth = name_width;
}
/*
* The blank before the storm.. er, before the next field.
*/
ap_rputs(" ", r);
if (!(autoindex_opts & SUPPRESS_LAST_MOD)) {
char time_str[MAX_STRING_LEN];
"%d-%b-%Y %H:%M ", &ts);
}
else {
/*Length="22-Feb-1998 23:42 " (see 4 lines above) */
ap_rputs(" ", r);
}
}
if (!(autoindex_opts & SUPPRESS_SIZE)) {
char buf[5];
ap_rputs(" ", r);
}
if (!(autoindex_opts & SUPPRESS_DESC)) {
desc_width), r);
}
}
ap_rputc('\n', r);
}
else {
"</a></li>\n", NULL);
}
}
if (autoindex_opts & TABLE_INDEXING) {
}
else if (autoindex_opts & FANCY_INDEXING) {
if (!(autoindex_opts & SUPPRESS_RULES)) {
ap_rputs("<hr", r);
if (autoindex_opts & EMIT_XHTML) {
ap_rputs(" /", r);
}
ap_rputs("></pre>\n", r);
}
else {
ap_rputs("</pre>\n", r);
}
}
else {
ap_rputs("</ul>\n", r);
}
}
/*
* Compare two file entries according to the sort criteria. The return
* is essentially a signum function value.
*/
{
int result = 0;
/*
* First, see if either of the entries is for the parent directory.
* If so, that *always* sorts lower than anything else.
*/
return -1;
}
return 1;
}
/*
* Now see if one's a directory and one isn't, if we're set
* isdir for FOLDERS_FIRST.
*/
}
/*
* All of our comparisons will be of the c1 entry against the c2 one,
* so assign them appropriately to take care of the ordering.
*/
}
else {
}
case K_LAST_MOD:
return 1;
}
return -1;
}
break;
case K_SIZE:
return 1;
}
return -1;
}
break;
case K_DESC:
if (c1->version_sort) {
}
else {
}
if (result) {
return result;
}
break;
}
/* names may identical when treated case-insensitively,
* so always fall back on strcmp() flavors to put entries
* in deterministic order. This means that 'ABC' and 'abc'
* will always appear in the same order, rather than
* variably between 'ABC abc' and 'abc ABC' order.
*/
if (c1->version_sort) {
if (c1->ignore_case) {
}
if (!result) {
}
}
/* The names may be identical in respects other other than
* filename case when strnatcmp is used above, so fall back
* to strcmp on conflicts so that fn1.01.zzz and fn1.1.zzz
* are also sorted in a deterministic order.
*/
}
if (!result) {
}
return result;
}
static int index_directory(request_rec *r,
{
char *title_endp;
int num_ent = 0, x;
const char *qstring;
char keyid;
char direction;
char *colargs;
char *fullpath;
"Can't open directory for index: %s", r->filename);
return HTTP_FORBIDDEN;
}
ap_set_content_type(r, "text/html;charset=utf-8");
#else
ap_set_content_type(r, "text/html");
#endif
if (autoindex_opts & TRACK_MODIFIED) {
ap_set_etag(r);
}
if (r->header_only) {
return 0;
}
/*
* If there is no specific ordering defined for this directory,
* default to ascending by filename.
*/
/*
* Figure out what sort of indexing (if any) we're supposed to use.
*
* If no QUERY_STRING was specified or client query strings have been
* explicitly disabled.
* If we are ignoring the client, suppress column sorting as well.
*/
if (autoindex_opts & IGNORE_CLIENT) {
colargs = "";
}
else {
/* C= First Sort key Column (N, M, S, D) */
|| !qstring[3])) {
}
/* O= Sort order (A, D) */
|| !qstring[3])) {
}
/* F= Output Format (0 plain, 1 fancy (pre), 2 table) */
|| !qstring[3])) {
}
& ~TABLE_INDEXING;
}
}
}
/* V= Version sort (0, 1) */
|| !qstring[3])) {
}
}
}
/* P= wildcard pattern (*.foo) */
++eos;
}
}
else {
/* ignore the pattern, if it's bad. */
}
else {
ppre = ";P=";
/* be correct */
}
}
}
else {
}
}
/* Syntax error? Ignore the remainder! */
else {
}
}
}
/* Spew HTML preamble */
*title_endp-- = '\0';
}
/*
* 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.
*/
if (p != NULL) {
head = p;
num_ent++;
}
thedir) == APR_SUCCESS) {
/* We want to explode symlinks here. */
const char *savename;
/* We *must* have FNAME. */
if (status != APR_SUCCESS) {
/* Something bad happened, skip this file. */
continue;
}
}
if (p != NULL) {
head = p;
num_ent++;
}
}
if (num_ent > 0) {
p = head;
x = 0;
while (p) {
ar[x++] = p;
p = p->next;
}
(int (*)(const void *, const void *)) dsortf);
}
return 0;
}
/* The formal handler... */
static int handle_autoindex(request_rec *r)
{
int allow_opts;
return DECLINED;
}
allow_opts = ap_allow_options(r);
if (r->method_number != M_GET) {
return DECLINED;
}
/* OK, nothing easy. Trot out the heavy artillery... */
if (allow_opts & OPT_INDEXES) {
int errstatus;
return errstatus;
}
/* 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...
*/
}
return index_directory(r, d);
}
else {
"Directory index forbidden by rule: %s", r->filename);
return HTTP_FORBIDDEN;
}
}
static void register_hooks(apr_pool_t *p)
{
}
{
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 apr_table_t */
register_hooks /* register hooks */
};