shithub: riscv

Download patch

ref: 1132d1b9df4c9ea2b857fa9778fe6762cd81ded8
parent: 3d052eb2ea48a7ab6e0169077a3f5b133c7121df
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Thu Mar 16 20:45:48 EDT 2017

tapefs: handle more cpio formats (thanks qrstuv)

--- a/sys/man/4/tapefs
+++ b/sys/man/4/tapefs
@@ -61,10 +61,7 @@
 .I Cpiofs
 interprets
 .B cpio
-tape images (constructed with
-.BI cpio 's
-.B c
-flag).
+tape images.
 .PP
 .I Tarfs
 interprets
--- a/sys/src/cmd/tapefs/cpiofs.c
+++ b/sys/src/cmd/tapefs/cpiofs.c
@@ -1,7 +1,6 @@
 #include <u.h>
 #include <libc.h>
-#include <auth.h>
-#include <fcall.h>
+#include <bio.h>
 #include "tapefs.h"
 
 /*
@@ -8,93 +7,223 @@
  * 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");
-	replete = 1;
-	for (offset = 0;;) {
-		seek(tapefile, offset, 0);
-		if (read(tapefile, (char *)&dblock.dbuf, TBLOCK)<TBLOCK)
+	/* 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(;;) {
+		/* 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;
-		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)
-			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 @@
 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;
 }