summaryrefslogtreecommitdiffstats
path: root/cpukit/shttpd/io_dir.c
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/shttpd/io_dir.c')
-rw-r--r--cpukit/shttpd/io_dir.c143
1 files changed, 143 insertions, 0 deletions
diff --git a/cpukit/shttpd/io_dir.c b/cpukit/shttpd/io_dir.c
new file mode 100644
index 0000000000..0534c623a2
--- /dev/null
+++ b/cpukit/shttpd/io_dir.c
@@ -0,0 +1,143 @@
+/*
+ * 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
+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 (my_stat(buf, &st) == -1 && my_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)
+{
+ 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) {
+ stream->flags |= FLAG_CLOSED;
+ 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) my_snprintf(file, sizeof(file),
+ "%s%s%s", stream->chan.dir.path, slash, dp->d_name);
+ (void) my_stat(file, &st);
+ if (S_ISDIR(st.st_mode)) {
+ my_snprintf(size,sizeof(size),"%s","&lt;DIR&gt;");
+ } else {
+ if (st.st_size < 1024)
+ (void) my_snprintf(size, sizeof(size),
+ "%lu", (unsigned long) st.st_size);
+ else if (st.st_size < 1024 * 1024)
+ (void) my_snprintf(size, sizeof(size), "%luk",
+ (unsigned long) (st.st_size >> 10) + 1);
+ else
+ (void) my_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 = my_snprintf(line, sizeof(line),
+ "<tr><td><a href=\"%s%s%s\">%s%s</a></td>"
+ "<td>&nbsp;%s</td><td>&nbsp;&nbsp;%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);
+
+ 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
+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);
+ send_server_error(c, 500, "Cannot open directory");
+ } else {
+ c->loc.io.head = my_snprintf(c->loc.io.buf, c->loc.io.size,
+ "HTTP/1.1 200 OK\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 = &io_dir;
+ c->loc.flags |= FLAG_R | FLAG_ALWAYS_READY;
+ }
+}
+
+const struct io_class io_dir = {
+ "dir",
+ read_dir,
+ NULL,
+ close_dir
+};