Browse Source

Plan 9 from Bell Labs 2005-02-09

David du Colombier 19 years ago
parent
commit
a484e2423c

+ 13 - 2
acme/mail/src/mail.c

@@ -74,8 +74,9 @@ void
 threadmain(int argc, char *argv[])
 {
 	char *s, *name;
-	char err[ERRMAX], cmd[256];
+	char err[ERRMAX], *cmd;
 	int i, newdir;
+	Fmt fmt;
 
 	doquote = needsrcquote;
 	quotefmtinstall();
@@ -184,7 +185,17 @@ threadmain(int argc, char *argv[])
 	winname(wbox, mbox.name);
 	wintagwrite(wbox, "Put Mail Delmesg ", 3+1+4+1+7+1);
 	threadcreate(mainctl, wbox, STACK);
-	snprint(cmd, sizeof cmd, "Mail %s", name);
+
+	fmtstrinit(&fmt);
+	fmtprint(&fmt, "Mail");
+	if(shortmenu)
+		fmtprint(&fmt, " -%c", "sS"[shortmenu-1]);
+	if(outgoing)
+		fmtprint(&fmt, " -o %s", outgoing);
+	fmtprint(&fmt, " %s", name);
+	cmd = fmtstrflush(&fmt);
+	if(cmd == nil)
+		sysfatal("out of memory");
 	winsetdump(wbox, "/acme/mail", cmd);
 	mbox.w = wbox;
 

+ 23 - 28
dist/replica/_plan9.db

@@ -16,11 +16,11 @@
 386/bin - 20000000775 sys sys 1018897690 0
 386/bin/8a - 775 sys sys 1104121953 114832
 386/bin/8c - 775 sys sys 1107405596 357746
-386/bin/8l - 775 sys sys 1107756104 115728
+386/bin/8l - 775 sys sys 1107835553 115728
 386/bin/9660srv - 775 sys sys 1104121955 103973
 386/bin/aan - 775 sys sys 1104121955 130710
 386/bin/acid - 775 sys sys 1107662683 355831
-386/bin/acme - 775 sys sys 1107230748 428041
+386/bin/acme - 775 sys sys 1107920768 428057
 386/bin/ape - 20000000775 sys sys 1016944144 0
 386/bin/ape/basename - 775 sys sys 1087442501 132681
 386/bin/ape/cc - 775 sys sys 1104121958 70291
@@ -53,11 +53,11 @@
 386/bin/auth/debug - 775 sys sys 1104121962 101064
 386/bin/auth/disable - 775 sys sys 1020319057 146
 386/bin/auth/enable - 775 sys sys 1020319057 134
-386/bin/auth/factotum - 775 sys sys 1107833921 312267
+386/bin/auth/factotum - 775 sys sys 1107920769 312307
 386/bin/auth/fgui - 775 sys sys 1106799169 217787
 386/bin/auth/guard.srv - 775 sys sys 1104121964 142850
 386/bin/auth/iam - 775 sys sys 1085076981 50791
-386/bin/auth/keyfs - 775 sys sys 1106107675 115351
+386/bin/auth/keyfs - 775 sys sys 1107920769 115430
 386/bin/auth/login - 775 sys sys 1107405597 103379
 386/bin/auth/newns - 775 sys sys 1104121965 87950
 386/bin/auth/none - 775 sys sys 1104121966 87699
@@ -407,7 +407,7 @@
 386/bin/swap - 775 sys sys 1104122060 62094
 386/bin/syscall - 775 sys sys 1104122060 73536
 386/bin/tail - 775 sys sys 1104122060 65938
-386/bin/tar - 775 sys sys 1104122061 83920
+386/bin/tar - 775 sys sys 1107920770 95246
 386/bin/tbl - 775 sys sys 1104122061 113124
 386/bin/tcs - 775 sys sys 1104122062 256588
 386/bin/tee - 775 sys sys 1104122062 38428
@@ -440,7 +440,7 @@
 386/bin/upas/bayes - 775 sys sys 1064598344 70530
 386/bin/upas/deliver - 775 sys sys 1104122069 99781
 386/bin/upas/filter - 775 sys sys 1104122070 147311
-386/bin/upas/fs - 775 sys sys 1107405598 332387
+386/bin/upas/fs - 775 sys sys 1107920771 332823
 386/bin/upas/isspam - 775 sys sys 1064598349 38
 386/bin/upas/list - 775 sys sys 1104122071 82776
 386/bin/upas/marshal - 775 sys sys 1107490159 132595
@@ -683,7 +683,7 @@ acme/bin/unind - 755 sys sys 1015011256 27
 acme/bin/wnew - 775 sys sys 1046184422 84
 acme/mail - 20000000775 sys sys 1015011265 0
 acme/mail/386 - 20000000775 sys sys 1015011538 0
-acme/mail/386/Mail - 775 sys sys 1104122116 178712
+acme/mail/386/Mail - 775 sys sys 1107920771 179076
 acme/mail/Mail - 775 sys sys 1015011264 202
 acme/mail/alpha - 20000000775 sys sys 1015011521 0
 acme/mail/arm - 20000000775 sys sys 1015011525 0
@@ -696,7 +696,7 @@ acme/mail/readme - 664 sys sys 1084385076 2795
 acme/mail/src - 20000000775 sys sys 1015364010 0
 acme/mail/src/dat.h - 664 sys sys 1033936953 3857
 acme/mail/src/html.c - 664 sys sys 1058463659 1348
-acme/mail/src/mail.c - 664 sys sys 1084385064 11057
+acme/mail/src/mail.c - 664 sys sys 1107894665 11277
 acme/mail/src/mesg.c - 664 sys sys 1043463888 26266
 acme/mail/src/mkfile - 664 sys sys 1037034918 364
 acme/mail/src/reply.c - 664 sys sys 1041137203 11326
@@ -3007,7 +3007,7 @@ rc/bin/bundle - 775 sys sys 945617206 173
 rc/bin/c: - 775 sys sys 1015089511 86
 rc/bin/cpurc - 775 sys sys 1048777186 1338
 rc/bin/dial - 20000000775 sys sys 1059180057 0
-rc/bin/dircp - 775 sys sys 1077038698 192
+rc/bin/dircp - 775 sys sys 1107836261 193
 rc/bin/doc2ps - 775 sys sys 1069793831 244
 rc/bin/doc2txt - 775 sys sys 1025197880 563
 rc/bin/doctype - 775 sys sys 945617206 1726
@@ -3041,8 +3041,9 @@ rc/bin/nroff - 775 sys sys 945617208 27
 rc/bin/patch - 20000000775 sys sys 1067803227 0
 rc/bin/patch/applied - 775 sys sys 1081204295 110
 rc/bin/patch/apply - 775 sys sys 1089299188 1276
-rc/bin/patch/create - 775 sys sys 1104988374 1160
+rc/bin/patch/create - 775 sys sys 1107836219 1380
 rc/bin/patch/diff - 775 sys sys 1106151131 466
+rc/bin/patch/email - 775 sys sys 1107836219 401
 rc/bin/patch/list - 775 sys sys 1081204287 644
 rc/bin/patch/move - 775 sys sys 1104430337 565
 rc/bin/patch/note - 664 sys sys 1089299189 655
@@ -3346,7 +3347,7 @@ sys/doc/venti/venti.pdf - 755 sys sys 1020384352 139090
 sys/doc/venti/venti.ps - 664 sys sys 1019852320 2012620
 sys/games - 20000000775 sys sys 952648872 0
 sys/games/lib - 20000000775 sys sys 952648879 0
-sys/games/lib/fortunes - 664 sys sys 1107321348 252719
+sys/games/lib/fortunes - 664 sys sys 1107880958 252781
 sys/games/lib/mahjongg - 20000000775 sys sys 1095792278 0
 sys/games/lib/mahjongg/backgrounds - 20000000775 sys sys 1095792293 0
 sys/games/lib/mahjongg/backgrounds/default.bit - 664 sys sys 1095792293 346803
@@ -3583,7 +3584,7 @@ sys/lib/dist/pc/glenda/tmp - 20000000775 sys sys 1018469723 0
 sys/lib/dist/pc/inst - 20000000775 sys sys 1018721419 0
 sys/lib/dist/pc/inst/bootfloppy - 775 sys sys 1019240165 899
 sys/lib/dist/pc/inst/bootplan9 - 775 sys sys 1019534696 1584
-sys/lib/dist/pc/inst/bootsetup - 775 sys sys 1063856192 3551
+sys/lib/dist/pc/inst/bootsetup - 775 sys sys 1107839820 3572
 sys/lib/dist/pc/inst/bootwin9x - 775 sys sys 1020384273 2525
 sys/lib/dist/pc/inst/bootwinnt - 775 sys sys 1019240165 1041
 sys/lib/dist/pc/inst/configarch - 775 sys sys 1018640312 636
@@ -4780,7 +4781,7 @@ sys/man/1/strip - 664 sys sys 958580250 448
 sys/man/1/sum - 664 sys sys 984772442 1390
 sys/man/1/syscall - 664 sys sys 1016466457 1439
 sys/man/1/tail - 664 sys sys 1017679307 1413
-sys/man/1/tar - 664 sys sys 1070371922 2538
+sys/man/1/tar - 664 sys sys 1107879863 3375
 sys/man/1/tbl - 664 sys sys 944959674 4308
 sys/man/1/tcs - 664 sys sys 952627441 2575
 sys/man/1/tee - 664 sys sys 969499886 351
@@ -5001,7 +5002,7 @@ sys/man/4/dossrv - 664 sys sys 1015024813 4176
 sys/man/4/execnet - 664 sys sys 1019866708 1069
 sys/man/4/exportfs - 664 sys sys 1105574692 4692
 sys/man/4/ext2srv - 664 sys sys 1055692986 2409
-sys/man/4/factotum - 664 sys sys 1107633798 14773
+sys/man/4/factotum - 664 sys sys 1107836362 14708
 sys/man/4/fossil - 664 sys sys 1101668322 9564
 sys/man/4/fs - 664 sys sys 1019058716 3387
 sys/man/4/ftpfs - 664 sys sys 1048285446 4327
@@ -6494,7 +6495,7 @@ sys/src/boot/pc/apm.c - 664 sys sys 1015007947 289
 sys/src/boot/pc/bcom.c - 664 sys sys 1032215919 6421
 sys/src/boot/pc/boot.c - 664 sys sys 1021579983 3353
 sys/src/boot/pc/bootld.c - 664 sys sys 1015007948 1801
-sys/src/boot/pc/bootp.c - 664 sys sys 1103641772 12262
+sys/src/boot/pc/bootp.c - 664 sys sys 1107882190 12147
 sys/src/boot/pc/cga.c - 664 sys sys 1015007948 1362
 sys/src/boot/pc/clock.c - 664 sys sys 1103641772 6425
 sys/src/boot/pc/conf.c - 664 sys sys 1094674484 10217
@@ -6510,10 +6511,10 @@ sys/src/boot/pc/dosboot.c - 664 sys sys 1097716791 11240
 sys/src/boot/pc/dosfs.h - 664 sys sys 1032215924 1467
 sys/src/boot/pc/eoffs - 664 sys sys 1015007950 0
 sys/src/boot/pc/error.h - 664 sys sys 1015007950 3081
-sys/src/boot/pc/ether.c - 664 sys sys 1103641772 5120
+sys/src/boot/pc/ether.c - 664 sys sys 1107882190 5090
 sys/src/boot/pc/ether2000.c - 664 sys sys 1015007950 2609
 sys/src/boot/pc/ether2114x.c - 664 sys sys 1066618033 37048
-sys/src/boot/pc/ether589.c - 664 sys sys 1015007950 4628
+sys/src/boot/pc/ether589.c - 664 sys sys 1107921511 4620
 sys/src/boot/pc/ether79c970.c - 664 sys sys 1015007950 11717
 sys/src/boot/pc/ether8003.c - 664 sys sys 1015007950 6446
 sys/src/boot/pc/ether8139.c - 664 sys sys 1102429126 14806
@@ -6525,7 +6526,7 @@ sys/src/boot/pc/ether8390.h - 664 sys sys 1015007951 1392
 sys/src/boot/pc/etherec2t.c - 664 sys sys 1015007951 3598
 sys/src/boot/pc/etherelnk3.c - 664 sys sys 1034454878 44068
 sys/src/boot/pc/etherelnk3x.c - 664 sys sys 1015007951 24989
-sys/src/boot/pc/etherif.h - 664 sys sys 1096379797 1285
+sys/src/boot/pc/etherif.h - 664 sys sys 1107882190 1255
 sys/src/boot/pc/etherigbe.c - 664 sys sys 1096379796 39825
 sys/src/boot/pc/ethermii.c - 664 sys sys 1103641771 4413
 sys/src/boot/pc/ethermii.h - 664 sys sys 1071175087 3259
@@ -6808,7 +6809,7 @@ sys/src/cmd/acme/elog.c - 664 sys sys 1078839859 7236
 sys/src/cmd/acme/exec.c - 664 sys sys 1099329953 28183
 sys/src/cmd/acme/file.c - 664 sys sys 1044626079 5717
 sys/src/cmd/acme/fns.h - 664 sys sys 1107154481 2916
-sys/src/cmd/acme/fsys.c - 664 sys sys 1107154482 12881
+sys/src/cmd/acme/fsys.c - 664 sys sys 1107897581 12891
 sys/src/cmd/acme/look.c - 664 sys sys 1077376257 14213
 sys/src/cmd/acme/mkfile - 664 sys sys 1058463682 543
 sys/src/cmd/acme/regx.c - 664 sys sys 1014926094 16057
@@ -6889,7 +6890,7 @@ sys/src/cmd/auth/factotum/util.c - 664 sys sys 1107833785 17917
 sys/src/cmd/auth/factotum/wep.c - 664 sys sys 1107706104 2140
 sys/src/cmd/auth/guard.srv.c - 664 sys sys 1032497638 2334
 sys/src/cmd/auth/iam.c - 664 sys sys 1015008430 841
-sys/src/cmd/auth/keyfs.c - 664 sys sys 1063855447 17524
+sys/src/cmd/auth/keyfs.c - 664 sys sys 1107835724 17624
 sys/src/cmd/auth/lib - 20000000775 sys sys 1015008430 0
 sys/src/cmd/auth/lib/error.c - 664 sys sys 1015008430 301
 sys/src/cmd/auth/lib/fs.c - 664 sys sys 1015008430 228
@@ -10451,7 +10452,7 @@ sys/src/cmd/tapefs/v10fs.c - 664 sys sys 1014926385 3754
 sys/src/cmd/tapefs/v6fs.c - 664 sys sys 1014926385 3971
 sys/src/cmd/tapefs/zip.h - 664 sys sys 1097914153 1428
 sys/src/cmd/tapefs/zipfs.c - 664 sys sys 1097900277 6803
-sys/src/cmd/tar.c - 664 sys sys 1103607141 15725
+sys/src/cmd/tar.c - 664 sys sys 1107921224 19566
 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
@@ -10858,7 +10859,7 @@ sys/src/cmd/upas/filterkit/readaddrs.c - 664 sys sys 1018549521 1381
 sys/src/cmd/upas/filterkit/token.c - 664 sys sys 1018549521 1312
 sys/src/cmd/upas/fs - 20000000775 sys sys 988250018 0
 sys/src/cmd/upas/fs/dat.h - 664 sys sys 1047490337 4267
-sys/src/cmd/upas/fs/fs.c - 664 sys sys 1107835225 27456
+sys/src/cmd/upas/fs/fs.c - 664 sys sys 1107880276 27460
 sys/src/cmd/upas/fs/imap4.c - 664 sys sys 1075069146 16233
 sys/src/cmd/upas/fs/mbox.c - 664 sys sys 1107835226 28935
 sys/src/cmd/upas/fs/mkfile - 664 sys sys 1047490336 321
@@ -12465,9 +12466,3 @@ usr/glenda/lib/profile - 664 glenda glenda 1105128663 890
 usr/glenda/readme.acme - 664 glenda glenda 1019860628 4753
 usr/glenda/readme.rio - 664 glenda glenda 1019860628 6370
 usr/glenda/tmp - 20000000775 glenda glenda 1018802620 0
-386/bin/8l - 775 sys sys 1107835553 115728
-rc/bin/dircp - 775 sys sys 1107836261 193
-rc/bin/patch/create - 775 sys sys 1107836219 1380
-rc/bin/patch/email - 775 sys sys 1107836219 401
-sys/man/4/factotum - 664 sys sys 1107836362 14708
-sys/src/cmd/auth/keyfs.c - 664 sys sys 1107835724 17624

+ 17 - 17
dist/replica/plan9.db

@@ -20,7 +20,7 @@
 386/bin/9660srv - 775 sys sys 1104121955 103973
 386/bin/aan - 775 sys sys 1104121955 130710
 386/bin/acid - 775 sys sys 1107662683 355831
-386/bin/acme - 775 sys sys 1107230748 428041
+386/bin/acme - 775 sys sys 1107920768 428057
 386/bin/ape - 20000000775 sys sys 1016944144 0
 386/bin/ape/basename - 775 sys sys 1087442501 132681
 386/bin/ape/cc - 775 sys sys 1104121958 70291
@@ -53,11 +53,11 @@
 386/bin/auth/debug - 775 sys sys 1104121962 101064
 386/bin/auth/disable - 775 sys sys 1020319057 146
 386/bin/auth/enable - 775 sys sys 1020319057 134
-386/bin/auth/factotum - 775 sys sys 1107833921 312267
+386/bin/auth/factotum - 775 sys sys 1107920769 312307
 386/bin/auth/fgui - 775 sys sys 1106799169 217787
 386/bin/auth/guard.srv - 775 sys sys 1104121964 142850
 386/bin/auth/iam - 775 sys sys 1085076981 50791
-386/bin/auth/keyfs - 775 sys sys 1106107675 115351
+386/bin/auth/keyfs - 775 sys sys 1107920769 115430
 386/bin/auth/login - 775 sys sys 1107405597 103379
 386/bin/auth/newns - 775 sys sys 1104121965 87950
 386/bin/auth/none - 775 sys sys 1104121966 87699
@@ -407,7 +407,7 @@
 386/bin/swap - 775 sys sys 1104122060 62094
 386/bin/syscall - 775 sys sys 1104122060 73536
 386/bin/tail - 775 sys sys 1104122060 65938
-386/bin/tar - 775 sys sys 1104122061 83920
+386/bin/tar - 775 sys sys 1107920770 95246
 386/bin/tbl - 775 sys sys 1104122061 113124
 386/bin/tcs - 775 sys sys 1104122062 256588
 386/bin/tee - 775 sys sys 1104122062 38428
@@ -440,7 +440,7 @@
 386/bin/upas/bayes - 775 sys sys 1064598344 70530
 386/bin/upas/deliver - 775 sys sys 1104122069 99781
 386/bin/upas/filter - 775 sys sys 1104122070 147311
-386/bin/upas/fs - 775 sys sys 1107405598 332387
+386/bin/upas/fs - 775 sys sys 1107920771 332823
 386/bin/upas/isspam - 775 sys sys 1064598349 38
 386/bin/upas/list - 775 sys sys 1104122071 82776
 386/bin/upas/marshal - 775 sys sys 1107490159 132595
@@ -683,7 +683,7 @@ acme/bin/unind - 755 sys sys 1015011256 27
 acme/bin/wnew - 775 sys sys 1046184422 84
 acme/mail - 20000000775 sys sys 1015011265 0
 acme/mail/386 - 20000000775 sys sys 1015011538 0
-acme/mail/386/Mail - 775 sys sys 1104122116 178712
+acme/mail/386/Mail - 775 sys sys 1107920771 179076
 acme/mail/Mail - 775 sys sys 1015011264 202
 acme/mail/alpha - 20000000775 sys sys 1015011521 0
 acme/mail/arm - 20000000775 sys sys 1015011525 0
@@ -696,7 +696,7 @@ acme/mail/readme - 664 sys sys 1084385076 2795
 acme/mail/src - 20000000775 sys sys 1015364010 0
 acme/mail/src/dat.h - 664 sys sys 1033936953 3857
 acme/mail/src/html.c - 664 sys sys 1058463659 1348
-acme/mail/src/mail.c - 664 sys sys 1084385064 11057
+acme/mail/src/mail.c - 664 sys sys 1107894665 11277
 acme/mail/src/mesg.c - 664 sys sys 1043463888 26266
 acme/mail/src/mkfile - 664 sys sys 1037034918 364
 acme/mail/src/reply.c - 664 sys sys 1041137203 11326
@@ -3347,7 +3347,7 @@ sys/doc/venti/venti.pdf - 755 sys sys 1020384352 139090
 sys/doc/venti/venti.ps - 664 sys sys 1019852320 2012620
 sys/games - 20000000775 sys sys 952648872 0
 sys/games/lib - 20000000775 sys sys 952648879 0
-sys/games/lib/fortunes - 664 sys sys 1107321348 252719
+sys/games/lib/fortunes - 664 sys sys 1107880958 252781
 sys/games/lib/mahjongg - 20000000775 sys sys 1095792278 0
 sys/games/lib/mahjongg/backgrounds - 20000000775 sys sys 1095792293 0
 sys/games/lib/mahjongg/backgrounds/default.bit - 664 sys sys 1095792293 346803
@@ -3584,7 +3584,7 @@ sys/lib/dist/pc/glenda/tmp - 20000000775 sys sys 1018469723 0
 sys/lib/dist/pc/inst - 20000000775 sys sys 1018721419 0
 sys/lib/dist/pc/inst/bootfloppy - 775 sys sys 1019240165 899
 sys/lib/dist/pc/inst/bootplan9 - 775 sys sys 1019534696 1584
-sys/lib/dist/pc/inst/bootsetup - 775 sys sys 1063856192 3551
+sys/lib/dist/pc/inst/bootsetup - 775 sys sys 1107839820 3572
 sys/lib/dist/pc/inst/bootwin9x - 775 sys sys 1020384273 2525
 sys/lib/dist/pc/inst/bootwinnt - 775 sys sys 1019240165 1041
 sys/lib/dist/pc/inst/configarch - 775 sys sys 1018640312 636
@@ -4781,7 +4781,7 @@ sys/man/1/strip - 664 sys sys 958580250 448
 sys/man/1/sum - 664 sys sys 984772442 1390
 sys/man/1/syscall - 664 sys sys 1016466457 1439
 sys/man/1/tail - 664 sys sys 1017679307 1413
-sys/man/1/tar - 664 sys sys 1070371922 2538
+sys/man/1/tar - 664 sys sys 1107879863 3375
 sys/man/1/tbl - 664 sys sys 944959674 4308
 sys/man/1/tcs - 664 sys sys 952627441 2575
 sys/man/1/tee - 664 sys sys 969499886 351
@@ -6495,7 +6495,7 @@ sys/src/boot/pc/apm.c - 664 sys sys 1015007947 289
 sys/src/boot/pc/bcom.c - 664 sys sys 1032215919 6421
 sys/src/boot/pc/boot.c - 664 sys sys 1021579983 3353
 sys/src/boot/pc/bootld.c - 664 sys sys 1015007948 1801
-sys/src/boot/pc/bootp.c - 664 sys sys 1103641772 12262
+sys/src/boot/pc/bootp.c - 664 sys sys 1107882190 12147
 sys/src/boot/pc/cga.c - 664 sys sys 1015007948 1362
 sys/src/boot/pc/clock.c - 664 sys sys 1103641772 6425
 sys/src/boot/pc/conf.c - 664 sys sys 1094674484 10217
@@ -6511,10 +6511,10 @@ sys/src/boot/pc/dosboot.c - 664 sys sys 1097716791 11240
 sys/src/boot/pc/dosfs.h - 664 sys sys 1032215924 1467
 sys/src/boot/pc/eoffs - 664 sys sys 1015007950 0
 sys/src/boot/pc/error.h - 664 sys sys 1015007950 3081
-sys/src/boot/pc/ether.c - 664 sys sys 1103641772 5120
+sys/src/boot/pc/ether.c - 664 sys sys 1107882190 5090
 sys/src/boot/pc/ether2000.c - 664 sys sys 1015007950 2609
 sys/src/boot/pc/ether2114x.c - 664 sys sys 1066618033 37048
-sys/src/boot/pc/ether589.c - 664 sys sys 1015007950 4628
+sys/src/boot/pc/ether589.c - 664 sys sys 1107921511 4620
 sys/src/boot/pc/ether79c970.c - 664 sys sys 1015007950 11717
 sys/src/boot/pc/ether8003.c - 664 sys sys 1015007950 6446
 sys/src/boot/pc/ether8139.c - 664 sys sys 1102429126 14806
@@ -6526,7 +6526,7 @@ sys/src/boot/pc/ether8390.h - 664 sys sys 1015007951 1392
 sys/src/boot/pc/etherec2t.c - 664 sys sys 1015007951 3598
 sys/src/boot/pc/etherelnk3.c - 664 sys sys 1034454878 44068
 sys/src/boot/pc/etherelnk3x.c - 664 sys sys 1015007951 24989
-sys/src/boot/pc/etherif.h - 664 sys sys 1096379797 1285
+sys/src/boot/pc/etherif.h - 664 sys sys 1107882190 1255
 sys/src/boot/pc/etherigbe.c - 664 sys sys 1096379796 39825
 sys/src/boot/pc/ethermii.c - 664 sys sys 1103641771 4413
 sys/src/boot/pc/ethermii.h - 664 sys sys 1071175087 3259
@@ -6809,7 +6809,7 @@ sys/src/cmd/acme/elog.c - 664 sys sys 1078839859 7236
 sys/src/cmd/acme/exec.c - 664 sys sys 1099329953 28183
 sys/src/cmd/acme/file.c - 664 sys sys 1044626079 5717
 sys/src/cmd/acme/fns.h - 664 sys sys 1107154481 2916
-sys/src/cmd/acme/fsys.c - 664 sys sys 1107154482 12881
+sys/src/cmd/acme/fsys.c - 664 sys sys 1107897581 12891
 sys/src/cmd/acme/look.c - 664 sys sys 1077376257 14213
 sys/src/cmd/acme/mkfile - 664 sys sys 1058463682 543
 sys/src/cmd/acme/regx.c - 664 sys sys 1014926094 16057
@@ -10452,7 +10452,7 @@ sys/src/cmd/tapefs/v10fs.c - 664 sys sys 1014926385 3754
 sys/src/cmd/tapefs/v6fs.c - 664 sys sys 1014926385 3971
 sys/src/cmd/tapefs/zip.h - 664 sys sys 1097914153 1428
 sys/src/cmd/tapefs/zipfs.c - 664 sys sys 1097900277 6803
-sys/src/cmd/tar.c - 664 sys sys 1103607141 15725
+sys/src/cmd/tar.c - 664 sys sys 1107921224 19566
 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
@@ -10859,7 +10859,7 @@ sys/src/cmd/upas/filterkit/readaddrs.c - 664 sys sys 1018549521 1381
 sys/src/cmd/upas/filterkit/token.c - 664 sys sys 1018549521 1312
 sys/src/cmd/upas/fs - 20000000775 sys sys 988250018 0
 sys/src/cmd/upas/fs/dat.h - 664 sys sys 1047490337 4267
-sys/src/cmd/upas/fs/fs.c - 664 sys sys 1107835225 27456
+sys/src/cmd/upas/fs/fs.c - 664 sys sys 1107880276 27460
 sys/src/cmd/upas/fs/imap4.c - 664 sys sys 1075069146 16233
 sys/src/cmd/upas/fs/mbox.c - 664 sys sys 1107835226 28935
 sys/src/cmd/upas/fs/mkfile - 664 sys sys 1047490336 321

+ 19 - 0
dist/replica/plan9.log

@@ -13481,3 +13481,22 @@
 1107837108 3 a rc/bin/patch/email - 775 sys sys 1107836219 401
 1107837108 4 c sys/man/4/factotum - 664 sys sys 1107836362 14708
 1107837108 5 c sys/src/cmd/auth/keyfs.c - 664 sys sys 1107835724 17624
+1107840709 0 c sys/lib/dist/pc/inst/bootsetup - 775 sys sys 1107839820 3572
+1107880317 0 c sys/man/1/tar - 664 sys sys 1107879863 3375
+1107880317 1 c sys/src/cmd/upas/fs/fs.c - 664 sys sys 1107880276 27460
+1107880317 2 c sys/src/cmd/tar.c - 664 sys sys 1107879866 19543
+1107882118 0 c sys/games/lib/fortunes - 664 sys sys 1107880958 252781
+1107883917 0 c sys/src/boot/pc/bootp.c - 664 sys sys 1107882190 12147
+1107883917 1 c sys/src/boot/pc/ether.c - 664 sys sys 1107882190 5090
+1107883917 2 c sys/src/boot/pc/etherif.h - 664 sys sys 1107882190 1255
+1107894720 0 c acme/mail/386/Mail - 775 sys sys 1107894681 179076
+1107894720 1 c acme/mail/src/mail.c - 664 sys sys 1107894665 11277
+1107898321 0 c sys/src/cmd/acme/fsys.c - 664 sys sys 1107897581 12891
+1107921606 0 c 386/bin/acme - 775 sys sys 1107920768 428057
+1107921606 1 c 386/bin/auth/factotum - 775 sys sys 1107920769 312307
+1107921606 2 c 386/bin/auth/keyfs - 775 sys sys 1107920769 115430
+1107921606 3 c 386/bin/tar - 775 sys sys 1107920770 95246
+1107921606 4 c 386/bin/upas/fs - 775 sys sys 1107920771 332823
+1107921606 5 c acme/mail/386/Mail - 775 sys sys 1107920771 179076
+1107921606 6 c sys/src/boot/pc/ether589.c - 664 sys sys 1107921511 4620
+1107921606 7 c sys/src/cmd/tar.c - 664 sys sys 1107921224 19566

+ 1 - 0
sys/games/lib/fortunes

@@ -4051,3 +4051,4 @@ panic: bad rob
 There is no interest in a WWW browser.  This fad is clearly not going to have any staying power.  - plan.9@research.att.com, Oct 22 1994
 the representation of characters, but not the character set itself, was changed this weekend.  we believe that the representation we are using now will become the one used by unix-like systems everywhere.  - rob's news about utf-8, sep 6 1992
 Linux: the world's best text adventure game.
+MessageSocket::setHostname(): gethostbyname() failed: Success

+ 2 - 1
sys/lib/dist/pc/inst/bootsetup

@@ -111,7 +111,8 @@ case go
 	}
 
 case checkdone
