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