zipfs.c 6.4 KB

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