tapefs: handle more cpio formats (thanks qrstuv)
This commit is contained in:
parent
3d052eb2ea
commit
1132d1b9df
2 changed files with 200 additions and 74 deletions
|
@ -61,10 +61,7 @@ the VAX (512 byte block size, the default), and also pre-FFS Berkeley VAX system
|
||||||
.I Cpiofs
|
.I Cpiofs
|
||||||
interprets
|
interprets
|
||||||
.B cpio
|
.B cpio
|
||||||
tape images (constructed with
|
tape images.
|
||||||
.BI cpio 's
|
|
||||||
.B c
|
|
||||||
flag).
|
|
||||||
.PP
|
.PP
|
||||||
.I Tarfs
|
.I Tarfs
|
||||||
interprets
|
interprets
|
||||||
|
|
|
@ -1,100 +1,229 @@
|
||||||
#include <u.h>
|
#include <u.h>
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include <auth.h>
|
#include <bio.h>
|
||||||
#include <fcall.h>
|
|
||||||
#include "tapefs.h"
|
#include "tapefs.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* File system for cpio tapes (read-only)
|
* 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 {
|
union hblock {
|
||||||
char dummy[TBLOCK];
|
|
||||||
char tbuf[Maxbuf];
|
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;
|
} dblock;
|
||||||
|
|
||||||
int tapefile;
|
typedef void HdrReader(Fileinf *);
|
||||||
vlong getoct(char*, int);
|
|
||||||
|
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
|
void
|
||||||
populate(char *name)
|
populate(char *name)
|
||||||
{
|
{
|
||||||
vlong offset;
|
HdrReader *rdhdr, *prevhdr;
|
||||||
long isabs, magic, namesize, mode;
|
|
||||||
Fileinf f;
|
Fileinf f;
|
||||||
|
|
||||||
tapefile = open(name, OREAD);
|
/* the tape buffer may not be the ideal size for scanning the
|
||||||
if (tapefile<0)
|
record headers */
|
||||||
error("Can't open argument file");
|
if((tape = Bopen(name, OREAD)) == nil)
|
||||||
|
sysfatal("Can't open argument file");
|
||||||
|
|
||||||
|
extern void (*_sysfatal)(char *, va_list);
|
||||||
|
_sysfatal = addrfatal;
|
||||||
|
|
||||||
|
prevhdr = nil;
|
||||||
replete = 1;
|
replete = 1;
|
||||||
for (offset = 0;;) {
|
for(;;) {
|
||||||
seek(tapefile, offset, 0);
|
/* sysiii and sysv implementations don't allow
|
||||||
if (read(tapefile, (char *)&dblock.dbuf, TBLOCK)<TBLOCK)
|
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;
|
break;
|
||||||
magic = getoct(dblock.dbuf.magic, sizeof(dblock.dbuf.magic));
|
switch(f.mode & 0170000) {
|
||||||
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)
|
|
||||||
break;
|
|
||||||
mode = getoct(dblock.dbuf.mode, sizeof(dblock.dbuf.mode));
|
|
||||||
f.mode = mode&0777;
|
|
||||||
switch(mode & 0170000) {
|
|
||||||
case 0040000:
|
case 0040000:
|
||||||
f.mode |= DMDIR;
|
f.mode = DMDIR | f.mode&0777;
|
||||||
break;
|
break;
|
||||||
case 0100000:
|
case 0100000: /* normal file */
|
||||||
|
case 0120000: /* symlink */
|
||||||
|
f.mode &= 0777;
|
||||||
break;
|
break;
|
||||||
default:
|
default: /* sockets, pipes, devices */
|
||||||
f.mode = 0;
|
f.mode = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
f.uid = getoct(dblock.dbuf.uid, sizeof(dblock.dbuf.uid));
|
f.addr = Bseek(tape, 0, 1);
|
||||||
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];
|
|
||||||
poppath(f, 1);
|
poppath(f, 1);
|
||||||
offset += sizeof(struct header)+namesize+f.size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vlong
|
Bseek(tape, f.size, 1);
|
||||||
getoct(char *p, int l)
|
|
||||||
{
|
|
||||||
vlong r;
|
|
||||||
|
|
||||||
for (r=0; l>0; p++, l--){
|
/* skip padding */
|
||||||
r <<= 3;
|
if(rdhdr == rdpwb11 && (Bseek(tape, 0, 1) & 1))
|
||||||
r += *p-'0';
|
egetc();
|
||||||
}
|
}
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -112,10 +241,10 @@ docreate(Ram *r)
|
||||||
char *
|
char *
|
||||||
doread(Ram *r, vlong off, long cnt)
|
doread(Ram *r, vlong off, long cnt)
|
||||||
{
|
{
|
||||||
seek(tapefile, r->addr+off, 0);
|
Bseek(tape, r->addr+off, 0);
|
||||||
if (cnt>sizeof(dblock.tbuf))
|
if (cnt>sizeof(dblock.tbuf))
|
||||||
error("read too big");
|
sysfatal("read too big");
|
||||||
read(tapefile, dblock.tbuf, cnt);
|
Bread(tape, dblock.tbuf, cnt);
|
||||||
return dblock.tbuf;
|
return dblock.tbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue