netlib_history.c 4.6 KB

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