Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include <bio.h>
4
#include "httpd.h"
5
#include "httpsrv.h"
6
 
7
Hio *HO;
8
int diffb;
9
 
10
enum{ DAY = 24*60*60 };
11
 
12
void
13
lastbefore(ulong t, char *f, char *b)
14
{
15
	Tm *tm;
16
	Dir *dir;
17
	int try;
18
	ulong t0, mtime;
19
 
20
	t0 = t;
21
	for(try=0; try<10; try++) {
22
		tm = localtime(t);
23
		t -= DAY;
24
		sprint(b,"%.4d/%.2d%.2d/netlib/pub/%s",tm->year+1900,tm->mon+1,tm->mday,f);
25
		dir = dirstat(b);
26
		if(dir == nil)
27
			continue;
28
		mtime = dir->mtime;
29
		free(dir);
30
		if(mtime > t0)
31
			continue;
32
		return;
33
	}
34
	strcpy(b, "filenotfound");
35
}
36
 
37
// create explicit file for diff, which otherwise would create a
38
// mode 0600 file that it couldn't read (because running as none)
39
void
40
gunzip(char *f, char *tmp)
41
{
42
	int fd = open(tmp, OWRITE);
43
 
44
	if(fd < 0)  // can't happen
45
		return;
46
	switch(fork()){
47
	case 0:
48
		dup(fd, 1);
49
		close(fd);
50
		close(0);
51
		execl("/bin/gunzip", "gunzip", "-c", f, nil);
52
		hprint(HO, "can't exec gunzip: %r\n");
53
		break;
54
	case -1:
55
		hprint(HO, "fork failed: %r\n");
56
	default:
57
		while(waitpid() != -1)
58
			;
59
		break;
60
	}
61
	close(fd);
62
}
63
 
64
void
65
netlibhistory(char *file)
66
{
67
	char buf[500], pair[2][500], tmpf[2][30], *f;
68
	int toggle = 0, started = 0, limit;
69
	Dir *dir;
70
	ulong otime, dt;
71
	int i, fd, tmpcnt;
72
 
73
	if(strncmp(file, "../", 3) == 0 || strstr(file, "/../") ||
74
		strlen(file) >= sizeof(buf) - strlen("1997/0204/netlib/pub/0"))
75
		return;
76
	limit = 50;
77
	if(diffb){
78
		limit = 10;
79
		// create two tmp files for gunzip
80
		for(i = 0, tmpcnt = 0; i < 2 && tmpcnt < 20; tmpcnt++){
81
			snprint(tmpf[i], sizeof(tmpf[0]), "/tmp/d%x", tmpcnt);
82
			if(access(buf, AEXIST) == 0)
83
				continue;
84
			fd = create(tmpf[i], OWRITE, 0666);
85
			if(fd < 0)
86
				goto done;
87
			close(fd);
88
			i++;
89
		}
90
	}
91
	otime = time(0);
92
	hprint(HO,"<UL>\n");
93
	while(limit--){
94
		lastbefore(otime, file, buf);
95
		dir = dirstat(buf);
96
		if(dir == nil)
97
			goto done;
98
		dt = DAY/2;
99
		while(otime <= dir->mtime){
100
			lastbefore(otime-dt, file, buf);
101
			free(dir);
102
			dir = dirstat(buf);
103
			if(dir == nil)
104
				goto done;
105
			dt += DAY/2;
106
		}
107
		f = pair[toggle];
108
		strcpy(f, buf);
109
		if(diffb && strcmp(f+strlen(f)-3, ".gz") == 0){
110
			gunzip(f, tmpf[toggle]);
111
			strcpy(f, tmpf[toggle]);
112
		}
113
		if(diffb && started){
114
			hprint(HO, "<PRE>\n");
115
			hflush(HO);
116
			switch(fork()){
117
			case 0:
118
				execl("/bin/diff", "diff", "-nb",
119
					pair[1-toggle], pair[toggle], nil);
120
				hprint(HO, "can't exec diff: %r\n");
121
				break;
122
			case -1:
123
				hprint(HO, "fork failed: %r\n");
124
				break;
125
			default:
126
				while(waitpid() != -1)
127
					;
128
				break;
129
			}
130
			hprint(HO, "</PRE>\n");
131
		}
132
		hprint(HO,"<LI><A HREF=\"/historic/%s\">%s</A> %lld bytes\n",
133
			buf, 4+asctime(gmtime(dir->mtime)), dir->length);
134
		if(diffb)
135
			hprint(HO," <FONT SIZE=-1>(%s)</FONT>\n", pair[toggle]);
136
		toggle = 1-toggle;
137
		started = 1;
138
		otime = dir->mtime;
139
		free(dir);
140
	}
141
	hprint(HO,"<LI>...\n");
142
done:
143
	hprint(HO,"</UL>\n");
144
	if(diffb){
145
		remove(tmpf[0]);
146
		remove(tmpf[1]);
147
	}
148
}
149
 
