]>
Commit | Line | Data |
---|---|---|
9492a34b | 1 | /* |
2 | * Copyright 2003 Michiel Boland. | |
3 | * All rights reserved. | |
4 | * | |
5 | * Redistribution and use in source and binary forms, with or | |
6 | * without modification, are permitted provided that the following | |
7 | * conditions are met: | |
8 | * | |
9 | * 1. Redistributions of source code must retain the above | |
10 | * copyright notice, this list of conditions and the following | |
11 | * disclaimer. | |
12 | * | |
13 | * 2. Redistributions in binary form must reproduce the above | |
14 | * copyright notice, this list of conditions and the following | |
15 | * disclaimer in the documentation and/or other materials | |
16 | * provided with the distribution. | |
17 | * | |
18 | * 3. The name of the author may not be used to endorse or promote | |
19 | * products derived from this software without specific prior | |
20 | * written permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY | |
23 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | |
24 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A | |
25 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR | |
26 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
27 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED | |
28 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
30 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
31 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | |
32 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | |
33 | * THE POSSIBILITY OF SUCH DAMAGE. | |
34 | */ | |
35 | ||
36 | #include <sys/types.h> | |
37 | #include <sys/stat.h> | |
38 | #include <dirent.h> | |
39 | #include <stdio.h> | |
40 | #include <stdlib.h> | |
41 | #include <string.h> | |
42 | ||
43 | struct cgi_dir_entry { | |
44 | char *name; | |
45 | off_t size; | |
46 | mode_t mode; | |
47 | time_t last_modified; | |
48 | }; | |
49 | ||
50 | static int cde_compare(const void *a, const void *b) | |
51 | { | |
52 | return strcmp(((struct cgi_dir_entry *) a)->name, ((struct cgi_dir_entry *) b)->name); | |
53 | } | |
54 | ||
55 | static void escape_html_print(const char *s) | |
56 | { | |
57 | int c; | |
58 | ||
59 | while ((c = *s++) != 0) | |
60 | switch (c) { | |
61 | case '<': | |
62 | printf("<"); | |
63 | break; | |
64 | case '&': | |
65 | printf("&"); | |
66 | break; | |
67 | case '"': | |
68 | printf("""); | |
69 | break; | |
70 | default: | |
71 | putchar(c); | |
72 | } | |
73 | } | |
74 | ||
75 | static int sort_and_print(struct cgi_dir_entry *p, size_t n) | |
76 | { | |
77 | size_t i; | |
78 | const char *path_info; | |
79 | ||
80 | if (n) | |
81 | qsort(p, n, sizeof *p, cde_compare); | |
82 | setvbuf(stdout, 0, _IOFBF, 0); | |
83 | printf("Cache-Control: max-age=900\n"); | |
84 | printf("Content-Type: text/html\n\n"); | |
85 | path_info = getenv("PATH_INFO"); | |
86 | printf("<html><head><title>index"); | |
87 | if (path_info) | |
88 | printf(" of %s", path_info); | |
89 | printf("</title></head><body><p><b>index"); | |
90 | if (path_info) | |
91 | printf(" of %s", path_info); | |
92 | printf("</b></p>\n"); | |
93 | printf("<p>directories:</p>\n"); | |
94 | printf("<div><a href=\"../\">[parent directory]</a></div>\n"); | |
95 | for (i = 0; i < n; i++) { | |
96 | if (S_ISDIR(p[i].mode)) { | |
97 | printf("<div><a href=\""); | |
98 | escape_html_print(p[i].name); | |
99 | printf("/\">"); | |
100 | escape_html_print(p[i].name); | |
101 | printf("</a></div>\n"); | |
102 | } | |
103 | } | |
104 | printf("<p>files:</p>\n"); | |
105 | for (i = 0; i < n; i++) { | |
106 | if (S_ISREG(p[i].mode)) { | |
107 | printf("<div><a href=\""); | |
108 | escape_html_print(p[i].name); | |
109 | printf("\">"); | |
110 | escape_html_print(p[i].name); | |
111 | printf("</a></div>\n"); | |
112 | } | |
113 | } | |
114 | printf("</body></html>\n"); | |
115 | return 0; | |
116 | } | |
117 | ||
118 | static int hide_name(const char *s) | |
119 | { | |
120 | return s[0] == 0 || s[0] == '.'; | |
121 | } | |
122 | ||
123 | static int do_dir(const char *dirname) | |
124 | { | |
125 | struct cgi_dir_entry *p, *q; | |
126 | size_t n; | |
127 | int rv; | |
128 | struct stat finfo; | |
129 | DIR *d; | |
130 | struct dirent *e; | |
131 | ||
132 | p = 0; | |
133 | n = 0; | |
134 | rv = 0; | |
135 | d = opendir(dirname); | |
136 | if (d == 0) { | |
137 | perror("opendir"); | |
138 | return 1; | |
139 | } | |
140 | while ((e = readdir(d)) != 0) { | |
141 | if (hide_name(e->d_name)) | |
142 | continue; | |
143 | if (lstat(e->d_name, &finfo) == -1) { | |
144 | perror("lstat"); | |
145 | rv = 1; | |
146 | break; | |
147 | } | |
148 | q = realloc(p, (n + 1) * sizeof *p); | |
149 | if (q == 0) { | |
150 | rv = 1; | |
151 | break; | |
152 | } | |
153 | p = q; | |
154 | p[n].name = strdup(e->d_name); | |
155 | if (p[n].name == 0) { | |
156 | rv = 1; | |
157 | break; | |
158 | } | |
159 | p[n].size = finfo.st_size; | |
160 | p[n].mode = finfo.st_mode; | |
161 | p[n].last_modified = finfo.st_mtime; | |
162 | ++n; | |
163 | } | |
164 | closedir(d); | |
165 | if (rv == 0) | |
166 | rv = sort_and_print(p, n); | |
167 | while (n) { | |
168 | --n; | |
169 | free(p[n].name); | |
170 | } | |
171 | if (p) | |
172 | free(p); | |
173 | return rv; | |
174 | } | |
175 | ||
176 | int main(void) | |
177 | { | |
178 | return do_dir("."); | |
179 | } |