-	if(! isfat /dev/sd*/9fat || ! ~ $didbootsetup 1){
+	xxxfat=(/dev/sd*/9fat)
+	if(! isfat $xxxfat(1) || ! ~ $didbootsetup 1){
 		bootsetup=ready
 		export bootsetup
 	}

+ 74 - 25
sys/man/1/tar

@@ -27,13 +27,9 @@ The function is one of the following letters:
 .B  c
 Create a new archive with the given files as contents.
 .TP
-.B  x
-Extract the named files from the archive.
-If a file is a directory, the directory is extracted recursively.
-Modes are restored if possible.
-If no file argument is given, extract the entire archive.
-If the archive contains multiple entries for a file,
-the latest one wins.
+.B  r
+The named files
+are appended to the archive.
 .TP
 .B  t
 List all occurrences of each 
@@ -42,21 +38,16 @@ in the archive, or of all files if there are no
 .I file
 arguments.
 .TP
-.B  r
-The named files
-are appended to the archive.
+.B  x
+Extract the named files from the archive.
+If a file is a directory, the directory is extracted recursively.
+Modes are restored if possible.
+If no file argument is given, extract the entire archive.
+If the archive contains multiple entries for a file,
+the latest one wins.
 .PP
 The modifiers are:
 .TP
-.B  v
-(verbose)
-Print the name of each file treated
-preceded by the function letter.
-With 
-.BR t ,
-give more details about the
-archive entries.
-.TP
 .B f
 Use the next argument as the name of the archive instead of
 the default standard input (for keys
@@ -68,21 +59,31 @@ or standard output (for keys
 and
 .BR r ).
 .TP
-.B u
-Use the next (numeric) argument as the user id for files in
-the output archive.  This is only useful when moving files to
-a non-Plan 9 system.
-.TP
 .B g
 Use the next (numeric) argument as the group id for files in
 the output archive.
 .TP
+.B k
+(keep)
+Modifies the behavior of
+.B x
+not to extract files which already exist.
+.TP
+.B m
+Do not set the modification time on extracted files.
+This is the default behavior; the flag exists only for compatibility with other tars.
+.TP
 .B p
 Create archive in POSIX ustar format,
 which raises the maximum pathname length from 100 to 256 bytes.
 Ustar archives are recognised automatically by
 .I tar
 when reading archives.
+This is the default behavior; the flag exists only for backwards compatibility
+with older versions of tar.
+.TP
+.B P
+Do not use the POSIX ustar format.
 .TP
 .B R
 When extracting, ignore leading slash on file names,
@@ -91,8 +92,56 @@ i.e., extract all files relative to the current directory.
 .B T
 Modifies the behavior of
 .B x
-to set the mode and modified time
+to set the modified time
 of each file to that specified in the archive.
+.TP
+.B u
+Use the next (numeric) argument as the user id for files in
+the output archive.  This is only useful when moving files to
+a non-Plan 9 system.
+.TP
+.B v
+(verbose)
+Print the name of each file treated
+preceded by the function letter.
+With 
+.BR t ,
+give more details about the
+archive entries.
+.TP
+.B z
+Operate on compressed tar archives.
+The type of compression is inferred from the file name extension:
+.IR gzip (1)
+for
+.B .tar.gz
+and
+.BR .tgz ;
+.I bzip2
+(see
+.IR gzip (1))
+for
+.BR .tar.bz ,
+.BR .tbz ,
+.BR .tar.bz2 ,
+and
+.BR .tbz2 ;
+.I compress
+(not distributed)
+for
+.B .tar.Z
+and
+.BR .tz .
+If no extension matches,
+.I gzip
+is used.
+The
+.B z
+flag is unnecessary (but allowed) when using the
+.B t
+and
+.B x
+verbs on archives with recognized extensions.
 .SH EXAMPLES
 .I Tar
 can be used to copy hierarchies thus:

+ 17 - 21
sys/src/boot/pc/bootp.c

@@ -136,13 +136,6 @@ ip_csum(uchar *addr)
 	return (sum^0xffff);
 }
 
-void
-printea(uchar *ea)
-{
-	print("%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
-		ea[0], ea[1], ea[2], ea[3], ea[4], ea[5]);
-}
-
 enum {
 	/* this is only true of IPv4, but we're not doing v6 yet */
 	Min_udp_payload = ETHERMINTU - ETHERHDRSIZE - UDP_HDRSIZE,
@@ -257,16 +250,12 @@ udprecv(int ctlrno, Netaddr *a, void *data, int dlen)
 			continue;
 
 		h = (Udphdr*)&pkt;
-if(debug) {
-	print("udprecv ");
-	printea(h->s);
-	print(" to ");
-	printea(h->d);
-	print("...\n");
-}
+		if(debug)
+			print("udprecv %E to %E...\n", h->s, h->d);
 
 		if(nhgets(h->type) != ET_IP) {
-if(debug) print("not ip...");
+			if(debug)
+				print("not ip...");
 			continue;
 		}
 
@@ -280,11 +269,13 @@ if(debug) print("not ip...");
 		}
 
 		if(h->udpproto != IP_UDPPROTO) {
-if(debug) print("not udp (%d)...", h->udpproto);
+			if(debug)
+				print("not udp (%d)...", h->udpproto);
 			continue;
 		}
 
-if(debug) print("okay udp...");
+		if(debug)
+			print("okay udp...");
 
 		h->ttl = 0;
 		len = nhgets(h->udplen);
@@ -293,25 +284,30 @@ if(debug) print("okay udp...");
 		if(nhgets(h->udpcksum)) {
 			csm = ptcl_csum(&h->ttl, len+UDP_PHDRSIZE);
 			if(csm != 0) {
-				print("udp chksum error csum #%4ux len %d\n", csm, n);
+				print("udp chksum error csum #%4ux len %d\n",
+					csm, n);
 				break;
 			}
 		}
 
 		if(a->port != 0 && nhgets(h->udpsport) != a->port) {
-if(debug) print("udpport %ux %ux\n", nhgets(h->udpsport), a->port);
+			if(debug)
+				print("udpport %ux %ux\n",
+					nhgets(h->udpsport), a->port);
 			continue;
 		}
 
 		addr = nhgetl(h->udpsrc);
 		if(a->ip != Bcastip && addr != a->ip) {
-if(debug) print("bad ip\n");
+			if(debug)
+				print("bad ip\n");
 			continue;
 		}
 
 		len -= UDP_HDRSIZE-UDP_PHDRSIZE;
 		if(len > dlen) {
-			print("udp: packet too big: %d > %d; from addr 0x%.8lux\n", len, dlen, addr);
+			print("udp: packet too big: %d > %d; from addr %E\n",
+				len, dlen, h->udpsrc);
 			continue;
 		}
 

+ 2 - 6
sys/src/boot/pc/ether.c

@@ -264,12 +264,8 @@ ethertxpkt(int ctlrno, Etherpkt* pkt, int len, int)
 	}
 
 	memmove(pkt->s, ctlr->ea, Eaddrlen);
-if(debug) {
-	printea(pkt->s);
-	print(" to ");
-	printea(pkt->d);
-	print("...\n");
-}
+	if(debug)
+		print("%E to %E...\n", pkt->s, pkt->d);
 	memmove(ring->pkt, pkt, len);
 	if(len < ETHERMINTU){
 		memset(ring->pkt+len, 0, ETHERMINTU-len);

+ 4 - 5
sys/src/boot/pc/ether589.c

@@ -153,7 +153,8 @@ if(debug) print("none found\n");
 	 */
 	memset(ea, 0, sizeof ea);
 	if(memcmp(ea, ether->ea, 6) == 0 && strcmp(type, "3C562") == 0) {
-if(debug) print("read 562...");
+		if(debug)
+			print("read 562...");
 		if(pcmcistuple(slot, 0x88, ea, 6) == 6) {
 			for(i = 0; i < 6; i += 2){
 				t = ea[i];
@@ -161,10 +162,8 @@ if(debug) print("read 562...");
 				ea[i+1] = t;
 			}
 			memmove(ether->ea, ea, 6);
-if(debug) {
-	print("ea ");
-	printea(ether->ea);
-}
+			if(debug)
+				print("ea %E", ea);
 		}
 	}
 	/*

+ 0 - 2
sys/src/boot/pc/etherif.h

@@ -44,5 +44,3 @@ extern void addethercard(char*, int(*)(Ether*));
 
 #define NEXT(x, l)	(((x)+1)%(l))
 #define PREV(x, l)	(((x) == 0) ? (l)-1: (x)-1)
-
-extern void printea(uchar*);

+ 3 - 1
sys/src/cmd/acme/fsys.c

@@ -321,7 +321,9 @@ static
 Xfid*
 fsysauth(Xfid *x, Fid*)
 {
-	return respond(x, nil, "acme: authentication not required");
+	Fcall t;
+
+	return respond(x, &t, "acme: authentication not required");
 }
 
 static

+ 828 - 621
sys/src/cmd/tar.c

@@ -1,17 +1,52 @@
+/*
+ * tar - `tape archiver', actually usable on any medium.
+ *	POSIX "ustar" compliant when extracting, and by default when creating.
+ *	this tar attempts to read and write multiple Tblock-byte blocks
+ *	at once to and from the filesystem, and does not copy blocks
+ *	around internally.
+ */
+
 #include <u.h>
 #include <libc.h>
-#include <auth.h>
-#include <fcall.h>
-#include <bio.h>
-
-#define TBLOCK	512
-#define NBLOCK	40	/* maximum blocksize */
-#define DBLOCK	20	/* default blocksize */
-#define NAMSIZ	100
+#include <fcall.h>		/* for %M */
+#include <String.h>
 
+/*
+ * modified versions of those in libc.h; scans only the first arg for
+ * keyletters and options.
+ */
+#define	TARGBEGIN {\
+	(argv0 || (argv0 = *argv)), argv++, argc--;\
+	if (argv[0]) {\
+		char *_args, *_argt;\
+		Rune _argc;\
+		_args = &argv[0][0];\
+		_argc = 0;\
+		while(*_args && (_args += chartorune(&_argc, _args)))\
+			switch(_argc)
+#define	TARGEND	SET(_argt); USED(_argt);USED(_argc);USED(_args); \
+	argc--, argv++; } \
+	USED(argv); USED(argc); }
+#define	TARGC() (_argc)
+
+#define ROUNDUP(a, b)	(((a) + (b) - 1)/(b))
+#define BYTES2TBLKS(bytes) ROUNDUP(bytes, Tblock)
+
+typedef vlong Off;
+typedef char *(*Refill)(int ar, char *bufs);
+
+enum { Stdin, Stdout, Stderr };
+enum { Rd, Wr };			/* pipe fd-array indices */
+enum { Output, Input };
+enum { None, Toc, Xtract, Replace };
 enum {
+	Tblock = 512,
+	Nblock = 40,		/* maximum blocksize */
+	Dblock = 20,		/* default blocksize */
+	Namsiz = 100,
 	Maxpfx = 155,		/* from POSIX */
-	Maxname = NAMSIZ + 1 + Maxpfx,
+	Maxname = Namsiz + 1 + Maxpfx,
+	DEBUG = 0,
 };
 
 /* POSIX link flags */
@@ -32,12 +67,11 @@ enum {
 #define islink(lf)	(isreallink(lf) || issymlink(lf))
 #define isreallink(lf)	((lf) == LF_LINK)
 #define issymlink(lf)	((lf) == LF_SYMLINK1 || (lf) == LF_SYMLINK2)
-union	hblock
-{
-	char	dummy[TBLOCK];
-	struct	header
-	{
-		char	name[NAMSIZ];
+
+typedef union {
+	uchar	data[Tblock];
+	struct {
+		char	name[Namsiz];
 		char	mode[8];
 		char	uid[8];
 		char	gid[8];
@@ -45,7 +79,8 @@ union	hblock
 		char	mtime[12];
 		char	chksum[8];
 		char	linkflag;
-		char	linkname[NAMSIZ];
+		char	linkname[Namsiz];
+
 		/* rest are defined by POSIX's ustar format; see p1003.2b */
 		char	magic[6];	/* "ustar" */
 		char	version[2];
@@ -53,54 +88,303 @@ union	hblock
 		char	gname[32];
 		char	devmajor[8];
 		char	devminor[8];
-		char	prefix[155];  /* if non-null, path = prefix "/" name */
-	} dbuf;
-} dblock, tbuf[NBLOCK];
-
-Dir *stbuf;
-Biobuf bout;
-static int ustar;		/* flag: tape block just read is ustar format */
-static char *fullname;			/* if non-nil, prefix "/" name */
-
-int	rflag, xflag, vflag, tflag, mt, cflag, fflag, Tflag, Rflag;
-int	uflag, gflag;
-static int posix;		/* flag: we're writing ustar format archive */
-int	chksum, recno, first;
-int	nblock = DBLOCK;
-
-void	usage(void);
-void	dorep(char **);
-int	endtar(void);
-void	getdir(void);
-void	passtar(void);
-void	putfile(char*, char *, char *);
-void	doxtract(char **);
-void	dotable(void);
-void	putempty(void);
-void	longt(Dir *);
-int	checkdir(char *, int, Qid*);
-void	tomodes(Dir *);
-int	checksum(void);
-int	checkupdate(char *);
-int	prefix(char *, char *);
-int	readtar(char *);
-int	writetar(char *);
-void	backtar(void);
-void	flushtar(void);
-void	affix(int, char *);
-int	volprompt(void);
+		char	prefix[Maxpfx]; /* if non-null, path= prefix "/" name */
+	};
+} Hdr;
+
+typedef struct {
+	char	*comp;
+	char	*decomp;
+	char	*sfx[4];
+} Compress;
+
+static Compress comps[] = {
+	"gzip",		"gunzip",	{ ".tar.gz", ".tgz" },	/* default */
+	"compress",	"uncompress",	{ ".tar.Z",  ".tz" },
+	"bzip2",	"bunzip2",	{ ".tar.bz", ".tbz",
+					  ".tar.bz2",".tbz2" },
+};
+
+typedef struct {
+	int	kid;
+	int	fd;	/* original fd */
+	int	rfd;	/* replacement fd */
+	int	input;
+	int	open;
+} Pushstate;
+
+#define OTHER(rdwr) (rdwr == Rd? Wr: Rd)
+
+static int debug;
+static int verb;
+static int posix = 1;
+static int docreate;
+static int aruid;
+static int argid;
+static int relative;
+static int settime;
+static int verbose;
+static int docompress;
+static int keepexisting;
+
+static int nblock = Dblock;
+static char *usefile;
+static char origdir[Maxname*2];
+static Hdr *tpblk, *endblk;
+static Hdr *curblk;
+
+static void
+usage(void)
+{
+	fprint(2, "usage: %s {crtx}[PRTfgkmpuvz] [archive] file1 file2...\n",
+		argv0);
+	exits("usage");
+}
+
+/* compression */
+
+static Compress *
+compmethod(char *name)
+{
+	int i, nmlen = strlen(name), sfxlen;
+	Compress *cp;
+
+	for (cp = comps; cp < comps + nelem(comps); cp++)
+		for (i = 0; i < nelem(cp->sfx) && cp->sfx[i]; i++) {
+			sfxlen = strlen(cp->sfx[i]);
+			if (nmlen > sfxlen &&
+			    strcmp(cp->sfx[i], name + nmlen - sfxlen) == 0)
+				return cp;
+		}
+	return docompress? comps: nil;
+}
 
+/*
+ * push a filter, cmd, onto fd.  if input, it's an input descriptor.
+ * returns a descriptor to replace fd, or -1 on error.
+ */
 static int
-isustar(struct header *hp)
+push(int fd, char *cmd, int input, Pushstate *ps)
 {
-	return strcmp(hp->magic, "ustar") == 0;
+	int nfd, pifds[2];
+	String *s;
+
+	ps->open = 0;
+	ps->fd = fd;
+	ps->input = input;
+	if (fd < 0 || pipe(pifds) < 0)
+		return -1;
+	ps->kid = fork();
+	switch (ps->kid) {
+	case -1:
+		return -1;
+	case 0:
+		if (input)
+			dup(pifds[Wr], Stdout);
+		else
+			dup(pifds[Rd], Stdin);
+		close(pifds[input? Rd: Wr]);
+		dup(fd, (input? Stdin: Stdout));
+		s = s_new();
+		if (cmd[0] != '/')
+			s_append(s, "/bin/");
+		s_append(s, cmd);
+		execl(s_to_c(s), cmd, nil);
+		sysfatal("can't exec %s: %r", cmd);
+	default:
+		nfd = pifds[input? Rd: Wr];
+		close(pifds[input? Wr: Rd]);
+		break;
+	}
+	ps->rfd = nfd;
+	ps->open = 1;
+	return nfd;
+}
+
+static char *
+pushclose(Pushstate *ps)
+{
+	Waitmsg *wm;
+
+	if (ps->fd < 0 || ps->rfd < 0 || !ps->open)
+		return "not open";
+	close(ps->rfd);
+	ps->rfd = -1;
+	ps->open = 0;
+	while ((wm = wait()) != nil && wm->pid != ps->kid)
+		continue;
+	return wm? wm->msg: nil;
 }
 
+/*
+ * block-buffer management
+ */
+
 static void
-setustar(struct header *hp)
+initblks(void)
+{
+	free(tpblk);
+	tpblk = malloc(Tblock * nblock);
+	assert(tpblk != nil);
+	endblk = tpblk + nblock;
+}
+
+/* (re)fill block buffers from archive */
+static char *
+refill(int ar, char *bufs)
+{
+	int i, n;
+	unsigned bytes = Tblock * nblock;
+	static int done, first = 1;
+
+	if (done)
+		return nil;
+
+	/* try to size non-pipe input at first read */
+	if (first && usefile) {
+		first = 0;
+		n = read(ar, bufs, bytes);
+		if (n <= 0)
+			sysfatal("error reading archive: %r");
+		i = n;
+		if (i % Tblock != 0) {
+			fprint(2, "%s: archive block size (%d) error\n",
+				argv0, i);
+			exits("blocksize");
+		}
+		i /= Tblock;
+		if (i != nblock) {
+			nblock = i;
+			fprint(2, "%s: blocking = %d\n", argv0, nblock);
+			endblk = (Hdr *)bufs + nblock;
+			bytes = n;
+		}
+	} else
+		n = readn(ar, bufs, bytes);
+	if (n == 0)
+		sysfatal("unexpected EOF reading archive");
+	else if (n < 0)
+		sysfatal("error reading archive: %r");
+	else if (n%Tblock != 0)
+		sysfatal("partial block read from archive");
+	if (n != bytes) {
+		done = 1;
+		memset(bufs + n, 0, bytes - n);
+	}
+	return bufs;
+}
+
+static Hdr *
+getblk(int ar, Refill rfp)
+{
+	if (curblk == nil || curblk >= endblk) {  /* input block exhausted? */
+		if (rfp != nil && (*rfp)(ar, (char *)tpblk) == nil)
+			return nil;
+		curblk = tpblk;
+	}
+	return curblk++;
+}
+
+static Hdr *
+getblkrd(int ar)
+{
+	return getblk(ar, refill);
+}
+
+static Hdr *
+getblke(int ar)
+{
+	return getblk(ar, nil);
+}
+
+static Hdr *
+getblkz(int ar)
+{
+	Hdr *hp = getblke(ar);
+
+	if (hp != nil)
+		memset(hp->data, 0, Tblock);
+	return hp;
+}
+
+/*
+ * how many block buffers are available, starting at the address
+ * just returned by getblk*?
+ */
+static int
+gothowmany(int max)
 {
-	strncpy(hp->magic, "ustar", sizeof hp->magic);
-	strncpy(hp->version, "00", sizeof hp->version);
+	int n = endblk - (curblk - 1);
+
+	return n > max? max: n;
+}
+
+/*
+ * indicate that one is done with the last block obtained from getblke
+ * and it is now available to be written into the archive.
+ */
+static void
+putlastblk(int ar)
+{
+	unsigned bytes = Tblock * nblock;
+
+	/* if writing end-of-archive, aid compression (good hygiene too) */
+	if (curblk < endblk)
+		memset(curblk, 0, (char *)endblk - (char *)curblk);
+	if (write(ar, tpblk, bytes) != bytes)
+		sysfatal("error writing archive: %r");
+}
+
+static void
+putblk(int ar)
+{
+	if (curblk >= endblk)
+		putlastblk(ar);
+}
+
+static void
+putbackblk(int ar)
+{
+	curblk--;
+	USED(ar);
+}
+
+static void
+putreadblks(int ar, int blks)
+{
+	curblk += blks - 1;
+	USED(ar);
+}
+
+static void
+putblkmany(int ar, int blks)
+{
+	curblk += blks - 1;
+	putblk(ar);
+}
+
+/*
+ * common routines
+ */
+
+/* modifies hp->chksum */
+long
+chksum(Hdr *hp)
+{
+	int n = Tblock;
+	long i = 0;
+	uchar *cp = hp->data;
+
+	memset(hp->chksum, ' ', sizeof hp->chksum);
+	while (n-- > 0)
+		i += *cp++;
+	return i;
+}
+
+static int
+isustar(Hdr *hp)
+{
+	return strcmp(hp->magic, "ustar") == 0;
 }
 
 /*
@@ -111,57 +395,97 @@ setustar(struct header *hp)
 static int
 strnlen(char *s, int n)
 {
-	if (s[n - 1] != '\0')
-		return n;
-	else
-		return strlen(s);
+	return s[n - 1] != '\0'? n: strlen(s);
 }
 
-/* set fullname from header; called from getdir() */
-static void
-getfullname(struct header *hp)
+/* set fullname from header */
+static char *
+name(Hdr *hp)
 {
 	int pfxlen, namlen;
+	static char fullname[Maxname + 1];
 
-	if (fullname != nil)
-		free(fullname);
 	namlen = strnlen(hp->name, sizeof hp->name);
-	if (hp->prefix[0] == '\0' || !ustar) {	/* old-style name? */
-		fullname = malloc(namlen + 1);
-		if (fullname == nil)
-			sysfatal("out of memory: %r");
+	if (hp->prefix[0] == '\0' || !isustar(hp)) {	/* old-style name? */
 		memmove(fullname, hp->name, namlen);
 		fullname[namlen] = '\0';
-		return;
+		return fullname;
 	}
+
+	/* name is in two pieces */
 	pfxlen = strnlen(hp->prefix, sizeof hp->prefix);
-	fullname = malloc(pfxlen + 1 + namlen + 1);
-	if (fullname == nil)
-		sysfatal("out of memory: %r");
 	memmove(fullname, hp->prefix, pfxlen);
 	fullname[pfxlen] = '/';
 	memmove(fullname + pfxlen + 1, hp->name, namlen);
 	fullname[pfxlen + 1 + namlen] = '\0';
+	return fullname;
 }
 
+static int
+isdir(Hdr *hp)
+{
+	/* the mode test is ugly but sometimes necessary */
+	return hp->linkflag == LF_DIR ||
+		strrchr(name(hp), '\0')[-1] == '/' ||
+		(strtoul(hp->mode, nil, 8)&0170000) == 040000;
+}
+
+static int
+eotar(Hdr *hp)
+{
+	return name(hp)[0] == '\0';
+}
+
+static Hdr *
+readhdr(int ar)
+{
+	long hdrcksum;
+	Hdr *hp;
+
+	hp = getblkrd(ar);
+	if (hp == nil)
+		sysfatal("unexpected EOF instead of archive header");
+	if (eotar(hp))			/* end-of-archive block? */
+		return nil;
+	hdrcksum = strtoul(hp->chksum, nil, 8);
+	if (chksum(hp) != hdrcksum)
+		sysfatal("bad archive header checksum: name %.64s...",
+			hp->name);
+	return hp;
+}
+
+/*
+ * tar r[c]
+ */
+
 /*
- * if name is longer than NAMSIZ bytes, try to split it at a slash and fit the
+ * if name is longer than Namsiz bytes, try to split it at a slash and fit the
  * pieces into hp->prefix and hp->name.
  */
 static int
-putfullname(struct header *hp, char *name)
+putfullname(Hdr *hp, char *name)
 {
 	int namlen, pfxlen;
 	char *sl, *osl;
+	String *slname = nil;
+
+	if (isdir(hp)) {
+		slname = s_new();
+		s_append(slname, name);
+		s_append(slname, "/");		/* posix requires this */
+		name = s_to_c(slname);
+	}
 
 	namlen = strlen(name);
-	if (namlen <= NAMSIZ) {
-		strncpy(hp->name, name, NAMSIZ);
+	if (namlen <= Namsiz) {
+		strncpy(hp->name, name, Namsiz);
 		hp->prefix[0] = '\0';		/* ustar paranoia */
 		return 0;
 	}
-	if (!posix || namlen > NAMSIZ + 1 + sizeof hp->prefix) {
-		fprint(2, "tar: name too long for tar header: %s\n", name);
+
+	if (!posix || namlen > Maxname) {
+		fprint(2, "%s: name too long for tar header: %s\n",
+			argv0, name);
 		return -1;
 	}
 	/*
@@ -173,7 +497,7 @@ putfullname(struct header *hp, char *name)
 	sl = strrchr(name, '/');
 	while (sl != nil) {
 		pfxlen = sl - name;
-		if (pfxlen <= sizeof hp->prefix && namlen-1 - pfxlen <= NAMSIZ)
+		if (pfxlen <= sizeof hp->prefix && namlen-1 - pfxlen <= Namsiz)
 			break;
 		osl = sl;
 		*osl = '\0';
@@ -181,615 +505,498 @@ putfullname(struct header *hp, char *name)
 		*osl = '/';
 	}
 	if (sl == nil) {
-		fprint(2, "tar: name can't be split to fit tar header: %s\n",
-			name);
+		fprint(2, "%s: name can't be split to fit tar header: %s\n",
+			argv0, name);
 		return -1;
 	}
 	*sl = '\0';
 	strncpy(hp->prefix, name, sizeof hp->prefix);
-	*sl = '/';
-	strncpy(hp->name, sl + 1, sizeof hp->name);
+	*sl++ = '/';
+	strncpy(hp->name, sl, sizeof hp->name);
+	if (slname)
+		s_free(slname);
 	return 0;
 }
 
-void
-main(int argc, char **argv)
+static int
+mkhdr(Hdr *hp, Dir *dir, char *file)
 {
-	char *usefile;
-	char *cp, *ap;
-
-	if (argc < 2)
-		usage();
-
-	Binit(&bout, 1, OWRITE);
-	usefile =  0;
-	argv[argc] = 0;
-	argv++;
-	for (cp = *argv++; *cp; cp++) 
-		switch(*cp) {
-		case 'f':
-			usefile = *argv++;
-			if(!usefile)
-				usage();
-			fflag++;
-			break;
-		case 'u':
-			ap = *argv++;
-			if(!ap)
-				usage();
-			uflag = strtoul(ap, 0, 0);
-			break;
-		case 'g':
-			ap = *argv++;
-			if(!ap)
-				usage();
-			gflag = strtoul(ap, 0, 0);
-			break;
-		case 'c':
-			cflag++;
-			rflag++;
-			break;
-		case 'p':
-			posix++;
-			break;
-		case 'r':
-			rflag++;
-			break;
-		case 'v':
-			vflag++;
-			break;
-		case 'x':
-			xflag++;
-			break;
-		case 'T':
-			Tflag++;
-			break;
-		case 't':
-			tflag++;
-			break;
-		case 'R':
-			Rflag++;
-			break;
-		case '-':
-			break;
-		default:
-			fprint(2, "tar: %c: unknown option\n", *cp);
-			usage();
-		}
-
-	fmtinstall('M', dirmodefmt);
-
-	if (rflag) {
-		if (!usefile) {
-			if (cflag == 0) {
-				fprint(2, "tar: can only create standard output archives\n");
-				exits("arg error");
-			}
-			mt = dup(1, -1);
-			nblock = 1;
-		}
-		else if ((mt = open(usefile, ORDWR)) < 0) {
-			if (cflag == 0 || (mt = create(usefile, OWRITE, 0666)) < 0) {
-				fprint(2, "tar: cannot open %s: %r\n", usefile);
-				exits("open");
-			}
-		}
-		dorep(argv);
-	}
-	else if (xflag)  {
-		if (!usefile) {
-			mt = dup(0, -1);
-			nblock = 1;
-		}
-		else if ((mt = open(usefile, OREAD)) < 0) {
-			fprint(2, "tar: cannot open %s: %r\n", usefile);
-			exits("open");
-		}
-		doxtract(argv);
+	/*
+	 * these fields run together, so we format them in order and don't use
+	 * snprint.
+	 */
+	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;
 	}
-	else if (tflag) {
-		if (!usefile) {
-			mt = dup(0, -1);
-			nblock = 1;
-		}
-		else if ((mt = open(usefile, OREAD)) < 0) {
-			fprint(2, "tar: cannot open %s: %r\n", usefile);
-			exits("open");
-		}
-		dotable();
+	sprint(hp->size, "%11lluo ", dir->length);
+	sprint(hp->mtime, "%11luo ", dir->mtime);
+	hp->linkflag = (dir->mode&DMDIR? LF_DIR: LF_PLAIN1);
+	putfullname(hp, file);
+	if (posix) {
+		strncpy(hp->magic, "ustar", sizeof hp->magic);
+		strncpy(hp->version, "00", sizeof hp->version);
+		strncpy(hp->uname, dir->uid, sizeof hp->uname);
+		strncpy(hp->gname, dir->gid, sizeof hp->gname);
 	}
-	else
-		usage();
-	exits(0);
+	sprint(hp->chksum, "%6luo", chksum(hp));
+	return 0;
 }
 
-void
-usage(void)
-{
-	fprint(2, "tar: usage  tar {txrc}[Rvf] [tarfile] file1 file2...\n");
-	exits("usage");
-}
+static void addtoar(int ar, char *file, char *shortf);
 
-void
-dorep(char **argv)
+static void
+addtreetoar(int ar, char *file, char *shortf, int fd)
 {
-	char cwdbuf[2048], *cwd, thisdir[2048];
-	char *cp, *cp2;
-	int cd;
+	int n;
+	Dir *dent, *dirents;
+	String *name = s_new();
 
-	if (getwd(cwdbuf, sizeof(cwdbuf)) == 0) {
-		fprint(2, "tar: can't find current directory: %r\n");
-		exits("cwd");
-	}
-	cwd = cwdbuf;
-
-	if (!cflag) {
-		getdir();
-		do {
-			passtar();
-			getdir();
-		} while (!endtar());
-	}
+	n = dirreadall(fd, &dirents);
+	close(fd);
+	if (n == 0)
+		return;
 
-	while (*argv) {
-		cp2 = *argv;
-		if (!strcmp(cp2, "-C") && argv[1]) {
-			argv++;
-			if (chdir(*argv) < 0)
-				perror(*argv);
-			cwd = *argv;
-			argv++;
-			continue;
-		}
-		cd = 0;
-		for (cp = *argv; *cp; cp++)
-			if (*cp == '/')
-				cp2 = cp;
-		if (cp2 != *argv) {
-			*cp2 = '\0';
-			chdir(*argv);
-			if(**argv == '/')
-				strncpy(thisdir, *argv, sizeof(thisdir));
-			else
-				snprint(thisdir, sizeof(thisdir), "%s/%s", cwd, *argv);
-			*cp2 = '/';
-			cp2++;
-			cd = 1;
-		} else
-			strncpy(thisdir, cwd, sizeof(thisdir));
-		putfile(thisdir, *argv++, cp2);
-		if(cd && chdir(cwd) < 0) {
-			fprint(2, "tar: can't cd back to %s: %r\n", cwd);
-			exits("cwd");
-		}
+	if (chdir(shortf) < 0)
+		sysfatal("chdir %s: %r", file);
+	if (DEBUG)
+		fprint(2, "chdir %s\t# %s\n", shortf, file);
+
+	for (dent = dirents; dent < dirents + n; dent++) {
+		s_reset(name);
+		s_append(name, file);
+		s_append(name, "/");
+		s_append(name, dent->name);
+		addtoar(ar, s_to_c(name), dent->name);
 	}
-	putempty();
-	putempty();
-	flushtar();
-}
+	s_free(name);
+	free(dirents);
 
-int
-isendtar(void)
-{
-	return fullname[0] == '\0';
+	if (chdir("..") < 0)
+		sysfatal("chdir %s/..: %r", file);
+	if (DEBUG)
+		fprint(2, "chdir ..\n");
 }
 
-int
-endtar(void)
+static void
+addtoar(int ar, char *file, char *shortf)
 {
-	if (isendtar()) {
-		backtar();
-		return(1);
+	int n, fd, isdir;
+	long bytes;
+	ulong blksleft, blksread;
+	Hdr *hbp;
+	Dir *dir;
+
+	fd = open(shortf, OREAD);
+	if (fd < 0) {
+		fprint(2, "%s: can't open %s: %r\n", argv0, file);
+		return;
 	}
-	else
-		return(0);
-}
-
-void
-getdir(void)
-{
-	Dir *sp;
-
-	readtar((char*)&dblock);
-	ustar = isustar(&dblock.dbuf);
-	getfullname(&dblock.dbuf);
-	if (isendtar())
+	dir = dirfstat(fd);
+	if (dir == nil)
+		sysfatal("can't fstat %s: %r", file);
+
+	hbp = getblkz(ar);
+	isdir = !!(dir->qid.type&QTDIR);
+	if (mkhdr(hbp, dir, file) < 0) {
+		putbackblk(ar);
+		free(dir);
+		close(fd);
 		return;
-	if(stbuf == nil){
-		stbuf = malloc(sizeof(Dir));
-		if(stbuf == nil)
-			sysfatal("out of memory: %r");
 	}
-	sp = stbuf;
-	sp->mode = strtol(dblock.dbuf.mode, 0, 8);
-	sp->uid = "adm";
-	sp->gid = "adm";
-	sp->length = strtol(dblock.dbuf.size, 0, 8);
-	sp->mtime = strtol(dblock.dbuf.mtime, 0, 8);
-	chksum = strtol(dblock.dbuf.chksum, 0, 8);
-	if (chksum != checksum())
-		sysfatal("header checksum error");
-	sp->qid.type = 0;
-	/* the mode test is ugly but sometimes necessary */
-	if (dblock.dbuf.linkflag == LF_DIR || (sp->mode&0170000) == 040000 ||
-	    strrchr(fullname, '\0')[-1] == '/') {
-		sp->qid.type |= QTDIR;
-		sp->mode |= DMDIR;
+	putblk(ar);
+
+	blksleft = BYTES2TBLKS(dir->length);
+	free(dir);
+
+	if (isdir)
+		addtreetoar(ar, file, shortf, fd);
+	else {
+		for (; blksleft > 0; blksleft -= blksread) {
+			hbp = getblke(ar);
+			blksread = gothowmany(blksleft);
+			bytes = blksread * Tblock;
+			n = readn(fd, hbp->data, bytes);
+			if (n < 0)
+				sysfatal("error reading %s: %r", file);
+			/*
+			 * ignore EOF.  zero any partial block to aid
+			 * compression and emergency recovery of data.
+			 */
+			if (n < Tblock)
+				memset(hbp->data + n, 0, bytes - n);
+			putblkmany(ar, blksread);
+		}
+		close(fd);
+		if (verbose)
+			fprint(2, "%s\n", file);
 	}
 }
 
-void
-passtar(void)
+static char *
+replace(char **argv)
 {
-	long blocks;
-	char buf[TBLOCK];
-
-	switch (dblock.dbuf.linkflag) {
-	case LF_LINK:
-	case LF_SYMLINK1:
-	case LF_SYMLINK2:
-	case LF_FIFO:
-		return;
-	}
-	blocks = stbuf->length;
-	blocks += TBLOCK-1;
-	blocks /= TBLOCK;
-
-	while (blocks-- > 0)
-		readtar(buf);
-}
-
-void
-putfile(char *dir, char *longname, char *sname)
-{
-	int infile;
-	long blocks;
-	char buf[TBLOCK];
-	char curdir[4096];
-	char shortname[4096];
-	char *cp;
-	Dir *db;
-	int i, n;
-
-	if(strlen(sname) > sizeof shortname - 3){
-		fprint(2, "tar: %s: name too long (max %d)\n", sname, sizeof shortname - 3);
-		return;
-	}
-	if (sname[0] != '/')		/* protect relative names like #foo */
-		snprint(shortname, sizeof shortname, "./%s", sname);
+	int i, ar;
+	ulong blksleft, blksread;
+	Off bytes;
+	Hdr *hp;
+	Compress *comp = nil;
+	Pushstate ps;
+
+	if (usefile && docreate) {
+		ar = create(usefile, OWRITE, 0666);
+		if (docompress)
+			comp = compmethod(usefile);
+	} else if (usefile)
+		ar = open(usefile, ORDWR);
 	else
-		strcpy(shortname, sname);
-	infile = open(shortname, OREAD);
-	if (infile < 0) {
-		fprint(2, "tar: %s: cannot open file - %r\n", longname);
-		return;
-	}
-
-	if(stbuf != nil)
-		free(stbuf);
-	stbuf = dirfstat(infile);
-
-	if (stbuf->qid.type & QTDIR) {
-		/* Directory */
-		for (i = 0, cp = buf; *cp++ = longname[i++];)
-			;
-		*--cp = '/';
-		*++cp = 0;
-		stbuf->length = 0;
-
-		tomodes(stbuf);
-		if (putfullname(&dblock.dbuf, buf) < 0) {
-			close(infile);
-			return;		/* putfullname already complained */
-		}
-		dblock.dbuf.linkflag = LF_DIR;
-		sprint(dblock.dbuf.chksum, "%6o", checksum());
-		writetar( (char *) &dblock);
-
-		if (chdir(shortname) < 0) {
-			fprint(2, "tar: can't cd to %s: %r\n", shortname);
-			snprint(curdir, sizeof(curdir), "cd %s", shortname);
-			exits(curdir);
-		}
-		sprint(curdir, "%s/%s", dir, sname);
-		while ((n = dirread(infile, &db)) > 0) {
-			for(i = 0; i < n; i++){
-				strncpy(cp, db[i].name, sizeof buf - (cp-buf));
-				putfile(curdir, buf, db[i].name);
+		ar = Stdout;
+	if (comp)
+		ar = push(ar, comp->comp, Output, &ps);
+	if (ar < 0)
+		sysfatal("can't open archive %s: %r", usefile);
+
+	if (usefile && !docreate) {
+		/* skip quickly to the end */
+		while ((hp = readhdr(ar)) != nil) {
+			bytes = strtoull(hp->size, nil, 8);
+			if(isdir(hp))
+				bytes = 0;
+			for (blksleft = BYTES2TBLKS(bytes);
+			     blksleft > 0 && getblkrd(ar) != nil;
+			     blksleft -= blksread) {
+				blksread = gothowmany(blksleft);
+				putreadblks(ar, blksread);
 			}
-			free(db);
-		}
-		close(infile);
-		if (chdir(dir) < 0 && chdir("..") < 0) {
-			fprint(2, "tar: can't cd to ..(%s): %r\n", dir);
-			snprint(curdir, sizeof(curdir), "cd ..(%s)", dir);
-			exits(curdir);
 		}
-		return;
+		/*
+		 * we have just read the end-of-archive Tblock.
+		 * now seek back over the (big) archive block containing it,
+		 * and back up curblk ptr over end-of-archive Tblock in memory.
+		 */
+		if (seek(ar, -Tblock*nblock, 1) < 0)
+			sysfatal("can't seek back over end-of-archive: %r");
+		curblk--;
 	}
 
-	/* plain file; write header block first */
-	tomodes(stbuf);
-	if (putfullname(&dblock.dbuf, longname) < 0) {
-		close(infile);
-		return;		/* putfullname already complained */
-	}
-	blocks = (stbuf->length + (TBLOCK-1)) / TBLOCK;
-	if (vflag) {
-		fprint(2, "a %s ", longname);
-		fprint(2, "%ld blocks\n", blocks);
-	}
-	dblock.dbuf.linkflag = LF_PLAIN1;
-	sprint(dblock.dbuf.chksum, "%6o", checksum());
-	writetar( (char *) &dblock);
-
-	/* then copy contents */
-	while ((i = readn(infile, buf, TBLOCK)) > 0 && blocks > 0) {
-		writetar(buf);
-		blocks--;
-	}
-	close(infile);
-	if (blocks != 0 || i != 0)
-		fprint(2, "%s: file changed size\n", longname);
-	while (blocks-- >  0)
-		putempty();
-}
-
-
-void
-doxtract(char **argv)
-{
-	Dir null;
-	int wrsize;
-	long blocks, bytes;
-	char buf[TBLOCK], outname[Maxname+3+1];
-	char **cp;
-	int ofile;
-
-	for (;;) {
-		getdir();
-		if (endtar())
-			break;
+	for (i = 0; argv[i] != nil; i++)
+		addtoar(ar, argv[i], argv[i]);
 
-		if (*argv == 0)
-			goto gotit;
+	/* write end-of-archive marker */
+	getblkz(ar);
+	putblk(ar);
+	getblkz(ar);
+	putlastblk(ar);
 
-		for (cp = argv; *cp; cp++)
-			if (prefix(*cp, fullname))
-				goto gotit;
-		passtar();
-		continue;
+	if (comp)
+		return pushclose(&ps);
+	if (ar > Stderr)
+		close(ar);
+	return nil;
+}
 
-gotit:
-		if(checkdir(fullname, stbuf->mode, &stbuf->qid))
-			continue;
+/*
+ * tar [xt]
+ */
 
-		if (dblock.dbuf.linkflag == LF_LINK) {
-			fprint(2, "tar: can't link %s %s\n",
-				dblock.dbuf.linkname, fullname);
-			remove(fullname);
-			continue;
-		}
-		if (dblock.dbuf.linkflag == LF_SYMLINK1 ||
-		    dblock.dbuf.linkflag == LF_SYMLINK2) {
-			fprint(2, "tar: %s: cannot symlink\n", fullname);
-			continue;
-		}
-		if(fullname[0] != '/' || Rflag)
-			sprint(outname, "./%s", fullname);
-		else
-			strcpy(outname, fullname);
-		if ((ofile = create(outname, OWRITE, stbuf->mode & 0777)) < 0) {
-			fprint(2, "tar: %s - cannot create: %r\n", outname);
-			passtar();
-			continue;
-		}
+/* is pfx a file-name prefix of name? */
+static int
+prefix(char *name, char *pfx)
+{
+	int pfxlen = strlen(pfx);
+	char clpfx[Maxname+1];
 
-		blocks = ((bytes = stbuf->length) + TBLOCK-1)/TBLOCK;
-		if (vflag)
-			fprint(2, "x %s, %ld bytes\n", fullname, bytes);
-		while (blocks-- > 0) {
-			readtar(buf);
-			wrsize = (bytes > TBLOCK? TBLOCK: bytes);
-			if (write(ofile, buf, wrsize) != wrsize) {
-				fprint(2,
-				    "tar: %s: HELP - extract write error: %r\n",
-					fullname);
-				exits("extract write");
-			}
-			bytes -= TBLOCK;
-		}
-		if(Tflag){
-			nulldir(&null);
-			null.mtime = stbuf->mtime;
-			dirfwstat(ofile, &null);
-		}
-		close(ofile);
-	}
+	if (pfxlen > Maxname)
+		return 0;
+	strcpy(clpfx, pfx);
+	cleanname(clpfx);
+	return strncmp(pfx, name, pfxlen) == 0 &&
+		(name[pfxlen] == '\0' || name[pfxlen] == '/');
 }
 
-void
-dotable(void)
+static int
+match(char *name, char **argv)
 {
-	for (;;) {
-		getdir();
-		if (endtar())
-			break;
-		if (vflag)
-			longt(stbuf);
-		Bprint(&bout, "%s", fullname);
-		if (dblock.dbuf.linkflag == '1')
-			Bprint(&bout, " linked to %s", dblock.dbuf.linkname);
-		if (dblock.dbuf.linkflag == 's')
-			Bprint(&bout, " -> %s", dblock.dbuf.linkname);
-		Bprint(&bout, "\n");
-		passtar();
-	}
+	int i;
+	char clname[Maxname+1];
+
+	if (argv[0] == nil)
+		return 1;
+	strcpy(clname, name);
+	cleanname(clname);
+	for (i = 0; argv[i] != nil; i++)
+		if (prefix(clname, argv[i]))
+			return 1;
+	return 0;
 }
 
-void
-putempty(void)
+static int
+makedir(char *s)
 {
-	char buf[TBLOCK];
+	int f;
 
-	memset(buf, 0, TBLOCK);
-	writetar(buf);
+	if (access(s, AEXIST) == 0)
+		return -1;
+	f = create(s, OREAD, DMDIR | 0777);
+	if (f >= 0)
+		close(f);
+	return f;
 }
 
-void
-longt(Dir *st)
+static void
+mkpdirs(char *s)
 {
-	char *cp;
+	int done = 0;
+	char *p = s;
 
-	Bprint(&bout, "%M %4d/%1d ", st->mode, 0, 0);	/* 0/0 uid/gid */
-	Bprint(&bout, "%8lld", st->length);
-	cp = ctime(st->mtime);
-	Bprint(&bout, " %-12.12s %-4.4s ", cp+4, cp+24);
+	while (!done && (p = strchr(p + 1, '/')) != nil) {
+		*p = '\0';
+		done = (access(s, AEXIST) < 0 && makedir(s) < 0);
+		*p = '/';
+	}
 }
 
-int
-checkdir(char *name, int mode, Qid *qid)
+/* copy a file from the archive into the filesystem */
+static void
+extract1(int ar, Hdr *hp, char *fname)
 {
-	char *cp;
-	int f;
-	Dir *d, null;
-
-	if(Rflag && *name == '/')
-		name++;
-	cp = name;
-	if(*cp == '/')
-		cp++;
-	for (; *cp; cp++) {
-		if (*cp == '/') {
-			*cp = '\0';
-			if (access(name, 0) < 0) {
-				f = create(name, OREAD, DMDIR + 0775L);
-				if(f < 0)
-					fprint(2, "tar: mkdir %s failed: %r\n", name);
-				close(f);
+	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);
+	ulong blksread, blksleft = BYTES2TBLKS(bytes);
+	Hdr *hbp;
+
+	if (isdir(hp)) {
+		mode |= DMDIR|0700;
+		blksleft = 0;
+		dir = 1;
+	}
+	switch (hp->linkflag) {
+	case LF_LINK:
+	case LF_SYMLINK1:
+	case LF_SYMLINK2:
+	case LF_FIFO:
+		blksleft = 0;
+		break;
+	}
+	if (relative && fname[0] == '/')
+		fname++;
+	if (verb == Xtract) {
+		cleanname(fname);
+		switch (hp->linkflag) {
+		case LF_LINK:
+		case LF_SYMLINK1:
+		case LF_SYMLINK2:
+			fprint(2, "%s: can't make (sym)link %s\n",
+				argv0, fname);
+			break;
+		case LF_FIFO:
+			fprint(2, "%s: can't make fifo %s\n", argv0, fname);
+			break;
+		default:
+			if (!keepexisting || access(fname, AEXIST) < 0) {
+				int rw = (dir? OREAD: OWRITE);
+
+				fd = create(fname, rw, mode);
+				if (fd < 0) {
+					mkpdirs(fname);
+					fd = create(fname, rw, mode);
+				}
+				if (fd < 0 &&
+				    (!dir || access(fname, AEXIST) < 0))
+					fprint(2, "%s: can't create %s: %r\n",
+						argv0, fname);
 			}
-			*cp = '/';
+			if (fd >= 0 && verbose)
+				fprint(2, "%s\n", fname);
+			break;
 		}
-	}
+	} else if (verbose) {
+		char *cp = ctime(mtime);
 
-	/* if this is a directory, chmod it to the mode in the tar plus 700 */
-	if(cp[-1] == '/' || (qid->type&QTDIR)){
-		if((d=dirstat(name)) != 0){
-			nulldir(&null);
-			null.mode = DMDIR | (mode & 0777) | 0700;
-			dirwstat(name, &null);
-			free(d);
-		}
-		return 1;
+		print("%M %8lld %-12.12s %-4.4s %s\n",
+			mode, bytes, cp+4, cp+24, fname);
 	} else
-		return 0;
-}
-
-void
-tomodes(Dir *sp)
-{
-	memset(dblock.dummy, 0, sizeof(dblock.dummy));
-	sprint(dblock.dbuf.mode, "%6lo ", sp->mode & 0777);
-	sprint(dblock.dbuf.uid, "%6o ", uflag);
-	sprint(dblock.dbuf.gid, "%6o ", gflag);
-	sprint(dblock.dbuf.size, "%11llo ", sp->length);
-	sprint(dblock.dbuf.mtime, "%11lo ", sp->mtime);
-	if (posix) {
-		setustar(&dblock.dbuf);
-		strncpy(dblock.dbuf.uname, sp->uid, sizeof dblock.dbuf.uname);
-		strncpy(dblock.dbuf.gname, sp->gid, sizeof dblock.dbuf.gname);
+		print("%s\n", fname);
+
+	for (; blksleft > 0; blksleft -= blksread) {
+		hbp = getblkrd(ar);
+		if (hbp == nil)
+			sysfatal("unexpected EOF on archive extracting %s",
+				fname);
+		blksread = gothowmany(blksleft);
+		wrbytes = Tblock*blksread;
+		if(wrbytes > bytes)
+			wrbytes = bytes;
+		if (fd >= 0 && write(fd, hbp->data, wrbytes) != wrbytes)
+			sysfatal("write error on %s: %r", fname);
+		putreadblks(ar, blksread);
+		bytes -= wrbytes;
+	}
+	if (fd >= 0) {
+		/*
+		 * directories should be wstated after we're done
+		 * creating files in them.
+		 */
+		if (settime) {
+			Dir nd;
+
+			nulldir(&nd);
+			nd.mtime = mtime;
+			if (isustar(hp))
+				nd.gid = hp->gname;
+			dirfwstat(fd, &nd);
+		}
+		close(fd);
 	}
 }
 
-int
-checksum(void)
-{
-	int i;
-	char *cp;
-
-	for (cp = dblock.dbuf.chksum; cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++)
-		*cp = ' ';
-	i = 0;
-	for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++)
-		i += *cp & 0xff;
-	return(i);
-}
-
-int
-prefix(char *s1, char *s2)
-{
-	while (*s1)
-		if (*s1++ != *s2++)
-			return(0);
-	if (*s2)
-		return(*s2 == '/');
-	return(1);
-}
-
-int
-readtar(char *buffer)
+static void
+skip(int ar, Hdr *hp, char *fname)
 {
-	int i;
+	Off bytes;
+	ulong blksleft, blksread;
+	Hdr *hbp;
 
-	if (recno >= nblock || first == 0) {
-		if ((i = readn(mt, tbuf, TBLOCK*nblock)) <= 0) {
-			if (i == 0)
-				werrstr("unexpected end of file");
-			fprint(2, "tar: archive read error: %r\n");
-			exits("archive read");
-		}
-		if (first == 0) {
-			if ((i % TBLOCK) != 0) {
-				fprint(2, "tar: archive blocksize error: %r\n");
-				exits("blocksize");
-			}
-			i /= TBLOCK;
-			if (i != nblock) {
-				fprint(2, "tar: blocksize = %d\n", i);
-				nblock = i;
-			}
-		}
-		recno = 0;
+	if (isdir(hp))
+		return;
+	bytes = strtoull(hp->size, nil, 8);
+	blksleft = BYTES2TBLKS(bytes);
+	for (; blksleft > 0; blksleft -= blksread) {
+		hbp = getblkrd(ar);
+		if (hbp == nil)
+			sysfatal("unexpected EOF on archive extracting %s",
+				fname);
+		blksread = gothowmany(blksleft);
+		putreadblks(ar, blksread);
 	}
-	first = 1;
-	memmove(buffer, &tbuf[recno++], TBLOCK);
-	return(TBLOCK);
 }
 
-int
-writetar(char *buffer)
+static char *
+extract(char **argv)
 {
-	first = 1;
-	if (recno >= nblock) {
-		if (write(mt, tbuf, TBLOCK*nblock) != TBLOCK*nblock) {
-			fprint(2, "tar: archive write error: %r\n");
-			exits("write");
-		}
-		recno = 0;
-	}
-	memmove(&tbuf[recno++], buffer, TBLOCK);
-	if (recno >= nblock) {
-		if (write(mt, tbuf, TBLOCK*nblock) != TBLOCK*nblock) {
-			fprint(2, "tar: archive write error: %r\n");
-			exits("write");
-		}
-		recno = 0;
+	int ar;
+	char *longname;
+	Hdr *hp;
+	Compress *comp = nil;
+	Pushstate ps;
+
+	if (usefile) {
+		ar = open(usefile, OREAD);
+		comp = compmethod(usefile);
+	} else
+		ar = Stdin;
+	if (comp)
+		ar = push(ar, comp->decomp, Input, &ps);
+	if (ar < 0)
+		sysfatal("can't open archive %s: %r", usefile);
+
+	while ((hp = readhdr(ar)) != nil) {
+		longname = name(hp);
+		if (match(longname, argv))
+			extract1(ar, hp, longname);
+		else
+			skip(ar, hp, longname);
 	}
-	return(TBLOCK);
-}
 
-/*
- * backup over last tar block
- */
-void
-backtar(void)
-{
-	seek(mt, -TBLOCK*nblock, 1);
-	recno--;
+	if (comp)
+		return pushclose(&ps);
+	if (ar > Stderr)
+		close(ar);
+	return nil;
 }
 
 void
-flushtar(void)
+main(int argc, char *argv[])
 {
-	write(mt, tbuf, TBLOCK*nblock);
+	int errflg = 0;
+	char *ret = nil;
+
+	quotefmtinstall();
+	fmtinstall('M', dirmodefmt);
+
+	TARGBEGIN {
+	case 'c':
+		docreate++;
+		verb = Replace;
+		break;
+	case 'f':
+		usefile = EARGF(usage());
+		break;
+	case 'g':
+		argid = strtoul(EARGF(usage()), 0, 0);
+		break;
+	case 'k':
+		keepexisting++;
+		break;
+	case 'm':	/* compatibility */
+		settime = 0;
+		break;
+	case 'p':
+		posix++;
+		break;
+	case 'P':
+		posix = 0;
+		break;
+	case 'r':
+		verb = Replace;
+		break;
+	case 'R':
+		relative++;
+		break;
+	case 't':
+		verb = Toc;
+		break;
+	case 'T':
+		settime++;
+		break;
+	case 'u':
+		aruid = strtoul(EARGF(usage()), 0, 0);
+		break;
+	case 'v':
+		verbose++;
+		break;
+	case 'x':
+		verb = Xtract;
+		break;
+	case 'z':
+		docompress++;
+		break;
+	case '-':
+		break;
+	default:
+		fprint(2, "tar: unknown letter %C\n", TARGC());
+		errflg++;
+		break;
+	} TARGEND
+
+	if (argc < 0 || errflg)
+		usage();
+
+	initblks();
+	switch (verb) {
+	case Toc:
+	case Xtract:
+		ret = extract(argv);
+		break;
+	case Replace:
+		if (getwd(origdir, sizeof origdir) == nil)
+			strcpy(origdir, "/tmp");
+		ret = replace(argv);
+		chdir(origdir);		/* for profiling */
+		break;
+	default:
+		usage();
+		break;
+	}
+	exits(ret);
 }

+ 2 - 1
sys/src/cmd/upas/fs/fs.c

@@ -1229,8 +1229,9 @@ reader(void)
 				continue;
 
 			qlock(mb);
+			if(mb->d)
 			if(d->qid.path != mb->d->qid.path
-			   || mb->d && d->qid.vers != mb->d->qid.vers){
+			   || d->qid.vers != mb->d->qid.vers){
 				free(d);
 				break;
 			}