zipfs.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include <u.h>
  10. #include <libc.h>
  11. #include <bio.h>
  12. #include <flate.h>
  13. #include <auth.h>
  14. #include <fcall.h>
  15. #include <ctype.h>
  16. #include "tapefs.h"
  17. #include "zip.h"
  18. #define FORCE_LOWER 1 /* force filenames to lower case */
  19. #define MUNGE_CR 1 /* replace '\r\n' with ' \n' */
  20. #define High64 (1LL<<63)
  21. /*
  22. * File system for zip archives (read-only)
  23. */
  24. enum {
  25. IS_MSDOS = 0, /* creator OS (interpretation of external flags) */
  26. IS_RDONLY = 1, /* file was readonly (external flags) */
  27. IS_TEXT = 1, /* file was text (internal flags) */
  28. };
  29. typedef struct Block Block;
  30. struct Block{
  31. uint8_t *pos;
  32. uint8_t *limit;
  33. };
  34. static Biobuf *bin;
  35. static uint32_t *crctab;
  36. static uint32_t crc;
  37. static int findCDir(Biobuf *);
  38. static int header(Biobuf *, ZipHead *);
  39. static int cheader(Biobuf *, ZipHead *);
  40. static void trailer(Biobuf *, ZipHead *);
  41. static char *getname(Biobuf *, int);
  42. static int blwrite(void *, void *, int);
  43. static uint32_t get4(Biobuf *);
  44. static int get2(Biobuf *);
  45. static int get1(Biobuf *);
  46. static int32_t msdos2time(int, int);
  47. void
  48. populate(char *name)
  49. {
  50. char *p;
  51. Fileinf f;
  52. ZipHead zh;
  53. int ok, entries;
  54. crctab = mkcrctab(ZCrcPoly);
  55. ok = inflateinit();
  56. if(ok != FlateOk)
  57. sysfatal("inflateinit failed: %s", flateerr(ok));
  58. bin = Bopen(name, OREAD);
  59. if (bin == nil)
  60. error("Can't open argument file");
  61. entries = findCDir(bin);
  62. if(entries < 0)
  63. sysfatal("empty file");
  64. while(entries-- > 0){
  65. memset(&zh, 0, sizeof(zh));
  66. if(!cheader(bin, &zh))
  67. break;
  68. f.addr = zh.off;
  69. if(zh.iattr & IS_TEXT)
  70. f.addr |= High64;
  71. f.mode = (zh.madevers == IS_MSDOS && zh.eattr & IS_RDONLY)? 0444: 0644;
  72. if (zh.meth == 0 && zh.uncsize == 0){
  73. p = strchr(zh.file, '\0');
  74. if(p > zh.file && p[-1] == '/')
  75. f.mode |= (DMDIR | 0111);
  76. }
  77. f.uid = 0;
  78. f.gid = 0;
  79. f.size = zh.uncsize;
  80. f.mdate = msdos2time(zh.modtime, zh.moddate);
  81. f.name = zh.file + ((zh.file[0] == '/')? 1: 0);
  82. poppath(f, 1);
  83. free(zh.file);
  84. }
  85. return ;
  86. }
  87. void
  88. dotrunc(Ram *r)
  89. {
  90. USED(r);
  91. }
  92. void
  93. docreate(Ram *r)
  94. {
  95. USED(r);
  96. }
  97. char *
  98. doread(Ram *r, int64_t off, int32_t cnt)
  99. {
  100. int i, err;
  101. Block bs;
  102. ZipHead zh;
  103. static Qid oqid;
  104. static char buf[Maxbuf];
  105. static uint8_t *cache = nil;
  106. if (cnt > Maxbuf)
  107. sysfatal("file too big (>%d)", Maxbuf);
  108. if (Bseek(bin, r->addr & 0x7FFFFFFFFFFFFFFFLL, 0) < 0)
  109. sysfatal("seek failed");
  110. memset(&zh, 0, sizeof(zh));
  111. if (!header(bin, &zh))
  112. sysfatal("cannot get local header");
  113. switch(zh.meth){
  114. case 0:
  115. if (Bseek(bin, off, 1) < 0)
  116. sysfatal("seek failed");
  117. if (Bread(bin, buf, cnt) != cnt)
  118. sysfatal("read failed");
  119. break;
  120. case 8:
  121. if (r->qid.path != oqid.path){
  122. oqid = r->qid;
  123. if (cache)
  124. free(cache);
  125. cache = emalloc(r->ndata);
  126. bs.pos = cache;
  127. bs.limit = cache+r->ndata;
  128. if ((err = inflate(&bs, blwrite, bin, (int(*)(void*))Bgetc)) != FlateOk)
  129. sysfatal("inflate failed - %s", flateerr(err));
  130. if (blockcrc(crctab, crc, cache, r->ndata) != zh.crc)
  131. fprint(2, "%s - crc failed", r->name);
  132. if ((r->addr & High64) && MUNGE_CR){
  133. for (i = 0; i < r->ndata -1; i++)
  134. if (cache[i] == '\r' && cache[i +1] == '\n')
  135. cache[i] = ' ';
  136. }
  137. }
  138. memcpy(buf, cache+off, cnt);
  139. break;
  140. default:
  141. sysfatal("%d - unsupported compression method", zh.meth);
  142. break;
  143. }
  144. return buf;
  145. }
  146. void
  147. popdir(Ram *r)
  148. {
  149. USED(r);
  150. }
  151. void
  152. dowrite(Ram *r, char *buf, int32_t off, int32_t cnt)
  153. {
  154. USED(r); USED(buf); USED(off); USED(cnt);
  155. }
  156. int
  157. dopermw(Ram *r)
  158. {
  159. USED(r);
  160. return 0;
  161. }
  162. /*************************************************/
  163. static int
  164. findCDir(Biobuf *bin)
  165. {
  166. int64_t ecoff;
  167. int32_t off;
  168. int entries, zclen;
  169. ecoff = Bseek(bin, -ZECHeadSize, 2);
  170. if(ecoff < 0)
  171. sysfatal("can't seek to header");
  172. if(get4(bin) != ZECHeader)
  173. sysfatal("bad magic number on directory");
  174. get2(bin);
  175. get2(bin);
  176. get2(bin);
  177. entries = get2(bin);
  178. get4(bin);
  179. off = get4(bin);
  180. zclen = get2(bin);
  181. while(zclen-- > 0)
  182. get1(bin);
  183. if(Bseek(bin, off, 0) != off)
  184. sysfatal("can't seek to contents");
  185. return entries;
  186. }
  187. static int
  188. header(Biobuf *bin, ZipHead *zh)
  189. {
  190. uint32_t v;
  191. int flen, xlen;
  192. v = get4(bin);
  193. if(v != ZHeader){
  194. if(v == ZCHeader)
  195. return 0;
  196. sysfatal("bad magic on local header");
  197. }
  198. zh->extvers = get1(bin);
  199. zh->extos = get1(bin);
  200. zh->flags = get2(bin);
  201. zh->meth = get2(bin);
  202. zh->modtime = get2(bin);
  203. zh->moddate = get2(bin);
  204. zh->crc = get4(bin);
  205. zh->csize = get4(bin);
  206. zh->uncsize = get4(bin);
  207. flen = get2(bin);
  208. xlen = get2(bin);
  209. zh->file = getname(bin, flen);
  210. while(xlen-- > 0)
  211. get1(bin);
  212. return 1;
  213. }
  214. static int
  215. cheader(Biobuf *bin, ZipHead *zh)
  216. {
  217. uint32_t v;
  218. int flen, xlen, fclen;
  219. v = get4(bin);
  220. if(v != ZCHeader){
  221. if(v == ZECHeader)
  222. return 0;
  223. sysfatal("bad magic number in file");
  224. }
  225. zh->madevers = get1(bin);
  226. zh->madeos = get1(bin);
  227. zh->extvers = get1(bin);
  228. zh->extos = get1(bin);
  229. zh->flags = get2(bin);
  230. zh->meth = get2(bin);
  231. zh->modtime = get2(bin);
  232. zh->moddate = get2(bin);
  233. zh->crc = get4(bin);
  234. zh->csize = get4(bin);
  235. zh->uncsize = get4(bin);
  236. flen = get2(bin);
  237. xlen = get2(bin);
  238. fclen = get2(bin);
  239. get2(bin); /* disk number start */
  240. zh->iattr = get2(bin); /* 1 == is-text-file */
  241. zh->eattr = get4(bin); /* 1 == readonly-file */
  242. zh->off = get4(bin);
  243. zh->file = getname(bin, flen);
  244. while(xlen-- > 0)
  245. get1(bin);
  246. while(fclen-- > 0)
  247. get1(bin);
  248. return 1;
  249. }
  250. static int
  251. blwrite(void *vb, void *buf, int n)
  252. {
  253. Block *b = vb;
  254. if(n > b->limit - b->pos)
  255. n = b->limit - b->pos;
  256. memmove(b->pos, buf, n);
  257. b->pos += n;
  258. return n;
  259. }
  260. static void
  261. trailer(Biobuf *bin, ZipHead *zh)
  262. {
  263. if(zh->flags & ZTrailInfo){
  264. zh->crc = get4(bin);
  265. zh->csize = get4(bin);
  266. zh->uncsize = get4(bin);
  267. }
  268. }
  269. static char*
  270. getname(Biobuf *bin, int len)
  271. {
  272. char *s;
  273. int i, c;
  274. s = emalloc(len + 1);
  275. for(i = 0; i < len; i++){
  276. c = get1(bin);
  277. if(FORCE_LOWER)
  278. c = tolower(c);
  279. s[i] = c;
  280. }
  281. s[i] = '\0';
  282. return s;
  283. }
  284. static uint32_t
  285. get4(Biobuf *b)
  286. {
  287. uint32_t v;
  288. int i, c;
  289. v = 0;
  290. for(i = 0; i < 4; i++){
  291. c = Bgetc(b);
  292. if(c < 0)
  293. sysfatal("unexpected eof");
  294. v |= c << (i * 8);
  295. }
  296. return v;
  297. }
  298. static int
  299. get2(Biobuf *b)
  300. {
  301. int i, c, v;
  302. v = 0;
  303. for(i = 0; i < 2; i++){
  304. c = Bgetc(b);
  305. if(c < 0)
  306. sysfatal("unexpected eof");
  307. v |= c << (i * 8);
  308. }
  309. return v;
  310. }
  311. static int
  312. get1(Biobuf *b)
  313. {
  314. int c;
  315. c = Bgetc(b);
  316. if(c < 0)
  317. sysfatal("unexpected eof");
  318. return c;
  319. }
  320. static int32_t
  321. msdos2time(int time, int date)
  322. {
  323. Tm tm;
  324. tm.hour = time >> 11;
  325. tm.min = (time >> 5) & 63;
  326. tm.sec = (time & 31) << 1;
  327. tm.year = 80 + (date >> 9);
  328. tm.mon = ((date >> 5) & 15) - 1;
  329. tm.mday = date & 31;
  330. tm.zone[0] = '\0';
  331. tm.yday = 0;
  332. return tm2sec(&tm);
  333. }