source: rtems/cpukit/shttpd/io_dir.c @ 4d0771e

4.104.115
Last change on this file since 4d0771e was 484cd8d, checked in by Ralf Corsepius <ralf.corsepius@…>, on 06/11/07 at 13:24:29

Import from shttpd-1.37.

  • Property mode set to 100644
File size: 3.7 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
19put_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 (my_stat(buf, &st) == -1 && my_mkdir(buf, 0755) != 0)
34                        return (-1);
35
36                /* Is path itself a directory ? */
37                if (p[1] == '\0')
38                        return (0);
39        }
40
41        return (1);
42}
43
44static int
45read_dir(struct stream *stream, void *buf, size_t len)
46{
47        struct dirent   *dp = NULL;
48        char            file[FILENAME_MAX], line[FILENAME_MAX + 512],
49                                size[64], mod[64];
50        struct stat     st;
51        struct conn     *c = stream->conn;
52        int             n, nwritten = 0;
53        const char      *slash = "";
54
55        assert(stream->chan.dir.dirp != NULL);
56        assert(stream->conn->uri[0] != '\0');
57
58        do {
59                if (len < sizeof(line))
60                        break;
61
62                if ((dp = readdir(stream->chan.dir.dirp)) == NULL) {
63                        stream->flags |= FLAG_CLOSED;
64                        break;
65                }
66                DBG(("read_dir: %s", dp->d_name));
67
68                /* Do not show current dir and passwords file */
69                if (strcmp(dp->d_name, ".") == 0 ||
70                   strcmp(dp->d_name, HTPASSWD) == 0)
71                        continue;
72
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","&lt;DIR&gt;");
78                } else {
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);
85                        else
86                                (void) my_snprintf(size, sizeof(size),
87                                    "%.1fM", (float) st.st_size / 1048576);
88                }
89                (void) strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M",
90                        localtime(&st.st_mtime));
91
92                n = my_snprintf(line, sizeof(line),
93                    "<tr><td><a href=\"%s%s%s\">%s%s</a></td>"
94                    "<td>&nbsp;%s</td><td>&nbsp;&nbsp;%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;
99                nwritten += n;
100                len -= n;
101        } while (dp != NULL);
102
103        return (nwritten);
104}
105
106static void
107close_dir(struct stream *stream)
108{
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);
113}
114
115void
116get_dir(struct conn *c)
117{
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");
121        } else {
122                c->loc.io.head = my_snprintf(c->loc.io.buf, c->loc.io.size,
123                    "HTTP/1.1 200 OK\r\n"
124                    "Content-Type: text/html; charset=utf-8\r\n\r\n"
125                    "<html><head><title>Index of %s</title>"
126                    "<style>th {text-align: left;}</style></head>"
127                    "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">"
128                    "<tr><th>Name</th><th>Modified</th><th>Size</th></tr>"
129                    "<tr><td colspan=\"3\"><hr></td></tr>",
130                    c->uri, c->uri);
131                io_clear(&c->rem.io);
132                c->status = 200;
133                c->loc.io_class = &io_dir;
134                c->loc.flags |= FLAG_R | FLAG_ALWAYS_READY;
135        }
136}
137
138const struct io_class   io_dir =  {
139        "dir",
140        read_dir,
141        NULL,
142        close_dir
143};
Note: See TracBrowser for help on using the repository browser.