Browse Source

Plan 9 from Bell Labs 2006-02-27

David du Colombier 18 years ago
parent
commit
c0442b8dd4

+ 11 - 10
dist/replica/_plan9.db

@@ -94,7 +94,7 @@
 386/bin/aux/cropmarks - 775 sys sys 1020319062 1808
 386/bin/aux/data2s - 775 sys sys 1135570782 60518
 386/bin/aux/depend - 775 sys sys 1138500404 145864
-386/bin/aux/disksim - 775 sys sys 1139680589 150454
+386/bin/aux/disksim - 775 sys sys 1140976599 150655
 386/bin/aux/download - 775 sys sys 1087442506 176016
 386/bin/aux/faxreceive - 775 sys sys 1135570783 83923
 386/bin/aux/faxsend - 775 sys sys 1135570783 89435
@@ -417,7 +417,7 @@
 386/bin/swap - 775 sys sys 1135570847 62130
 386/bin/syscall - 775 sys sys 1130594788 73568
 386/bin/tail - 775 sys sys 1135570847 66163
-386/bin/tar - 775 sys sys 1138723507 93772
+386/bin/tar - 775 sys sys 1141012626 93114
 386/bin/tbl - 775 sys sys 1131302431 113308
 386/bin/tcs - 775 sys sys 1138393253 309719
 386/bin/tee - 775 sys sys 1130384340 38446
@@ -7615,7 +7615,7 @@ sys/man/4/rio - 664 sys sys 1023206844 8660
 sys/man/4/sacfs - 664 sys sys 964886843 907
 sys/man/4/snap - 664 sys sys 1017251244 1833
 sys/man/4/srv - 664 sys sys 1045236157 4649
-sys/man/4/tapefs - 664 sys sys 1107543772 1811
+sys/man/4/tapefs - 664 sys sys 1140965924 1861
 sys/man/4/telco - 664 sys sys 1015024814 4359
 sys/man/4/u9fs - 664 sys sys 1043769139 4748
 sys/man/4/upasfs - 664 sys sys 1034348505 6212
@@ -7697,6 +7697,7 @@ sys/man/8/checkarenas - 664 sys sys 1019866709 669
 sys/man/8/cpurc - 664 sys sys 971455510 1275
 sys/man/8/cron - 664 sys sys 1063858596 1867
 sys/man/8/dhcpd - 664 sys sys 1032654987 5237
+sys/man/8/disksim - 664 sys sys 1141009713 1452
 sys/man/8/drawterm - 664 sys sys 1135901219 1741
 sys/man/8/fossilcons - 664 sys sys 1138466274 18276
 sys/man/8/fs - 664 sys sys 1055701170 15029
@@ -9615,7 +9616,7 @@ sys/src/cmd/aux/consolefs.c - 664 sys sys 1134305455 20200
 sys/src/cmd/aux/conswdir.c - 664 sys sys 1045504955 2077
 sys/src/cmd/aux/data2s.c - 664 sys sys 1032059295 796
 sys/src/cmd/aux/depend.c - 664 sys sys 1134305455 25880
-sys/src/cmd/aux/disksim.c - 664 sys sys 1139667305 10919
+sys/src/cmd/aux/disksim.c - 664 sys sys 1140964826 11178
 sys/src/cmd/aux/flashfs - 20000000775 sys sys 1015009082 0
 sys/src/cmd/aux/flashfs/aux.c - 664 sys sys 1015009080 699
 sys/src/cmd/aux/flashfs/aux.h - 664 sys sys 1015009080 111
@@ -13301,20 +13302,20 @@ sys/src/cmd/syscall/mkfile - 664 sys sys 1037122264 549
 sys/src/cmd/syscall/syscall.c - 664 sys sys 1135487934 3951
 sys/src/cmd/tail.c - 664 sys sys 1123123922 6034
 sys/src/cmd/tapefs - 20000000775 sys sys 944962012 0
-sys/src/cmd/tapefs/32vfs.c - 664 sys sys 1140814623 3710
+sys/src/cmd/tapefs/32vfs.c - 664 sys sys 1140965787 3922
 sys/src/cmd/tapefs/cpiofs.c - 664 sys sys 1140814623 2491