150
int
151
send(HConnect *c)
152
{
153
	char *file, *s;
154
	HSPairs *q;
155
 
156
	if(strcmp(c->req.meth, "GET") != 0 && strcmp(c->req.meth, "HEAD") != 0)
157
		return hunallowed(c, "GET, HEAD");
158
	if(c->head.expectother || c->head.expectcont)
159
		return hfail(c, HExpectFail, nil);
160
	if(c->req.search == nil || !*c->req.search)
161
		return hfail(c, HNoData, "netlib_history");
162
	s = c->req.search;
163
	while((s = strchr(s, '+')) != nil)
164
		*s++ = ' ';
165
	file = nil;
166
	for(q = hparsequery(c, hstrdup(c, c->req.search)); q; q = q->next){
167
		if(strcmp(q->s, "file") == 0)
168
			file = q->t;
169
		else if(strcmp(q->s, "diff") == 0)
170
			diffb = 1;
171
	}
172
	if(file == nil)
173
		return hfail(c, HNoData, "netlib_history missing file field");
174
	logit(c, "netlib_hist %s%s", file, diffb?" DIFF":"");
175
 
176
	if(c->req.vermaj){
177
		hokheaders(c);
178
		hprint(HO, "Content-type: text/html\r\n");
179
		hprint(HO, "\r\n");
180
	}
181
	if(strcmp(c->req.meth, "HEAD") == 0){
182
		writelog(c, "Reply: 200 netlib_history 0\n");
183
		hflush(HO);
184
		exits(nil);
185
	}
186
 
187
	hprint(HO, "<HEAD><TITLE>%s history</TITLE></HEAD>\n<BODY>\n",file);
188
	hprint(HO, "<H2>%s history</H2>\n",file);
189
	hprint(HO, "<I>Netlib's copy of %s was changed\n", file);
190
	hprint(HO, "on the dates shown.  <BR>Click on the date link\n");
191
	hprint(HO, "to retrieve the corresponding version.</I>\n");
192
	if(diffb){
193
		hprint(HO, "<BR><I>Lines beginning with &lt; are for the\n");
194
		hprint(HO, "newer of the two versions.</I>\n");
195
	}
196
 
197
	if(chdir("/usr/web/historic") < 0)
198
		hprint(HO, "chdir failed: %r\n");
199
	netlibhistory(file);
200
 
201
	hprint(HO, "<BR><A HREF=\"http://cm.bell-labs.com/who/ehg\">Eric Grosse</A>\n");
202
	hprint(HO, "</BODY></HTML>\n");
203
	hflush(HO);
204
	writelog(c, "Reply: 200 netlib_history %ld %ld\n", HO->seek, HO->seek);
205
	return 1;
206
}
207
 
208
void
209
main(int argc, char **argv)
210
{
211
	HConnect *c;
212
 
213
	c = init(argc, argv);
214
	HO = &c->hout;
215
	if(hparseheaders(c, HSTIMEOUT) >= 0)
216
		send(c);
217
	exits(nil);
218
}