2 * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com>
5 * "THE BEER-WARE LICENSE" (Revision 42):
6 * Sergey Lyubka wrote this file. As long as you retain this notice you
7 * can do whatever you want with this stuff. If we meet some day, and you think
8 * this stuff is worth it, you can buy me a beer in return.
14 * For a given PUT path, create all intermediate subdirectories
15 * for given path. Return 0 if the path itself is a directory,
16 * or -1 on error, 1 if OK.
19 put_dir(const char *path)
21 char buf[FILENAME_MAX];
26 for (s = p = path + 2; (p = strchr(s, '/')) != NULL; s = ++p) {
28 assert(len < sizeof(buf));
29 (void) memcpy(buf, path, len);
32 /* Try to create intermediate directory */
33 if (my_stat(buf, &st) == -1 && my_mkdir(buf, 0755) != 0)
36 /* Is path itself a directory ? */
45 read_dir(struct stream *stream, void *buf, size_t len)
47 struct dirent *dp = NULL;
48 char file[FILENAME_MAX], line[FILENAME_MAX + 512],
51 struct conn *c = stream->conn;
53 const char *slash = "";
55 assert(stream->chan.dir.dirp != NULL);
56 assert(stream->conn->uri[0] != '\0');
59 if (len < sizeof(line))
62 if ((dp = readdir(stream->chan.dir.dirp)) == NULL) {
63 stream->flags |= FLAG_CLOSED;
66 DBG(("read_dir: %s", dp->d_name));
68 /* Do not show current dir and passwords file */
69 if (strcmp(dp->d_name, ".") == 0 ||
70 strcmp(dp->d_name, HTPASSWD) == 0)
73 (void) my_snprintf(file, sizeof(file),
74 "%s%s%s", stream->chan.dir.path, slash, dp->d_name);
75 (void) my_stat(file, &st);
76 if (S_ISDIR(st.st_mode)) {
77 my_snprintf(size,sizeof(size),"%s","<DIR>");
79 if (st.st_size < 1024)
80 (void) my_snprintf(size, sizeof(size),
81 "%lu", (unsigned long) st.st_size);
82 else if (st.st_size < 1024 * 1024)
83 (void) my_snprintf(size, sizeof(size), "%luk",
84 (unsigned long) (st.st_size >> 10) + 1);
86 (void) my_snprintf(size, sizeof(size),
87 "%.1fM", (float) st.st_size / 1048576);
89 (void) strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M",
90 localtime(&st.st_mtime));
92 n = my_snprintf(line, sizeof(line),
93 "<tr><td><a href=\"%s%s%s\">%s%s</a></td>"
94 "<td> %s</td><td> %s</td></tr>\n",
95 c->uri, slash, dp->d_name, dp->d_name,
96 S_ISDIR(st.st_mode) ? "/" : "", mod, size);
97 (void) memcpy(buf, line, n);
98 buf = (char *) buf + n;
101 } while (dp != NULL);
107 close_dir(struct stream *stream)
109 assert(stream->chan.dir.dirp != NULL);
110 assert(stream->chan.dir.path != NULL);
111 (void) closedir(stream->chan.dir.dirp);
112 free(stream->chan.dir.path);
116 get_dir(struct conn *c)
118 if ((c->loc.chan.dir.dirp = opendir(c->loc.chan.dir.path)) == NULL) {
119 (void) free(c->loc.chan.dir.path);
120 send_server_error(c, 500, "Cannot open directory");
122 c->loc.io.head = my_snprintf(c->loc.io.buf, c->loc.io.size,
123 "HTTP/1.1 200 OK\r\n"
124 "Connection: close\r\n"
125 "Content-Type: text/html; charset=utf-8\r\n\r\n"
126 "<html><head><title>Index of %s</title>"
127 "<style>th {text-align: left;}</style></head>"
128 "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">"
129 "<tr><th>Name</th><th>Modified</th><th>Size</th></tr>"
130 "<tr><td colspan=\"3\"><hr></td></tr>",
132 io_clear(&c->rem.io);
134 c->loc.io_class = &io_dir;
135 c->loc.flags |= FLAG_R | FLAG_ALWAYS_READY;
139 const struct io_class io_dir = {