]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/tapefs/tarfs.c
cc: fix void cast crash
[plan9front.git] / sys / src / cmd / tapefs / tarfs.c
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         Maxlongname = 65535,
18         Binsize = 0x80,         /* flag in size[0], from gnu: positive binary size */
19         Binnegsz = 0xff,        /* flag in size[0]: negative binary size */
20 };
21
22 /* POSIX link flags */
23 enum {
24         LF_PLAIN1 =     '\0',
25         LF_PLAIN2 =     '0',
26         LF_LINK =       '1',
27         LF_SYMLINK1 =   '2',
28         LF_SYMLINK2 =   's',            /* 4BSD used this */
29         LF_CHR =        '3',
30         LF_BLK =        '4',
31         LF_DIR =        '5',
32         LF_FIFO =       '6',
33         LF_CONTIG =     '7',
34
35         /* 'A' - 'Z' are reserved for custom implementations */
36
37         LF_LONGNAME =   'L',            /* GNU extension */
38         LF_LONGLINK =   'K',
39
40 };
41
42 typedef union {
43         char    dummy[Tblock];
44         char    tbuf[Maxbuf];
45         struct Header {
46                 char    name[Namsiz];
47                 char    mode[8];
48                 char    uid[8];
49                 char    gid[8];
50                 char    size[12];
51                 char    mtime[12];
52                 char    chksum[8];
53                 char    linkflag;
54                 char    linkname[Namsiz];
55
56                 /* rest are defined by POSIX's ustar format; see p1003.2b */
57                 char    magic[6];       /* "ustar" */
58                 char    version[2];
59                 char    uname[32];
60                 char    gname[32];
61                 char    devmajor[8];
62                 char    devminor[8];
63                 char    prefix[Maxpfx]; /* if non-null, path= prefix "/" name */
64         };
65 } Hdr;
66
67 Hdr dblock;
68 int tapefile;
69
70 int     checksum(void);
71
72 static int
73 isustar(Hdr *hp)
74 {
75         return strcmp(hp->magic, "ustar") == 0;
76 }
77
78 /*
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
81  * be NUL.
82  */
83 static int
84 strnlen(char *s, int n)
85 {
86         return s[n - 1] != '\0'? n: strlen(s);
87 }
88
89 /* set fullname from header */
90 static char *
91 tarname(Hdr *hp)
92 {
93         int pfxlen, namlen;
94         static char fullname[Maxname+1];
95
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';
100                 return fullname;
101         }
102
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';
109         return fullname;
110 }
111
112 void
113 populate(char *name)
114 {
115         char longname[Maxlongname+1];
116         char *nextname = nil;
117         long chksum, linkflg, namelen;
118         vlong blkno;
119         char *fname;
120         Fileinf f;
121         Hdr *hp;
122
123         tapefile = open(name, OREAD);
124         if (tapefile < 0)
125                 error("Can't open argument file");
126         replete = 1;
127         hp = &dblock;
128         for (blkno = 0; ; blkno++) {
129                 seek(tapefile, Tblock*blkno, 0);
130                 if (readn(tapefile, hp->dummy, sizeof hp->dummy) < sizeof hp->dummy)
131                         break;
132                 fname = nextname, nextname = nil;
133                 if(fname == nil || fname[0] == '\0')
134                         fname = tarname(hp);
135                 if (fname[0] == '\0')
136                         break;
137
138                 /* crack header */
139                 f.addr = blkno + 1;
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);
145                 else
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] == '/'){
152                         f.mode |= DMDIR;
153                         f.size = 0;
154                 }
155                 f.mode &= DMDIR | 0777;
156
157                 /* make file name safe, canonical and free of . and .. */
158                 while (fname[0] == '/')         /* don't allow absolute paths */
159                         ++fname;
160                 cleanname(fname);
161                 while (strncmp(fname, "../", 3) == 0)
162                         fname += 3;
163
164                 /* reject links */
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);
170                         exits("checksum");
171                 }
172                 if (linkflg) {
173                         /*fprint(2, "link %s->%s skipped\n", fname, hp->linkname);*/
174                         f.size = 0;
175                 } else if (hp->linkflag == LF_LONGLINK) {
176                         ;
177                 } else if (hp->linkflag == LF_LONGNAME) {
178                         namelen = Maxlongname;
179                         if(f.size < namelen)
180                                 namelen = f.size;
181                         namelen = readn(tapefile, longname, namelen);
182                         if(namelen < 0) namelen = 0;
183                         longname[namelen] = '\0';
184                         nextname = longname;
185                 } else {
186                         /* accept this file */
187                         f.name = fname;
188                         if (f.name[0] == '\0')
189                                 fprint(2, "%s: null name skipped\n", argv0);
190                         else
191                                 poppath(f, 1);
192                 }
193                 blkno += (f.size + Tblock - 1)/Tblock;
194         }
195 }
196
197 void
198 dotrunc(Ram *r)
199 {
200         USED(r);
201 }
202
203 void
204 docreate(Ram *r)
205 {
206         USED(r);
207 }
208
209 char *
210 doread(Ram *r, vlong off, long cnt)
211 {
212         int n;
213
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);
218         if (n != cnt)
219                 memset(dblock.tbuf + n, 0, cnt - n);
220         return dblock.tbuf;
221 }
222
223 void
224 popdir(Ram *r)
225 {
226         USED(r);
227 }
228
229 void
230 dowrite(Ram *r, char *buf, long off, long cnt)
231 {
232         USED(r); USED(buf); USED(off); USED(cnt);
233 }
234
235 int
236 dopermw(Ram *r)
237 {
238         USED(r);
239         return 0;
240 }
241
242 int
243 checksum(void)
244 {
245         int i, n;
246         uchar *cp;
247
248         memset(dblock.chksum, ' ', sizeof dblock.chksum);
249         cp = (uchar *)dblock.dummy;
250         i = 0;
251         for (n = Tblock; n-- > 0; )
252                 i += *cp++;
253         return i;
254 }