diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2017-03-17 00:45:48 +0100 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2017-03-17 00:45:48 +0100 |
commit | 1132d1b9df4c9ea2b857fa9778fe6762cd81ded8 (patch) | |
tree | 3102d928ed05d388b6a8257a0d6ca562976483b2 /sys/src/cmd/tapefs | |
parent | 3d052eb2ea48a7ab6e0169077a3f5b133c7121df (diff) |
tapefs: handle more cpio formats (thanks qrstuv)
Diffstat (limited to 'sys/src/cmd/tapefs')
-rw-r--r-- | sys/src/cmd/tapefs/cpiofs.c | 269 |
1 files changed, 199 insertions, 70 deletions
diff --git a/sys/src/cmd/tapefs/cpiofs.c b/sys/src/cmd/tapefs/cpiofs.c index fc11346db..591c80f1d 100644 --- a/sys/src/cmd/tapefs/cpiofs.c +++ b/sys/src/cmd/tapefs/cpiofs.c @@ -1,100 +1,229 @@ #include <u.h> #include <libc.h> -#include <auth.h> -#include <fcall.h> +#include <bio.h> #include "tapefs.h" /* * File system for cpio tapes (read-only) */ -#define TBLOCK 512 -#define NBLOCK 40 /* maximum blocksize */ -#define DBLOCK 20 /* default blocksize */ -#define TNAMSIZ 100 - union hblock { - char dummy[TBLOCK]; char tbuf[Maxbuf]; - struct header { - char magic[6]; - char dev[6]; - char ino[6]; - char mode[6]; - char uid[6]; - char gid[6]; - char nlink[6]; - char rdev[6]; - char mtime[11]; - char namesize[6]; - char size[11]; - } dbuf; - struct hname { - struct header x; - char name[1]; - } nbuf; } dblock; -int tapefile; -vlong getoct(char*, int); +typedef void HdrReader(Fileinf *); + +Biobuf *tape; + +static void +addrfatal(char *fmt, va_list arg) +{ + char buf[1024]; + + vseprint(buf, buf+sizeof(buf), fmt, arg); + fprint(2, "%s: %#llx: %s\n", argv0, Bseek(tape, 0, 1), buf); + exits(buf); +} + +static int +egetc(void) +{ + int c; + + if((c = Bgetc(tape)) == Beof) + sysfatal("unexpected eof"); + if(c < 0) + sysfatal("read error: %r"); + return c; +} + +static ushort +rd16le() +{ + ushort x; + + return x = egetc(), x |= egetc()<<8; +} + +static ulong +rd3211() +{ + ulong x; + + return x = egetc()<<16, x |= egetc()<<24, x |= egetc(), x |= egetc()<<8; +} + +/* sysvr3 and sysvr4 skip records with names longer than 256. pwb 1.0, +32V, sysiii, sysvr1, and sysvr2 overrun their 256 byte buffer */ +static void +rdpwb(Fileinf *f, ushort (*rd16)(void), ulong (*rd32)(void)) +{ + int namesz, n; + static char buf[256]; + + rd16(); /* dev */ + rd16(); /* ino */ + f->mode = rd16(); + f->uid = rd16(); + f->gid = rd16(); + rd16(); /* nlink */ + rd16(); /* rdev */ + f->mdate = rd32(); + namesz = rd16(); + f->size = rd32(); + + /* namesz include the trailing nul */ + if(namesz == 0) + sysfatal("name too small"); + if(namesz > sizeof(buf)) + sysfatal("name too big"); + + if((n = Bread(tape, buf, namesz)) < 0) + sysfatal("read error: %r"); + if(n < namesz) + sysfatal("unexpected eof"); + + if(buf[n-1] != '\0') + sysfatal("no nul after file name"); + if((n = strlen(buf)) != namesz-1) + sysfatal("mismatched name length: saw %d; expected %d", n, namesz-1); + f->name = buf; + + /* skip padding */ + if(Bseek(tape, 0, 1) & 1) + egetc(); +} + +static void +rdpwb11(Fileinf *f) +{ + rdpwb(f, rd16le, rd3211); +} + +static vlong +rdasc(int n) +{ + vlong x; + int y; + + for(x = 0; n > 0; n--) { + if((y = egetc() - '0') & ~7) + sysfatal("not octal"); + x = x<<3 | y; + } + return x; +} + +/* sysvr3 and sysvr4 skip records with names longer than 256. sysiii, +sysvr1, and sysvr2 overrun their 256 byte buffer */ +static void +rdsysiii(Fileinf *f) +{ + int namesz, n; + static char buf[256]; + + rdasc(6); /* dev */ + rdasc(6); /* ino */ + f->mode = rdasc(6); + f->uid = rdasc(6); + f->gid = rdasc(6); + rdasc(6); /* nlink */ + rdasc(6); /* rdev */ + f->mdate = rdasc(11); + namesz = rdasc(6); + f->size = rdasc(11); + + /* namesz includes the trailing nul */ + if(namesz == 0) + sysfatal("name too small"); + if(namesz > sizeof (buf)) + sysfatal("name too big"); + + if((n = Bread(tape, buf, namesz)) < 0) + sysfatal("read error: %r"); + if(n < namesz) + sysfatal("unexpected eof"); + + if(buf[n-1] != '\0') + sysfatal("no nul after file name"); + if((n = strlen(buf)) != namesz-1) + sysfatal("mismatched name length: saw %d; expected %d", n, namesz-1); + f->name = buf; +} + +static HdrReader * +rdmagic(void) +{ + uchar buf[6]; + + buf[0] = egetc(); + buf[1] = egetc(); + if(buf[0] == 0xc7 && buf[1] == 0x71) + return rdpwb11; + + buf[2] = egetc(); + buf[3] = egetc(); + buf[4] = egetc(); + buf[5] = egetc(); + if(memcmp(buf, "070707", 6) == 0) + return rdsysiii; + + sysfatal("Out of phase--get MERT help"); + return nil; +} void populate(char *name) { - vlong offset; - long isabs, magic, namesize, mode; + HdrReader *rdhdr, *prevhdr; Fileinf f; - tapefile = open(name, OREAD); - if (tapefile<0) - error("Can't open argument file"); + /* the tape buffer may not be the ideal size for scanning the + record headers */ + if((tape = Bopen(name, OREAD)) == nil) + sysfatal("Can't open argument file"); + + extern void (*_sysfatal)(char *, va_list); + _sysfatal = addrfatal; + + prevhdr = nil; replete = 1; - for (offset = 0;;) { - seek(tapefile, offset, 0); - if (read(tapefile, (char *)&dblock.dbuf, TBLOCK)<TBLOCK) - break; - magic = getoct(dblock.dbuf.magic, sizeof(dblock.dbuf.magic)); - if (magic != 070707){ - print("%lo\n", magic); - error("out of phase--get help"); - } - if (dblock.nbuf.name[0]=='\0' || strcmp(dblock.nbuf.name, "TRAILER!!!")==0) + for(;;) { + /* sysiii and sysv implementations don't allow + multiple header types within a single tape, so we + won't either */ + rdhdr = rdmagic(); + if(prevhdr != nil && rdhdr != prevhdr) + sysfatal("mixed headers"); + rdhdr(&f); + + while(f.name[0] == '/') + f.name++; + if(f.name[0] == '\0') + sysfatal("nameless record"); + if(strcmp(f.name, "TRAILER!!!") == 0) break; - mode = getoct(dblock.dbuf.mode, sizeof(dblock.dbuf.mode)); - f.mode = mode&0777; - switch(mode & 0170000) { + switch(f.mode & 0170000) { case 0040000: - f.mode |= DMDIR; + f.mode = DMDIR | f.mode&0777; break; - case 0100000: + case 0100000: /* normal file */ + case 0120000: /* symlink */ + f.mode &= 0777; break; - default: + default: /* sockets, pipes, devices */ f.mode = 0; break; } - f.uid = getoct(dblock.dbuf.uid, sizeof(dblock.dbuf.uid)); - f.gid = getoct(dblock.dbuf.gid, sizeof(dblock.dbuf.gid)); - f.size = getoct(dblock.dbuf.size, sizeof(dblock.dbuf.size)); - f.mdate = getoct(dblock.dbuf.mtime, sizeof(dblock.dbuf.mtime)); - namesize = getoct(dblock.dbuf.namesize, sizeof(dblock.dbuf.namesize)); - f.addr = offset+sizeof(struct header)+namesize; - isabs = dblock.nbuf.name[0]=='/'; - f.name = &dblock.nbuf.name[isabs]; + f.addr = Bseek(tape, 0, 1); poppath(f, 1); - offset += sizeof(struct header)+namesize+f.size; - } -} -vlong -getoct(char *p, int l) -{ - vlong r; + Bseek(tape, f.size, 1); - for (r=0; l>0; p++, l--){ - r <<= 3; - r += *p-'0'; + /* skip padding */ + if(rdhdr == rdpwb11 && (Bseek(tape, 0, 1) & 1)) + egetc(); } - return r; } void @@ -112,10 +241,10 @@ docreate(Ram *r) char * doread(Ram *r, vlong off, long cnt) { - seek(tapefile, r->addr+off, 0); + Bseek(tape, r->addr+off, 0); if (cnt>sizeof(dblock.tbuf)) - error("read too big"); - read(tapefile, dblock.tbuf, cnt); + sysfatal("read too big"); + Bread(tape, dblock.tbuf, cnt); return dblock.tbuf; } |