tarfs.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. /*
  2. * File system for tar archives (read-only)
  3. */
  4. #include <u.h>
  5. #include <libc.h>
  6. #include <auth.h>
  7. #include <fcall.h>
  8. #include "tapefs.h"
  9. /* fundamental constants */
  10. enum {
  11. Tblock = 512,
  12. Namsiz = 100,
  13. Maxpfx = 155, /* from POSIX */
  14. Maxname = Namsiz + 1 + Maxpfx,
  15. Binsize = 0x80, /* flag in size[0], from gnu: positive binary size */
  16. Binnegsz = 0xff, /* flag in size[0]: negative binary size */
  17. };
  18. /* POSIX link flags */
  19. enum {
  20. LF_PLAIN1 = '\0',
  21. LF_PLAIN2 = '0',
  22. LF_LINK = '1',
  23. LF_SYMLINK1 = '2',
  24. LF_SYMLINK2 = 's', /* 4BSD used this */
  25. LF_CHR = '3',
  26. LF_BLK = '4',
  27. LF_DIR = '5',
  28. LF_FIFO = '6',
  29. LF_CONTIG = '7',
  30. /* 'A' - 'Z' are reserved for custom implementations */
  31. };
  32. typedef union {
  33. char dummy[Tblock];
  34. char tbuf[Maxbuf];
  35. struct Header {
  36. char name[Namsiz];
  37. char mode[8];
  38. char uid[8];
  39. char gid[8];
  40. char size[12];
  41. char mtime[12];
  42. char chksum[8];
  43. char linkflag;
  44. char linkname[Namsiz];
  45. /* rest are defined by POSIX's ustar format; see p1003.2b */
  46. char magic[6]; /* "ustar" */
  47. char version[2];
  48. char uname[32];
  49. char gname[32];
  50. char devmajor[8];
  51. char devminor[8];
  52. char prefix[Maxpfx]; /* if non-null, path= prefix "/" name */
  53. };
  54. } Hdr;
  55. Hdr dblock;
  56. int tapefile;
  57. int checksum(void);
  58. static int
  59. isustar(Hdr *hp)
  60. {
  61. return strcmp(hp->magic, "ustar") == 0;
  62. }
  63. /*
  64. * s is at most n bytes long, but need not be NUL-terminated.
  65. * if shorter than n bytes, all bytes after the first NUL must also
  66. * be NUL.
  67. */
  68. static int
  69. strnlen(char *s, int n)
  70. {
  71. return s[n - 1] != '\0'? n: strlen(s);
  72. }
  73. /* set fullname from header */
  74. static char *
  75. tarname(Hdr *hp)
  76. {
  77. int pfxlen, namlen;
  78. static char fullname[Maxname+1];
  79. namlen = strnlen(hp->name, sizeof hp->name);
  80. if (hp->prefix[0] == '\0' || !isustar(hp)) { /* old-style name? */
  81. memmove(fullname, hp->name, namlen);
  82. fullname[namlen] = '\0';
  83. return fullname;
  84. }
  85. /* posix name: name is in two pieces */
  86. pfxlen = strnlen(hp->prefix, sizeof hp->prefix);
  87. memmove(fullname, hp->prefix, pfxlen);
  88. fullname[pfxlen] = '/';
  89. memmove(fullname + pfxlen + 1, hp->name, namlen);
  90. fullname[pfxlen + 1 + namlen] = '\0';
  91. return fullname;
  92. }
  93. void
  94. populate(char *name)
  95. {
  96. long chksum, linkflg;
  97. vlong blkno;
  98. char *fname;
  99. Fileinf f;
  100. Hdr *hp;
  101. tapefile = open(name, OREAD);
  102. if (tapefile < 0)
  103. error("Can't open argument file");
  104. replete = 1;
  105. hp = &dblock;
  106. for (blkno = 0; ; blkno++) {
  107. seek(tapefile, Tblock*blkno, 0);
  108. if (readn(tapefile, hp->dummy, sizeof hp->dummy) < sizeof hp->dummy)
  109. break;
  110. fname = tarname(hp);
  111. if (fname[0] == '\0')
  112. break;
  113. /* crack header */
  114. f.addr = blkno + 1;
  115. f.mode = strtoul(hp->mode, 0, 8);
  116. f.uid = strtoul(hp->uid, 0, 8);
  117. f.gid = strtoul(hp->gid, 0, 8);
  118. if((uchar)hp->size[0] == 0x80)
  119. f.size = b8byte(hp->size+3);
  120. else
  121. f.size = strtoull(hp->size, 0, 8);
  122. f.mdate = strtoul(hp->mtime, 0, 8);
  123. chksum = strtoul(hp->chksum, 0, 8);
  124. /* the mode test is ugly but sometimes necessary */
  125. if (hp->linkflag == LF_DIR || (f.mode&0170000) == 040000 ||
  126. strrchr(fname, '\0')[-1] == '/'){
  127. f.mode |= DMDIR;
  128. f.size = 0;
  129. }
  130. f.mode &= DMDIR | 0777;
  131. /* make file name safe, canonical and free of . and .. */
  132. while (fname[0] == '/') /* don't allow absolute paths */
  133. ++fname;
  134. cleanname(fname);
  135. while (strncmp(fname, "../", 3) == 0)
  136. fname += 3;
  137. /* reject links */
  138. linkflg = hp->linkflag == LF_SYMLINK1 ||
  139. hp->linkflag == LF_SYMLINK2 || hp->linkflag == LF_LINK;
  140. if (chksum != checksum()){
  141. fprint(2, "%s: bad checksum on %.28s at offset %lld\n",
  142. argv0, fname, Tblock*blkno);
  143. exits("checksum");
  144. }
  145. if (linkflg) {
  146. /*fprint(2, "link %s->%s skipped\n", fname, hp->linkname);*/
  147. f.size = 0;
  148. } else {
  149. /* accept this file */
  150. f.name = fname;
  151. if (f.name[0] == '\0')
  152. fprint(2, "%s: null name skipped\n", argv0);
  153. else
  154. poppath(f, 1);
  155. blkno += (f.size + Tblock - 1)/Tblock;
  156. }
  157. }
  158. }
  159. void
  160. dotrunc(Ram *r)
  161. {
  162. USED(r);
  163. }
  164. void
  165. docreate(Ram *r)
  166. {
  167. USED(r);
  168. }
  169. char *
  170. doread(Ram *r, vlong off, long cnt)
  171. {
  172. int n;
  173. seek(tapefile, Tblock*r->addr + off, 0);
  174. if (cnt > sizeof dblock.tbuf)
  175. error("read too big");
  176. n = readn(tapefile, dblock.tbuf, cnt);
  177. if (n != cnt)
  178. memset(dblock.tbuf + n, 0, cnt - n);
  179. return dblock.tbuf;
  180. }
  181. void
  182. popdir(Ram *r)
  183. {
  184. USED(r);
  185. }
  186. void
  187. dowrite(Ram *r, char *buf, long off, long cnt)
  188. {
  189. USED(r); USED(buf); USED(off); USED(cnt);
  190. }
  191. int
  192. dopermw(Ram *r)
  193. {
  194. USED(r);
  195. return 0;
  196. }
  197. int
  198. checksum(void)
  199. {
  200. int i, n;
  201. uchar *cp;
  202. memset(dblock.chksum, ' ', sizeof dblock.chksum);
  203. cp = (uchar *)dblock.dummy;
  204. i = 0;
  205. for (n = Tblock; n-- > 0; )
  206. i += *cp++;
  207. return i;
  208. }