dir-index-bozo.c revision 1.24
1/* $NetBSD: dir-index-bozo.c,v 1.24 2015/12/28 07:37:59 mrg Exp $ */ 2 3/* $eterna: dir-index-bozo.c,v 1.20 2011/11/18 09:21:15 mrg Exp $ */ 4 5/* 6 * Copyright (c) 1997-2014 Matthew R. Green 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer and 16 * dedication in the documentation and/or other materials provided 17 * with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 */ 32 33/* this code implements directory index generation for bozohttpd */ 34 35#ifndef NO_DIRINDEX_SUPPORT 36 37#include <sys/param.h> 38 39#include <dirent.h> 40#include <errno.h> 41#include <string.h> 42#include <stdlib.h> 43#include <time.h> 44#include <assert.h> 45 46#include "bozohttpd.h" 47 48static void 49directory_hr(bozohttpd_t *httpd) 50{ 51 52 bozo_printf(httpd, 53 "<hr noshade align=\"left\" width=\"80%%\">\r\n\r\n"); 54} 55 56/* 57 * output a directory index. return 1 if it actually did something.. 58 */ 59int 60bozo_dir_index(bozo_httpreq_t *request, const char *dirpath, int isindex) 61{ 62 bozohttpd_t *httpd = request->hr_httpd; 63 struct stat sb; 64 struct dirent **de, **deo; 65 struct tm *tm; 66 DIR *dp; 67 char buf[MAXPATHLEN]; 68 char spacebuf[48]; 69 char *file = NULL, *printname = NULL; 70 int l, k, j, i; 71 72 if (!isindex || !httpd->dir_indexing) 73 return 0; 74 75 if (strlen(dirpath) <= strlen(httpd->index_html)) 76 dirpath = "."; 77 else { 78 file = bozostrdup(httpd, request, dirpath); 79 80 file[strlen(file) - strlen(httpd->index_html)] = '\0'; 81 dirpath = file; 82 } 83 debug((httpd, DEBUG_FAT, "bozo_dir_index: dirpath ``%s''", dirpath)); 84 if (stat(dirpath, &sb) < 0 || 85 (dp = opendir(dirpath)) == NULL) { 86 if (errno == EPERM) 87 (void)bozo_http_error(httpd, 403, request, 88 "no permission to open directory"); 89 else if (errno == ENOENT) 90 (void)bozo_http_error(httpd, 404, request, "no file"); 91 else 92 (void)bozo_http_error(httpd, 500, request, 93 "open directory"); 94 goto done; 95 /* NOTREACHED */ 96 } 97 98 bozo_printf(httpd, "%s 200 OK\r\n", request->hr_proto); 99 100 if (request->hr_proto != httpd->consts.http_09) { 101 bozo_print_header(request, NULL, "text/html", ""); 102 bozo_printf(httpd, "\r\n"); 103 } 104 bozo_flush(httpd, stdout); 105 106 if (request->hr_method == HTTP_HEAD) { 107 closedir(dp); 108 goto done; 109 } 110 111#ifndef NO_USER_SUPPORT 112 if (request->hr_user) { 113 if (asprintf(&printname, "~%s/%s", request->hr_user, 114 request->hr_file) < 0) 115 bozoerr(httpd, 1, "asprintf"); 116 } else 117 printname = bozostrdup(httpd, request, request->hr_file); 118#else 119 printname = bozostrdup(httpd, request, request->hr_file); 120#endif /* !NO_USER_SUPPORT */ 121 122 bozo_printf(httpd, 123 "<html><head><title>Index of %s</title></head>\r\n", 124 printname); 125 bozo_printf(httpd, "<body><h1>Index of %s</h1>\r\n", 126 printname); 127 bozo_printf(httpd, "<pre>\r\n"); 128#define NAMELEN 40 129#define LMODLEN 19 130 bozo_printf(httpd, "Name " 131 "Last modified " 132 "Size\n"); 133 bozo_printf(httpd, "</pre>"); 134 directory_hr(httpd); 135 bozo_printf(httpd, "<pre>"); 136 137 for (j = k = scandir(dirpath, &de, NULL, alphasort), deo = de; 138 j--; de++) { 139 int nostat = 0; 140 char *name = (*de)->d_name; 141 char *urlname, *htmlname; 142 143 if (strcmp(name, ".") == 0 || 144 (strcmp(name, "..") != 0 && 145 httpd->hide_dots && name[0] == '.')) 146 continue; 147 148 snprintf(buf, sizeof buf, "%s/%s", dirpath, name); 149 if (stat(buf, &sb)) 150 nostat = 1; 151 152 l = 0; 153 154 urlname = bozo_escape_rfc3986(httpd, name, 0); 155 htmlname = bozo_escape_html(httpd, name); 156 if (htmlname == NULL) 157 htmlname = name; 158 if (strcmp(name, "..") == 0) { 159 bozo_printf(httpd, "<a href=\"../\">"); 160 l += bozo_printf(httpd, "Parent Directory"); 161 } else if (S_ISDIR(sb.st_mode)) { 162 bozo_printf(httpd, "<a href=\"%s/\">", urlname); 163 l += bozo_printf(httpd, "%s/", htmlname); 164 } else if (strchr(name, ':') != NULL) { 165 /* RFC 3986 4.2 */ 166 bozo_printf(httpd, "<a href=\"./%s\">", urlname); 167 l += bozo_printf(httpd, "%s", htmlname); 168 } else { 169 bozo_printf(httpd, "<a href=\"%s\">", urlname); 170 l += bozo_printf(httpd, "%s", htmlname); 171 } 172 if (htmlname != name) 173 free(htmlname); 174 bozo_printf(httpd, "</a>"); 175 176 /* NAMELEN spaces */ 177 /*LINTED*/ 178 assert(/*CONSTCOND*/sizeof(spacebuf) > NAMELEN); 179 i = (l < NAMELEN) ? (NAMELEN - l) : 0; 180 i++; 181 memset(spacebuf, ' ', (size_t)i); 182 spacebuf[i] = '\0'; 183 bozo_printf(httpd, "%s", spacebuf); 184 l += i; 185 186 if (nostat) 187 bozo_printf(httpd, "? ?"); 188 else { 189 tm = gmtime(&sb.st_mtime); 190 strftime(buf, sizeof buf, "%d-%b-%Y %R", tm); 191 l += bozo_printf(httpd, "%s", buf); 192 193 /* LMODLEN spaces */ 194 /*LINTED*/ 195 assert(/*CONSTCOND*/sizeof(spacebuf) > LMODLEN); 196 i = (l < (LMODLEN+NAMELEN+1)) ? 197 ((LMODLEN+NAMELEN+1) - l) : 0; 198 i++; 199 memset(spacebuf, ' ', (size_t)i); 200 spacebuf[i] = '\0'; 201 bozo_printf(httpd, "%s", spacebuf); 202 203 bozo_printf(httpd, "%12llukB", 204 (unsigned long long)sb.st_size >> 10); 205 } 206 bozo_printf(httpd, "\r\n"); 207 } 208 209 closedir(dp); 210 while (k--) 211 free(deo[k]); 212 free(deo); 213 bozo_printf(httpd, "</pre>"); 214 directory_hr(httpd); 215 bozo_printf(httpd, "</body></html>\r\n\r\n"); 216 bozo_flush(httpd, stdout); 217 218done: 219 free(file); 220 free(printname); 221 return 1; 222} 223#endif /* NO_DIRINDEX_SUPPORT */ 224 225