-sys/src/cmd/tapefs/fs.c - 664 sys sys 1140814810 9754
+sys/src/cmd/tapefs/fs.c - 664 sys sys 1141003366 9887
 sys/src/cmd/tapefs/mkfile - 664 sys sys 1097914131 254
-sys/src/cmd/tapefs/tapefs.h - 664 sys sys 1140875580 1702
+sys/src/cmd/tapefs/tapefs.h - 664 sys sys 1140966413 1815
 sys/src/cmd/tapefs/tapfs.c - 664 sys sys 1140814624 1924
-sys/src/cmd/tapefs/tarfs.c - 664 sys sys 1140815766 2759
+sys/src/cmd/tapefs/tarfs.c - 664 sys sys 1141003342 2759
 sys/src/cmd/tapefs/tpfs.c - 664 sys sys 1140814810 1999
-sys/src/cmd/tapefs/util.c - 664 sys sys 1140814810 2699
+sys/src/cmd/tapefs/util.c - 664 sys sys 1140966088 2964
 sys/src/cmd/tapefs/v10fs.c - 664 sys sys 1140814624 3776
 sys/src/cmd/tapefs/v6fs.c - 664 sys sys 1140814625 3993
 sys/src/cmd/tapefs/zip.h - 664 sys sys 1097914153 1428
 sys/src/cmd/tapefs/zipfs.c - 664 sys sys 1140814625 6588
-sys/src/cmd/tar.c - 664 sys sys 1138711857 22453
+sys/src/cmd/tar.c - 664 sys sys 1141007861 24018
 sys/src/cmd/tbl - 20000000775 sys sys 954038038 0
 sys/src/cmd/tbl/mkfile - 664 sys sys 944961243 268
 sys/src/cmd/tbl/t.h - 664 sys sys 944961244 3987

+ 11 - 10
dist/replica/plan9.db

@@ -94,7 +94,7 @@
 386/bin/aux/cropmarks - 775 sys sys 1020319062 1808
 386/bin/aux/data2s - 775 sys sys 1135570782 60518
 386/bin/aux/depend - 775 sys sys 1138500404 145864
-386/bin/aux/disksim - 775 sys sys 1139680589 150454
+386/bin/aux/disksim - 775 sys sys 1140976599 150655
 386/bin/aux/download - 775 sys sys 1087442506 176016
 386/bin/aux/faxreceive - 775 sys sys 1135570783 83923
 386/bin/aux/faxsend - 775 sys sys 1135570783 89435
@@ -417,7 +417,7 @@
 386/bin/swap - 775 sys sys 1135570847 62130
 386/bin/syscall - 775 sys sys 1130594788 73568
 386/bin/tail - 775 sys sys 1135570847 66163
-386/bin/tar - 775 sys sys 1138723507 93772
+386/bin/tar - 775 sys sys 1141012626 93114
 386/bin/tbl - 775 sys sys 1131302431 113308
 386/bin/tcs - 775 sys sys 1138393253 309719
 386/bin/tee - 775 sys sys 1130384340 38446
@@ -7615,7 +7615,7 @@ sys/man/4/rio - 664 sys sys 1023206844 8660
 sys/man/4/sacfs - 664 sys sys 964886843 907
 sys/man/4/snap - 664 sys sys 1017251244 1833
 sys/man/4/srv - 664 sys sys 1045236157 4649
-sys/man/4/tapefs - 664 sys sys 1107543772 1811
+sys/man/4/tapefs - 664 sys sys 1140965924 1861
 sys/man/4/telco - 664 sys sys 1015024814 4359
 sys/man/4/u9fs - 664 sys sys 1043769139 4748
 sys/man/4/upasfs - 664 sys sys 1034348505 6212
@@ -7697,6 +7697,7 @@ sys/man/8/checkarenas - 664 sys sys 1019866709 669
 sys/man/8/cpurc - 664 sys sys 971455510 1275
 sys/man/8/cron - 664 sys sys 1063858596 1867
 sys/man/8/dhcpd - 664 sys sys 1032654987 5237
+sys/man/8/disksim - 664 sys sys 1141009713 1452
 sys/man/8/drawterm - 664 sys sys 1135901219 1741
 sys/man/8/fossilcons - 664 sys sys 1138466274 18276
 sys/man/8/fs - 664 sys sys 1055701170 15029
@@ -9615,7 +9616,7 @@ sys/src/cmd/aux/consolefs.c - 664 sys sys 1134305455 20200
 sys/src/cmd/aux/conswdir.c - 664 sys sys 1045504955 2077
 sys/src/cmd/aux/data2s.c - 664 sys sys 1032059295 796
 sys/src/cmd/aux/depend.c - 664 sys sys 1134305455 25880
-sys/src/cmd/aux/disksim.c - 664 sys sys 1139667305 10919
+sys/src/cmd/aux/disksim.c - 664 sys sys 1140964826 11178
 sys/src/cmd/aux/flashfs - 20000000775 sys sys 1015009082 0
 sys/src/cmd/aux/flashfs/aux.c - 664 sys sys 1015009080 699
 sys/src/cmd/aux/flashfs/aux.h - 664 sys sys 1015009080 111
@@ -13301,20 +13302,20 @@ sys/src/cmd/syscall/mkfile - 664 sys sys 1037122264 549
 sys/src/cmd/syscall/syscall.c - 664 sys sys 1135487934 3951
 sys/src/cmd/tail.c - 664 sys sys 1123123922 6034
 sys/src/cmd/tapefs - 20000000775 sys sys 944962012 0
-sys/src/cmd/tapefs/32vfs.c - 664 sys sys 1140814623 3710
+sys/src/cmd/tapefs/32vfs.c - 664 sys sys 1140965787 3922
 sys/src/cmd/tapefs/cpiofs.c - 664 sys sys 1140814623 2491
-sys/src/cmd/tapefs/fs.c - 664 sys sys 1140814810 9754
+sys/src/cmd/tapefs/fs.c - 664 sys sys 1141003366 9887
 sys/src/cmd/tapefs/mkfile - 664 sys sys 1097914131 254
-sys/src/cmd/tapefs/tapefs.h - 664 sys sys 1140875580 1702
+sys/src/cmd/tapefs/tapefs.h - 664 sys sys 1140966413 1815
 sys/src/cmd/tapefs/tapfs.c - 664 sys sys 1140814624 1924
-sys/src/cmd/tapefs/tarfs.c - 664 sys sys 1140815766 2759
+sys/src/cmd/tapefs/tarfs.c - 664 sys sys 1141003342 2759
 sys/src/cmd/tapefs/tpfs.c - 664 sys sys 1140814810 1999
-sys/src/cmd/tapefs/util.c - 664 sys sys 1140814810 2699
+sys/src/cmd/tapefs/util.c - 664 sys sys 1140966088 2964
 sys/src/cmd/tapefs/v10fs.c - 664 sys sys 1140814624 3776
 sys/src/cmd/tapefs/v6fs.c - 664 sys sys 1140814625 3993
 sys/src/cmd/tapefs/zip.h - 664 sys sys 1097914153 1428
 sys/src/cmd/tapefs/zipfs.c - 664 sys sys 1140814625 6588
-sys/src/cmd/tar.c - 664 sys sys 1138711857 22453
+sys/src/cmd/tar.c - 664 sys sys 1141007861 24018
 sys/src/cmd/tbl - 20000000775 sys sys 954038038 0
 sys/src/cmd/tbl/mkfile - 664 sys sys 944961243 268
 sys/src/cmd/tbl/t.h - 664 sys sys 944961244 3987

+ 13 - 0
dist/replica/plan9.log

@@ -27873,3 +27873,16 @@
 1140876068 0 c sys/src/cmd/tapefs/tapefs.h - 664 sys sys 1140875580 1702
 1140901275 0 c sys/man/2/graphics - 664 sys sys 1140900146 12765
 1140901275 1 c sys/man/2/mouse - 664 sys sys 1140900146 4952
+1140962491 0 c sys/src/cmd/tapefs/tapefs.h - 664 sys sys 1140960820 1704
+1140966090 0 c 386/bin/aux/disksim - 775 sys sys 1140964829 150649
+1140966090 1 c sys/man/4/tapefs - 664 sys sys 1140965924 1861
+1140966090 2 c sys/src/cmd/aux/disksim.c - 664 sys sys 1140964826 11178
+1140966090 3 c sys/src/cmd/tapefs/32vfs.c - 664 sys sys 1140965787 3922
+1140966090 4 c sys/src/cmd/tapefs/util.c - 664 sys sys 1140966088 2964
+1140967892 0 c sys/src/cmd/tapefs/tapefs.h - 664 sys sys 1140966413 1815
+1140976894 0 c 386/bin/aux/disksim - 775 sys sys 1140976599 150655
+1141003901 0 c sys/src/cmd/tapefs/fs.c - 664 sys sys 1141003366 9887
+1141003901 1 c sys/src/cmd/tapefs/tarfs.c - 664 sys sys 1141003342 2759
+1141009304 0 c sys/src/cmd/tar.c - 664 sys sys 1141007861 24018
+1141011104 0 a sys/man/8/disksim - 664 sys sys 1141009713 1452
+1141012904 0 c 386/bin/tar - 775 sys sys 1141012626 93114

+ 6 - 3
sys/man/4/tapefs

@@ -4,6 +4,10 @@
 .SH SYNOPSIS
 .B fs/32vfs
 [
+.B -b
+.I blocksize
+]
+[
 .B -m
 .I mountpoint
 ]
@@ -52,7 +56,7 @@ attached; the default is
 .PP
 .I 32vfs
 interprets raw disk images of 32V systems, which are ca. 1978 research Unix systems for
-the VAX, and also pre-FFS Berkeley VAX systems (1KB block size).
+the VAX (512 byte block size, the default), and also pre-FFS Berkeley VAX systems (1KB block size).
 .PP
 .I Cpiofs
 interprets
@@ -101,6 +105,5 @@ which in
 turn derive substantially from
 .IR ramfs (4).
 .SH "SEE ALSO
-Section 5
-.IR passim ,
+.IR intro (5),
 .IR ramfs (4).

+ 90 - 0
sys/man/8/disksim

@@ -0,0 +1,90 @@
+.TH DISKSIM 8
+.SH NAME
+disksim \- disk simulator
+.SH SYNOPSIS
+.B aux/disksim
+[
+.B -r
+]
+[
+.B -f
+.I file
+]
+[
+.B -s
+.I srvname
+]
+[
+.B -m
+.I mtpt
+]
+[
+.I diskname
+]
+.SH DESCRIPTION
+.I Disksim
+presents an in-memory disk in the manner of the
+.IR sd (3)
+device on
+.IB mtpt / diskname
+(default
+.B /dev/sdXX ).
+The disk is initialized to zeros;
+non-zeroed blocks written to the disk are kept in memory.
+.PP
+The
+.B -f
+option causes
+.I disksim
+to use
+.I file
+as the initial contents of the disk rather than a zeroed image.
+Changes made to the disk are written back to 
+.I file
+unless the
+.B -r
+option is given.
+.PP
+The
+.B -s
+option causes
+.I disksim
+to post its 9P service at
+.BI /srv/ service \fR.
+.SH EXAMPLES
+.I Disksim
+can be used to test programs such as
+.I fdisk
+and
+.IR prep (8)
+that expect
+.IR sd (3)
+disks:
+.IP
+.EX
+aux/disksim
+echo geometry 40000 512 0 0 0 >/dev/sdXX/ctl # 20MB
+disk/fdisk -baw /dev/sdXX/data
+disk/prep /dev/sdXX/plan9
+.EE
+.PP
+.I Disksim
+is useful for creating very large but mostly zeroed files
+for testing other programs.
+Test
+.IR tar (1)'s
+handling of large files:
+.IP
+.EX
+for(i in sdXX sdYY sdZZ) aux/disksim $i
+echo geometry 40000000 512 0 0 0 >/dev/sdXX/ctl # 20GB
+echo geometry 10000000 512 0 0 0 >/dev/sdYY/ctl # 5GB
+echo geometry 20000000 512 0 0 0 >/dev/sdZZ/ctl # 10GB
+tar cf /dev/sdXX/data /dev/sdYY/data /dev/sdZZ/data
+tar tvf /dev/sdXX/data
+.EE
+.SH SOURCE
+.B /sys/src/cmd/aux/disksim.c
+.SH SEE ALSO
+.IR sd (3),
+.IR prep (8)

+ 27 - 12
sys/src/cmd/aux/disksim.c

@@ -23,6 +23,7 @@ enum
 	LOGNPTR = LOGBLKSZ-2,	/* assume sizeof(void*) == 4 */
 	NPTR = 1<<LOGNPTR,
 };
+static uchar zero[BLKSZ];
 
 struct Trip
 {
@@ -239,7 +240,6 @@ allocblk(vlong addr)
 uchar*
 getblock(vlong addr, int alloc)
 {
-	static uchar zero[BLKSZ];
  	Dbl *p2;
 	Ind *p1;
 	uchar *p0;
@@ -355,10 +355,23 @@ evommem(void *a, void *b, ulong n)
 	return memmove(b, a, n);
 }
 
+int
+isnonzero(void *v, ulong n)
+{
+	uchar *a, *ea;
+	
+	a = v;
+	ea = a+n;
+	for(; a<ea; a++)
+		if(*a)
+			return 1;
+	return 0;
+}
+
 int
 rdwrpart(Req *r)
 {
-	int q;
+	int q, nonzero;
 	Part *p;
 	vlong offset;
 	long count, tot, n, o;
@@ -396,34 +409,36 @@ rdwrpart(Req *r)
 		move = evommem;
 
 	tot = 0;
+	nonzero = 1;
 	if(r->ifcall.type == Tread)
 		dat = (uchar*)r->ofcall.data;
-	else
+	else{
 		dat = (uchar*)r->ifcall.data;
+		nonzero = isnonzero(dat, r->ifcall.count);
+	}
 	o = offset & (BLKSZ-1);
 
 	/* left fringe block */
-	if(o && count){	
-		blk = getblock(offset, r->ifcall.type==Twrite);
-		if(blk == nil)
-			abort();
+	if(o && count){
+		blk = getblock(offset, r->ifcall.type==Twrite && nonzero);
 		n = BLKSZ - o;
 		if(n > count)
 			n = count;
-		(*move)(dat, blk+o, n);
+		if(r->ifcall.type != Twrite || blk != zero)
+			(*move)(dat, blk+o, n);
 		if(r->ifcall.type == Twrite)
 			dirty(offset, blk);
 		tot += n;
 	}
+next:
 	/* full and right fringe blocks */
 	while(tot < count){
-		blk = getblock(offset+tot, r->ifcall.type==Twrite);
-		if(blk == nil)
-			abort();
+		blk = getblock(offset+tot, r->ifcall.type==Twrite && nonzero);
 		n = BLKSZ;
 		if(n > count-tot)
 			n = count-tot;
-		(*move)(dat+tot, blk, n);
+		if(r->ifcall.type != Twrite || blk != zero)
+			(*move)(dat+tot, blk, n);
 		if(r->ifcall.type == Twrite)
 			dirty(offset+tot, blk);
 		tot += n;

+ 16 - 6
sys/src/cmd/tapefs/32vfs.c

@@ -20,9 +20,11 @@
 #define	VSUPERB	1
 #define	VROOT		2	/* root inode */
 #define	VNAMELEN	14
-#define	BLSIZE	512
+#define	MAXBLSIZE	1024
+int	BLSIZE;
 #define	LINOPB	(BLSIZE/sizeof(struct v32dinode))
-#define	LNINDIR	(BLSIZE/sizeof(unsigned long))
+#define	LNINDIR	(BLSIZE/4)
+#define	MAXLNINDIR	(MAXBLSIZE/4)
 
 struct v32dinode {
 	unsigned char flags[2];
@@ -50,7 +52,15 @@ void
 populate(char *name)
 {
 	Fileinf f;
-
+	uchar buf[MAXBLSIZE];
+
+	BLSIZE = 512;	/* 32v */
+	if(blocksize){
+		/* 1024 for 4.1BSD */
+		if(blocksize != 512 && blocksize != 1024)
+			error("bad block size");
+		BLSIZE = blocksize;
+	}
 	replete = 0;
 	tapefile = open(name, OREAD);
 	if (tapefile<0)
@@ -106,7 +116,7 @@ docreate(Ram *r)
 char *
 doread(Ram *r, vlong off, long cnt)
 {
-	static char buf[Maxbuf+BLSIZE];
+	static char buf[Maxbuf+MAXBLSIZE];
 	int bno, i;
 
 	bno = off/BLSIZE;
@@ -147,7 +157,7 @@ dopermw(Ram *r)
 Fileinf
 iget(int ino)
 {
-	char buf[BLSIZE];
+	char buf[MAXBLSIZE];
 	struct v32dinode *dp;
 	long flags, i;
 	Fileinf f;
@@ -194,7 +204,7 @@ getblk(Ram *r, long bno, char *buf)
 long
 bmap(Ram *r, long bno)
 {
-	unsigned char indbuf[LNINDIR][sizeof(long)];
+	unsigned char indbuf[MAXLNINDIR][4];
 
 	if (bno < VNADDR-3)
 		return ((long*)r->data)[bno];

+ 9 - 4
sys/src/cmd/tapefs/fs.c

@@ -16,8 +16,10 @@ ulong	path;
 Idmap	*uidmap;
 Idmap	*gidmap;
 int	replete;
+int	blocksize;		/* for 32v */
 int	verbose;
 int	newtap;		/* tap with time in sec */
+int	blocksize;
 
 Fid *	newfid(int);
 int	ramstat(Ram*, uchar*, int);
@@ -80,20 +82,23 @@ main(int argc, char *argv[])
 	defmnt = "/n/tapefs";
 	ARGBEGIN{
 	case 'm':
-		defmnt = ARGF();
+		defmnt = EARGF(usage());
 		break;
 	case 'p':			/* password file */
-		uidmap = getpass(ARGF());
+		uidmap = getpass(EARGF(usage()));
 		break;
 	case 'g':			/* group file */
-		gidmap = getpass(ARGF());
+		gidmap = getpass(EARGF(usage()));
 		break;
 	case 'v':
 		verbose++;
-
+		break;
 	case 'n':
 		newtap++;
 		break;
+	case 'b':
+		blocksize = atoi(EARGF(usage()));
+		break;
 	default:
 		usage();
 	}ARGEND

+ 5 - 1
sys/src/cmd/tapefs/tapefs.h

@@ -1,7 +1,10 @@
 #define	g2byte(x)	(((x)[1]<<8) + (x)[0])		/* little-endian */
 #define	g3byte(x)	(((x)[2]<<16) + ((x)[1]<<8) + (x)[0])
 #define	g4byte(x)	(((x)[3]<<24) + ((x)[2]<<16) + ((x)[1]<<8) + (x)[0])
-#define	g8byte(x)	(((vlong)g4byte(x)<<32) | (u32int)g4byte(x+4))
+
+/* big endian */
+#define	b4byte(x)	(((x)[0]<<24) + ((x)[1]<<16) + ((x)[2]<<8) + (x)[3])
+#define	b8byte(x)	(((vlong)b4byte(x)<<32) | (u32int)b4byte((x)+4))
 enum
 {
 	OPERM	= 0x3,		/* mask of all permission types in open mode */
@@ -75,6 +78,7 @@ extern	char	*user;
 extern	Idmap	*uidmap;
 extern	Idmap	*gidmap;
 extern	int	replete;
+extern	int	blocksize;
 void	error(char*);
 void	*erealloc(void*, ulong);
 void	*emalloc(ulong);

+ 1 - 1
sys/src/cmd/tapefs/tarfs.c

@@ -53,7 +53,7 @@ populate(char *name)
 		f.uid = strtoul(dblock.dbuf.uid, 0, 8);
 		f.gid = strtoul(dblock.dbuf.gid, 0, 8);
 		if((uchar)dblock.dbuf.size[0] == 0x80)
-			f.size = g8byte(dblock.dbuf.size+3);
+			f.size = b8byte(dblock.dbuf.size+3);
 		else
 			f.size = strtoull(dblock.dbuf.size, 0, 8);
 		f.mdate = strtoul(dblock.dbuf.mtime, 0, 8);

+ 16 - 4
sys/src/cmd/tapefs/util.c

@@ -58,19 +58,25 @@ mapid(Idmap *up, int id)
 Ram *
 poppath(Fileinf fi, int new)
 {
-	char *suffix;
+	char *suffix, *origname;
 	Ram *dir, *ent;
 	Fileinf f;
 
 	if (*fi.name=='\0')
 		return 0;
+	origname = estrdup(fi.name);
 	if (suffix=strrchr(fi.name, '/')){
 		*suffix = 0;
 		suffix++;
 		if (*suffix=='\0'){
 			fi.mode |= DMDIR;
+			free(origname);
 			return poppath(fi, 1);
 		}
+		/*
+		 * create parent directory of suffix;
+		 * may recurse, thus shortening fi.name even further.
+		 */
 		f = fi;
 		f.size = 0;
 		f.addr = 0;
@@ -81,15 +87,20 @@ poppath(Fileinf fi, int new)
 	} else {
 		suffix = fi.name;
 		dir = ram;
-		if (strcmp(suffix, ".")==0)
+		if (strcmp(suffix, ".")==0) {
+			free(origname);
 			return dir;
+		}
 	}
 	ent = lookup(dir, suffix);
 	fi.mode |= 0400;			/* at least user read */
 	if (ent){
 		if (((fi.mode&DMDIR)!=0) != ((ent->qid.type&QTDIR)!=0)){
-			fprint(2, "%s/%s directory botch\n", fi.name, suffix);
-			exits("");
+			fprint(2,
+		"%s file type changed; probably due to union dir.; ignoring\n",
+				origname);
+			free(origname);
+			return ent;
 		}
 		if (new)  {
 			ent->ndata = fi.size;
@@ -104,6 +115,7 @@ poppath(Fileinf fi, int new)
 		fi.name = suffix;
 		ent = popfile(dir, fi);
 	}
+	free(origname);
 	return ent;
 }
 

+ 83 - 24
sys/src/cmd/tar.c

@@ -32,6 +32,12 @@
 #define ROUNDUP(a, b)	(((a) + (b) - 1)/(b))
 #define BYTES2TBLKS(bytes) ROUNDUP(bytes, Tblock)
 
+/* read big-endian binary integers; args must be (uchar *) */
+#define	G2BEBYTE(x)	(((x)[0]<<8)  |  (x)[1])
+#define	G3BEBYTE(x)	(((x)[0]<<16) | ((x)[1]<<8)  |  (x)[2])
+#define	G4BEBYTE(x)	(((x)[0]<<24) | ((x)[1]<<16) | ((x)[2]<<8) | (x)[3])
+#define	G8BEBYTE(x)	(((vlong)G4BEBYTE(x)<<32) | (u32int)G4BEBYTE((x)+4))
+
 typedef vlong Off;
 typedef char *(*Refill)(int ar, char *bufs, int justhdr);
 
@@ -42,11 +48,14 @@ enum { None, Toc, Xtract, Replace };
 enum { Alldata, Justnxthdr };
 enum {
 	Tblock = 512,
-	Nblock = 40,		/* maximum blocksize */
-	Dblock = 20,		/* default blocksize */
 	Namsiz = 100,
 	Maxpfx = 155,		/* from POSIX */
 	Maxname = Namsiz + 1 + Maxpfx,
+	Binsize = 0x80,		/* flag in size[0], from gnu: positive binary size */
+	Binnegsz = 0xff,	/* flag in size[0]: negative binary size */
+
+	Nblock = 40,		/* maximum blocksize */
+	Dblock = 20,		/* default blocksize */
 	DEBUG = 0,
 };
 
@@ -386,7 +395,7 @@ putblkmany(int ar, int blks)
  * modifies hp->chksum but restores it; important for the last block of the
  * old archive when updating with `tar rf archive'
  */
-long
+static long
 chksum(Hdr *hp)
 {
 	int n = Tblock;
@@ -459,15 +468,62 @@ eotar(Hdr *hp)
 	return name(hp)[0] == '\0';
 }
 
-/* return the size from the header block, or zero for links, dirs, etc. */
-Off
+/*
+static uvlong
+getbe(uchar *src, int size)
+{
+	uvlong vl = 0;
+
+	while (size-- > 0) {
+		vl <<= 8;
+		vl |= *src++;
+	}
+	return vl;
+}
+ */
+
+static void
+putbe(uchar *dest, uvlong vl, int size)
+{
+	for (dest += size; size-- > 0; vl >>= 8)
+		*--dest = vl;
+}
+
+/*
+ * return the nominal size from the header block, which is not always the
+ * size in the archive (the archive size may be zero for some file types
+ * regardless of the nominal size).
+ *
+ * gnu and freebsd tars are now recording vlongs as big-endian binary
+ * with a flag in byte 0 to indicate this, which permits file sizes up to
+ * 2^64-1 (actually 2^80-1 but our file sizes are vlongs) rather than 2^33-1.
+ */
+static Off
 hdrsize(Hdr *hp)
 {
-	Off bytes = strtoull(hp->size, nil, 8);
+	uchar *p;
+
+	if((uchar)hp->size[0] == Binnegsz) {
+		fprint(2, "%s: %s: negative length, which is insane\n",
+			argv0, name(hp));
+		return 0;
+	} else if((uchar)hp->size[0] == Binsize) {
+		p = (uchar *)hp->size + sizeof hp->size - 1 -
+			sizeof(vlong);		/* -1 for terminating space */
+		return G8BEBYTE(p);
+	} else
+		return strtoull(hp->size, nil, 8);
+}
 
+/*
+ * return the number of bytes recorded in the archive.
+ */
+static Off
+arsize(Hdr *hp)
+{
 	if(isdir(hp) || islink(hp->linkflag))
-		bytes = 0;
-	return bytes;
+		return 0;
+	return hdrsize(hp);
 }
 
 static Hdr *
@@ -485,7 +541,7 @@ readhdr(int ar)
 	if (chksum(hp) != hdrcksum)
 		sysfatal("bad archive header checksum: name %.64s...",
 			hp->name);
-	nexthdr += Tblock*(1 + BYTES2TBLKS(hdrsize(hp)));
+	nexthdr += Tblock*(1 + BYTES2TBLKS(arsize(hp)));
 	return hp;
 }
 
@@ -563,16 +619,19 @@ mkhdr(Hdr *hp, Dir *dir, char *file)
 	sprint(hp->mode, "%6lo ", dir->mode & 0777);
 	sprint(hp->uid, "%6o ", aruid);
 	sprint(hp->gid, "%6o ", argid);
-	/*
-	 * files > 2⁳⁳ bytes can't be described
-	 * (unless we resort to xustar or exustar formats).
-	 */
-	if (dir->length >= (Off)1<<33) {
-		fprint(2, "%s: %s: too large for tar header format\n",
-			argv0, file);
-		return -1;
-	}
-	sprint(hp->size, "%11lluo ", dir->length);
+	if (dir->length >= (Off)1<<32) {
+		static int printed;
+
+		if (!printed) {
+			printed = 1;
+			fprint(2, "%s: storing large sizes in \"base 256\"\n", argv0);
+		}
+		hp->size[0] = Binsize;
+		/* emit so-called `base 256' representation of size */
+		putbe((uchar *)hp->size+1, dir->length, sizeof hp->size - 2);
+		hp->size[sizeof hp->size - 1] = ' ';
+	} else
+		sprint(hp->size, "%11lluo ", dir->length);
 	sprint(hp->mtime, "%11luo ", dir->mtime);
 	hp->linkflag = (dir->mode&DMDIR? LF_DIR: LF_PLAIN1);
 	putfullname(hp, file);
@@ -722,7 +781,7 @@ replace(char **argv)
 	if (usefile && !docreate) {
 		/* skip quickly to the end */
 		while ((hp = readhdr(ar)) != nil) {
-			bytes = hdrsize(hp);
+			bytes = arsize(hp);
 			for (blksleft = BYTES2TBLKS(bytes);
 			     blksleft > 0 && getblkrd(ar, Justnxthdr) != nil;
 			     blksleft -= blksread) {
@@ -874,8 +933,8 @@ extract1(int ar, Hdr *hp, char *fname)
 	int wrbytes, fd = -1, dir = 0;
 	long mtime = strtol(hp->mtime, nil, 8);
 	ulong mode = strtoul(hp->mode, nil, 8) & 0777;
-	Off bytes  = strtoll(hp->size, nil, 8);		/* for printing */
-	ulong blksread, blksleft = BYTES2TBLKS(hdrsize(hp));
+	Off bytes = hdrsize(hp);		/* for printing */
+	ulong blksread, blksleft = BYTES2TBLKS(arsize(hp));
 	Hdr *hbp;
 
 	if (isdir(hp)) {
@@ -982,7 +1041,7 @@ skip(int ar, Hdr *hp, char *fname)
 	ulong blksleft, blksread;
 	Hdr *hbp;
 
-	for (blksleft = BYTES2TBLKS(hdrsize(hp)); blksleft > 0;
+	for (blksleft = BYTES2TBLKS(arsize(hp)); blksleft > 0;
 	     blksleft -= blksread) {
 		hbp = getblkrd(ar, Justnxthdr);
 		if (hbp == nil)
@@ -1109,4 +1168,4 @@ main(int argc, char *argv[])
 		break;
 	}
 	exits(ret);
-}
+}