2 * File system for tar archives (read-only)
11 /* fundamental constants */
15 Maxpfx = 155, /* from POSIX */
16 Maxname = Namsiz + 1 + Maxpfx,
18 Binsize = 0x80, /* flag in size[0], from gnu: positive binary size */
19 Binnegsz = 0xff, /* flag in size[0]: negative binary size */
22 /* POSIX link flags */
28 LF_SYMLINK2 = 's', /* 4BSD used this */
35 /* 'A' - 'Z' are reserved for custom implementations */
37 LF_LONGNAME = 'L', /* GNU extension */
54 char linkname[Namsiz];
56 /* rest are defined by POSIX's ustar format; see p1003.2b */
57 char magic[6]; /* "ustar" */
63 char prefix[Maxpfx]; /* if non-null, path= prefix "/" name */
75 return strcmp(hp->magic, "ustar") == 0;
79 * s is at most n bytes long, but need not be NUL-terminated.
80 * if shorter than n bytes, all bytes after the first NUL must also
84 strnlen(char *s, int n)
86 return s[n - 1] != '\0'? n: strlen(s);
89 /* set fullname from header */
94 static char fullname[Maxname+1];
96 namlen = strnlen(hp->name, sizeof hp->name);
97 if (hp->prefix[0] == '\0' || !isustar(hp)) { /* old-style name? */
98 memmove(fullname, hp->name, namlen);
99 fullname[namlen] = '\0';
103 /* posix name: name is in two pieces */
104 pfxlen = strnlen(hp->prefix, sizeof hp->prefix);
105 memmove(fullname, hp->prefix, pfxlen);
106 fullname[pfxlen] = '/';
107 memmove(fullname + pfxlen + 1, hp->name, namlen);
108 fullname[pfxlen + 1 + namlen] = '\0';
115 char longname[Maxlongname+1];
116 char *nextname = nil;
117 long chksum, linkflg, namelen;
123 tapefile = open(name, OREAD);
125 error("Can't open argument file");
128 for (blkno = 0; ; blkno++) {
129 seek(tapefile, Tblock*blkno, 0);
130 if (readn(tapefile, hp->dummy, sizeof hp->dummy) < sizeof hp->dummy)
132 fname = nextname, nextname = nil;
133 if(fname == nil || fname[0] == '\0')
135 if (fname[0] == '\0')
140 f.mode = strtoul(hp->mode, 0, 8);
141 f.uid = strtoul(hp->uid, 0, 8);
142 f.gid = strtoul(hp->gid, 0, 8);
143 if((uchar)hp->size[0] == 0x80)
144 f.size = b8byte(hp->size+3);
146 f.size = strtoull(hp->size, 0, 8);
147 f.mdate = strtoul(hp->mtime, 0, 8);
148 chksum = strtoul(hp->chksum, 0, 8);
149 /* the mode test is ugly but sometimes necessary */
150 if (hp->linkflag == LF_DIR || (f.mode&0170000) == 040000 ||
151 strrchr(fname, '\0')[-1] == '/'){
155 f.mode &= DMDIR | 0777;
157 /* make file name safe, canonical and free of . and .. */
158 while (fname[0] == '/') /* don't allow absolute paths */
161 while (strncmp(fname, "../", 3) == 0)
165 linkflg = hp->linkflag == LF_SYMLINK1 ||
166 hp->linkflag == LF_SYMLINK2 || hp->linkflag == LF_LINK;
167 if (chksum != checksum()){
168 fprint(2, "%s: bad checksum on %.28s at offset %lld\n",
169 argv0, fname, Tblock*blkno);
173 /*fprint(2, "link %s->%s skipped\n", fname, hp->linkname);*/
175 } else if (hp->linkflag == LF_LONGLINK) {
177 } else if (hp->linkflag == LF_LONGNAME) {
178 namelen = Maxlongname;
181 namelen = readn(tapefile, longname, namelen);
182 if(namelen < 0) namelen = 0;
183 longname[namelen] = '\0';
186 /* accept this file */
188 if (f.name[0] == '\0')
189 fprint(2, "%s: null name skipped\n", argv0);
193 blkno += (f.size + Tblock - 1)/Tblock;
210 doread(Ram *r, vlong off, long cnt)
214 seek(tapefile, Tblock*r->addr + off, 0);
215 if (cnt > sizeof dblock.tbuf)
216 error("read too big");
217 n = readn(tapefile, dblock.tbuf, cnt);
219 memset(dblock.tbuf + n, 0, cnt - n);
230 dowrite(Ram *r, char *buf, long off, long cnt)
232 USED(r); USED(buf); USED(off); USED(cnt);
248 memset(dblock.chksum, ' ', sizeof dblock.chksum);
249 cp = (uchar *)dblock.dummy;
251 for (n = Tblock; n-- > 0; )