X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;f=libs%2Fshttpd%2Fio_dir.c;fp=libs%2Fshttpd%2Fio_dir.c;h=0534c623a270273c07800433dba24005dfa25a50;hb=d8ccfe2b3944adf07d35534459cdda19d15217c8;hp=0000000000000000000000000000000000000000;hpb=21f835f30b4e092c847bf4569a00995774f7330e;p=fms.git diff --git a/libs/shttpd/io_dir.c b/libs/shttpd/io_dir.c new file mode 100644 index 0000000..0534c62 --- /dev/null +++ b/libs/shttpd/io_dir.c @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2004-2005 Sergey Lyubka + * 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","<DIR>"); + } 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), + "%s%s" + " %s  %s\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" + "Index of %s" + "" + "

Index of %s

"
+		    ""
+		    "",
+		    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
+};
NameModifiedSize