]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/tapefs/cpiofs.c
cc: use 7 octal digits for 21 bit runes
[plan9front.git] / sys / src / cmd / tapefs / cpiofs.c
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include "tapefs.h"
5
6 /*
7  * File system for cpio tapes (read-only)
8  */
9
10 union hblock {
11         char tbuf[Maxbuf];
12 } dblock;
13
14 typedef  void HdrReader(Fileinf *);
15
16 Biobuf  *tape;
17
18 static void
19 addrfatal(char *fmt, va_list arg)
20 {
21         char buf[1024];
22
23         vseprint(buf, buf+sizeof(buf), fmt, arg);
24         fprint(2, "%s: %#llx: %s\n", argv0, Bseek(tape, 0, 1), buf);
25         exits(buf);
26 }
27
28 static int
29 egetc(void)
30 {
31         int c;
32
33         if((c = Bgetc(tape)) == Beof)
34                 sysfatal("unexpected eof");
35         if(c < 0)
36                 sysfatal("read error: %r");
37         return c;
38 }
39
40 static ushort
41 rd16le()
42 {
43         ushort x;
44
45         return x = egetc(), x |= egetc()<<8;
46 }
47
48 static ulong
49 rd3211()
50 {
51         ulong x;
52
53         return x = egetc()<<16, x |= egetc()<<24, x |= egetc(), x |= egetc()<<8;
54 }
55
56 /* sysvr3 and sysvr4 skip records with names longer than 256. pwb 1.0,
57 32V, sysiii, sysvr1, and sysvr2 overrun their 256 byte buffer */
58 static void
59 rdpwb(Fileinf *f, ushort (*rd16)(void), ulong (*rd32)(void))
60 {
61         int namesz, n;
62         static char buf[256];
63
64         rd16(); /* dev */
65         rd16(); /* ino */
66         f->mode = rd16();
67         f->uid = rd16();
68         f->gid = rd16();
69         rd16(); /* nlink */
70         rd16(); /* rdev */
71         f->mdate = rd32();
72         namesz = rd16();
73         f->size = rd32();
74
75         /* namesz include the trailing nul */
76         if(namesz == 0)
77                 sysfatal("name too small");
78         if(namesz > sizeof(buf))
79                 sysfatal("name too big");
80
81         if((n = Bread(tape, buf, namesz)) < 0)
82                 sysfatal("read error: %r");
83         if(n < namesz)
84                 sysfatal("unexpected eof");
85
86         if(buf[n-1] != '\0')
87                 sysfatal("no nul after file name");
88         if((n = strlen(buf)) != namesz-1)
89                 sysfatal("mismatched name length: saw %d; expected %d", n, namesz-1);
90         f->name = buf;
91
92         /* skip padding */
93         if(Bseek(tape, 0, 1) & 1)
94                 egetc();
95 }
96
97 static void
98 rdpwb11(Fileinf *f)
99 {
100         rdpwb(f, rd16le, rd3211);
101 }
102
103 static vlong
104 rdasc(int n)
105 {
106         vlong x;
107         int y;
108
109         for(x = 0; n > 0; n--) {
110                 if((y = egetc() - '0') & ~7)
111                         sysfatal("not octal");
112                 x = x<<3 | y;
113         }
114         return x;
115 }
116
117 /* sysvr3 and sysvr4 skip records with names longer than 256. sysiii,
118 sysvr1, and sysvr2 overrun their 256 byte buffer */
119 static void
120 rdsysiii(Fileinf *f)
121 {
122         int namesz, n;
123         static char buf[256];
124
125         rdasc(6);       /* dev */
126         rdasc(6);       /* ino */
127         f->mode = rdasc(6);
128         f->uid = rdasc(6);
129         f->gid = rdasc(6);
130         rdasc(6);       /* nlink */
131         rdasc(6);       /* rdev */
132         f->mdate = rdasc(11);
133         namesz = rdasc(6);
134         f->size = rdasc(11);
135
136         /* namesz includes the trailing nul */
137         if(namesz == 0)
138                 sysfatal("name too small");
139         if(namesz > sizeof (buf))
140                 sysfatal("name too big");
141
142         if((n = Bread(tape, buf, namesz)) < 0)
143                 sysfatal("read error: %r");
144         if(n < namesz)
145                 sysfatal("unexpected eof");
146
147         if(buf[n-1] != '\0')
148                 sysfatal("no nul after file name");
149         if((n = strlen(buf)) != namesz-1)
150                 sysfatal("mismatched name length: saw %d; expected %d", n, namesz-1);
151         f->name = buf;
152 }
153
154 static HdrReader *
155 rdmagic(void)
156 {
157         uchar buf[6];
158
159         buf[0] = egetc();
160         buf[1] = egetc();
161         if(buf[0] == 0xc7 && buf[1] == 0x71)
162                 return rdpwb11;
163
164         buf[2] = egetc();
165         buf[3] = egetc();
166         buf[4] = egetc();
167         buf[5] = egetc();
168         if(memcmp(buf, "070707", 6) == 0)
169                 return rdsysiii;
170
171         sysfatal("Out of phase--get MERT help");
172         return nil;
173 }
174
175 void
176 populate(char *name)
177 {
178         HdrReader *rdhdr, *prevhdr;
179         Fileinf f;
180
181         /* the tape buffer may not be the ideal size for scanning the
182         record headers */
183         if((tape = Bopen(name, OREAD)) == nil)
184                 sysfatal("Can't open argument file");
185
186         extern void (*_sysfatal)(char *, va_list);
187         _sysfatal = addrfatal;
188
189         prevhdr = nil;
190         replete = 1;
191         for(;;) {
192                 /* sysiii and sysv implementations don't allow
193                 multiple header types within a single tape, so we
194                 won't either */
195                 rdhdr = rdmagic();
196                 if(prevhdr != nil && rdhdr != prevhdr)
197                         sysfatal("mixed headers");
198                 rdhdr(&f);
199
200                 while(f.name[0] == '/')
201                         f.name++;
202                 if(f.name[0] == '\0')
203                         sysfatal("nameless record");
204                 if(strcmp(f.name, "TRAILER!!!") == 0)
205                         break;
206                 switch(f.mode & 0170000) {
207                 case 0040000:
208                         f.mode = DMDIR | f.mode&0777;
209                         break;
210                 case 0100000:   /* normal file */
211                 case 0120000:   /* symlink */
212                         f.mode &= 0777;
213                         break;
214                 default:        /* sockets, pipes, devices */
215                         f.mode = 0;
216                         break;
217                 }
218                 f.addr = Bseek(tape, 0, 1);
219                 poppath(f, 1);
220
221                 Bseek(tape, f.size, 1);
222
223                 /* skip padding */
224                 if(rdhdr == rdpwb11 && (Bseek(tape, 0, 1) & 1))
225                         egetc();
226         }
227 }
228
229 void
230 dotrunc(Ram *r)
231 {
232         USED(r);
233 }
234
235 void
236 docreate(Ram *r)
237 {
238         USED(r);
239 }
240
241 char *
242 doread(Ram *r, vlong off, long cnt)
243 {
244         Bseek(tape, r->addr+off, 0);
245         if (cnt>sizeof(dblock.tbuf))
246                 sysfatal("read too big");
247         Bread(tape, dblock.tbuf, cnt);
248         return dblock.tbuf;
249 }
250
251 void
252 popdir(Ram *r)
253 {
254         USED(r);
255 }
256
257 void
258 dowrite(Ram *r, char *buf, long off, long cnt)
259 {
260         USED(r); USED(buf); USED(off); USED(cnt);
261 }
262
263 int
264 dopermw(Ram *r)
265 {
266         USED(r);
267         return 0;
268 }