source: trunk/third-party/shttpd/io_dir.c @ 6644

Last change on this file since 6644 was 6644, checked in by charles, 13 years ago

upgrade to shttpd 1.42

File size: 4.0 KB
Line 
1/*
2 * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com>
3 * All rights reserved
4 *
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.
9 */
10
11#include "defs.h"
12
13/*
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.
17 */
18int
19_shttpd_put_dir(const char *path)
20{
21        char            buf[FILENAME_MAX];
22        const char      *s, *p;
23        struct stat     st;
24        size_t          len;
25
26        for (s = p = path + 2; (p = strchr(s, '/')) != NULL; s = ++p) {
27                len = p - path;
28                assert(len < sizeof(buf));
29                (void) memcpy(buf, path, len);
30                buf[len] = '\0';
31
32                /* Try to create intermediate directory */
33                if (_shttpd_stat(buf, &st) == -1 &&
34                    _shttpd_mkdir(buf, 0755) != 0)
35                        return (-1);
36
37                /* Is path itself a directory ? */
38                if (p[1] == '\0')
39                        return (0);
40        }
41
42        return (1);
43}
44
45static int
46read_dir(struct stream *stream, void *buf, size_t len)
47{
48        static const char footer[] = "</table></body></html>\n";
49
50        struct dirent   *dp = NULL;
51        char            file[FILENAME_MAX], line[FILENAME_MAX + 512],
52                                size[64], mod[64];
53        struct stat     st;
54        struct conn     *c = stream->conn;
55        int             n, nwritten = 0;
56        const char      *slash = "";
57
58        assert(stream->chan.dir.dirp != NULL);
59        assert(stream->conn->uri[0] != '\0');
60
61        do {
62                if (len < sizeof(line))
63                        break;
64
65                if ((dp = readdir(stream->chan.dir.dirp)) == NULL)
66                        break;
67                DBG(("read_dir: %s", dp->d_name));
68
69                /* Do not show current dir and passwords file */
70                if (strcmp(dp->d_name, ".") == 0 ||
71                   strcmp(dp->d_name, HTPASSWD) == 0)
72                        continue;
73
74                (void) _shttpd_snprintf(file, sizeof(file),
75                    "%s%s%s", stream->chan.dir.path, slash, dp->d_name);
76                (void) _shttpd_stat(file, &st);
77                if (S_ISDIR(st.st_mode)) {
78                        _shttpd_snprintf(size,sizeof(size),"%s","&lt;DIR&gt;");
79                } else {
80                        if (st.st_size < 1024)
81                                (void) _shttpd_snprintf(size, sizeof(size),
82                                    "%lu", (unsigned long) st.st_size);
83                        else if (st.st_size < 1024 * 1024)
84                                (void) _shttpd_snprintf(size,
85                                    sizeof(size), "%luk",
86                                    (unsigned long) (st.st_size >> 10)  + 1);
87                        else
88                                (void) _shttpd_snprintf(size, sizeof(size),
89                                    "%.1fM", (float) st.st_size / 1048576);
90                }
91                (void) strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M",
92                        localtime(&st.st_mtime));
93
94                n = _shttpd_snprintf(line, sizeof(line),
95                    "<tr><td><a href=\"%s%s%s\">%s%s</a></td>"
96                    "<td>&nbsp;%s</td><td>&nbsp;&nbsp;%s</td></tr>\n",
97                    c->uri, slash, dp->d_name, dp->d_name,
98                    S_ISDIR(st.st_mode) ? "/" : "", mod, size);
99                (void) memcpy(buf, line, n);
100                buf = (char *) buf + n;
101                nwritten += n;
102                len -= n;
103        } while (dp != NULL);
104
105        /* Append proper HTML footer for the page */
106        if (dp == NULL && len >= sizeof(footer)) {
107                (void) memcpy(buf, footer, sizeof(footer));
108                nwritten += sizeof(footer);
109                stream->flags |= FLAG_CLOSED;
110        }
111
112        return (nwritten);
113}
114
115static void
116close_dir(struct stream *stream)
117{
118        assert(stream->chan.dir.dirp != NULL);
119        assert(stream->chan.dir.path != NULL);
120        (void) closedir(stream->chan.dir.dirp);
121        free(stream->chan.dir.path);
122}
123
124void
125_shttpd_get_dir(struct conn *c)
126{
127        if ((c->loc.chan.dir.dirp = opendir(c->loc.chan.dir.path)) == NULL) {
128                (void) free(c->loc.chan.dir.path);
129                _shttpd_send_server_error(c, 500, "Cannot open directory");
130        } else {
131                c->loc.io.head = _shttpd_snprintf(c->loc.io.buf, c->loc.io.size,
132                    "HTTP/1.1 200 OK\r\n"
133                    "Connection: close\r\n"
134                    "Content-Type: text/html; charset=utf-8\r\n\r\n"
135                    "<html><head><title>Index of %s</title>"
136                    "<style>th {text-align: left;}</style></head>"
137                    "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">"
138                    "<tr><th>Name</th><th>Modified</th><th>Size</th></tr>"
139                    "<tr><td colspan=\"3\"><hr></td></tr>",
140                    c->uri, c->uri);
141                io_clear(&c->rem.io);
142                c->status = 200;
143                c->loc.io_class = &_shttpd_io_dir;
144                c->loc.flags |= FLAG_R | FLAG_ALWAYS_READY;
145        }
146}
147
148const struct io_class   _shttpd_io_dir =  {
149        "dir",
150        read_dir,
151        NULL,
152        close_dir
153};
Note: See TracBrowser for help on using the repository browser.