123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 |
- /*
- * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com>
- * All rights reserved
- *
- * "THE BEER-WARE LICENSE" (Revision 42):
- * Sergey Lyubka wrote this file. As long as you retain this notice you
- * can do whatever you want with this stuff. If we meet some day, and you think
- * this stuff is worth it, you can buy me a beer in return.
- */
- #include "defs.h"
- /*
- * For a given PUT path, create all intermediate subdirectories
- * for given path. Return 0 if the path itself is a directory,
- * or -1 on error, 1 if OK.
- */
- int
- _shttpd_put_dir(const char *path)
- {
- char buf[FILENAME_MAX];
- const char *s, *p;
- struct stat st;
- size_t len;
- for (s = p = path + 2; (p = strchr(s, '/')) != NULL; s = ++p) {
- len = p - path;
- assert(len < sizeof(buf));
- (void) memcpy(buf, path, len);
- buf[len] = '\0';
- /* Try to create intermediate directory */
- if (_shttpd_stat(buf, &st) == -1 &&
- _shttpd_mkdir(buf, 0755) != 0)
- return (-1);
- /* Is path itself a directory ? */
- if (p[1] == '\0')
- return (0);
- }
- return (1);
- }
- static int
- read_dir(struct stream *stream, void *buf, size_t len)
- {
- static const char footer[] = "</table></body></html>\n";
- struct dirent *dp = NULL;
- char file[FILENAME_MAX], line[FILENAME_MAX + 512],
- size[64], mod[64];
- struct stat st;
- struct conn *c = stream->conn;
- int n, nwritten = 0;
- const char *slash = "";
- assert(stream->chan.dir.dirp != NULL);
- assert(stream->conn->uri[0] != '\0');
- do {
- if (len < sizeof(line))
- break;
- if ((dp = readdir(stream->chan.dir.dirp)) == NULL)
- break;
- DBG(("read_dir: %s", dp->d_name));
- /* Do not show current dir and passwords file */
- if (strcmp(dp->d_name, ".") == 0 ||
- strcmp(dp->d_name, HTPASSWD) == 0)
- continue;
- (void) _shttpd_snprintf(file, sizeof(file),
- "%s%s%s", stream->chan.dir.path, slash, dp->d_name);
- (void) _shttpd_stat(file, &st);
- if (S_ISDIR(st.st_mode)) {
- _shttpd_snprintf(size,sizeof(size),"%s","<DIR>");
- } else {
- if (st.st_size < 1024)
- (void) _shttpd_snprintf(size, sizeof(size),
- "%lu", (unsigned long) st.st_size);
- else if (st.st_size < 1024 * 1024)
- (void) _shttpd_snprintf(size,
- sizeof(size), "%luk",
- (unsigned long) (st.st_size >> 10) + 1);
- else
- (void) _shttpd_snprintf(size, sizeof(size),
- "%.1fM", (float) st.st_size / 1048576);
- }
- (void) strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M",
- localtime(&st.st_mtime));
- n = _shttpd_snprintf(line, sizeof(line),
- "<tr><td><a href=\"%s%s%s\">%s%s</a></td>"
- "<td> %s</td><td> %s</td></tr>\n",
- c->uri, slash, dp->d_name, dp->d_name,
- S_ISDIR(st.st_mode) ? "/" : "", mod, size);
- (void) memcpy(buf, line, n);
- buf = (char *) buf + n;
- nwritten += n;
- len -= n;
- } while (dp != NULL);
- /* Append proper HTML footer for the page */
- if (dp == NULL && len >= sizeof(footer)) {
- (void) memcpy(buf, footer, sizeof(footer));
- nwritten += sizeof(footer);
- stream->flags |= FLAG_CLOSED;
- }
- return (nwritten);
- }
- static void
- close_dir(struct stream *stream)
- {
- assert(stream->chan.dir.dirp != NULL);
- assert(stream->chan.dir.path != NULL);
- (void) closedir(stream->chan.dir.dirp);
- free(stream->chan.dir.path);
- }
- void
- _shttpd_get_dir(struct conn *c)
- {
- if ((c->loc.chan.dir.dirp = opendir(c->loc.chan.dir.path)) == NULL) {
- (void) free(c->loc.chan.dir.path);
- _shttpd_send_server_error(c, 500, "Cannot open directory");
- } else {
- c->loc.io.head = _shttpd_snprintf(c->loc.io.buf, c->loc.io.size,
- "HTTP/1.1 200 OK\r\n"
- "Connection: close\r\n"
- "Content-Type: text/html; charset=utf-8\r\n\r\n"
- "<html><head><title>Index of %s</title>"
- "<style>th {text-align: left;}</style></head>"
- "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">"
- "<tr><th>Name</th><th>Modified</th><th>Size</th></tr>"
- "<tr><td colspan=\"3\"><hr></td></tr>",
- c->uri, c->uri);
- io_clear(&c->rem.io);
- c->status = 200;
- c->loc.io_class = &_shttpd_io_dir;
- c->loc.flags |= FLAG_R | FLAG_ALWAYS_READY;
- }
- }
- const struct io_class _shttpd_io_dir = {
- "dir",
- read_dir,
- NULL,
- close_dir
- };
|