Browse Source

Plan 9 from Bell Labs 2008-06-16

David du Colombier 16 years ago
parent
commit
068c9c4b7b

+ 18 - 27
dist/replica/_plan9.db

@@ -7515,7 +7515,7 @@ sys/man/1/tweak - 664 sys sys 1196638936 4762
 sys/man/1/uniq - 664 sys sys 1196638933 995
 sys/man/1/uniq - 664 sys sys 1196638933 995
 sys/man/1/units - 664 sys sys 1196638933 2046
 sys/man/1/units - 664 sys sys 1196638933 2046
 sys/man/1/uptime - 664 sys sys 1196638936 380
 sys/man/1/uptime - 664 sys sys 1196638936 380
-sys/man/1/vac - 664 sys sys 1161727008 3244
+sys/man/1/vac - 664 sys sys 1213503568 4017
 sys/man/1/venti - 664 sys sys 1203807503 2321
 sys/man/1/venti - 664 sys sys 1203807503 2321
 sys/man/1/vi - 664 sys sys 1196638936 2904
 sys/man/1/vi - 664 sys sys 1196638936 2904
 sys/man/1/vnc - 664 sys sys 1196638933 4313
 sys/man/1/vnc - 664 sys sys 1196638933 4313
@@ -14324,27 +14324,18 @@ sys/src/cmd/va/l.s - 664 sys sys 944961340 12696
 sys/src/cmd/va/lex.c - 664 sys sys 1143293804 12095
 sys/src/cmd/va/lex.c - 664 sys sys 1143293804 12095
 sys/src/cmd/va/mkfile - 664 sys sys 944961340 215
 sys/src/cmd/va/mkfile - 664 sys sys 944961340 215
 sys/src/cmd/vac - 20000000775 sys sys 1055699701 0
 sys/src/cmd/vac - 20000000775 sys sys 1055699701 0
-sys/src/cmd/vac/cache.c - 664 sys sys 1189020077 15843
-sys/src/cmd/vac/dat.h - 664 sys sys 1162951177 4029
-sys/src/cmd/vac/error.c - 664 sys sys 1036006057 633
-sys/src/cmd/vac/error.h - 664 sys sys 1036024048 327
-sys/src/cmd/vac/file.c - 664 sys sys 1168307519 19922
-sys/src/cmd/vac/fns.h - 664 sys sys 1036006061 1746
-sys/src/cmd/vac/fs.c - 664 sys sys 1189020075 2950
-sys/src/cmd/vac/mkfile - 664 sys sys 1189020070 435
-sys/src/cmd/vac/pack.c - 664 sys sys 1036006059 10126
-sys/src/cmd/vac/rtest.c - 664 sys sys 1019678787 1116
-sys/src/cmd/vac/source.c - 664 sys sys 1162327879 6767
-sys/src/cmd/vac/srcload.c - 664 sys sys 1036024047 4925
-sys/src/cmd/vac/stdinc.h - 664 sys sys 1189020065 122
-sys/src/cmd/vac/util.c - 664 sys sys 1019678787 930
-sys/src/cmd/vac/vac.c - 664 sys sys 1162350579 23803
-sys/src/cmd/vac/vac.h - 664 sys sys 1091904424 3598
-sys/src/cmd/vac/vacfs.c - 664 sys sys 1162402257 13621
-sys/src/cmd/vac/vactest.c - 664 sys sys 1036024047 2742
-sys/src/cmd/vac/vtdump.c - 664 sys sys 1162951782 8007
-sys/src/cmd/vac/vtread.c - 664 sys sys 1162951740 2016
-sys/src/cmd/vac/wtest.c - 664 sys sys 1019678788 766
+sys/src/cmd/vac/dat.h - 664 sys sys 1213498239 801
+sys/src/cmd/vac/error.c - 664 sys sys 1213498239 709
+sys/src/cmd/vac/error.h - 664 sys sys 1213498239 444
+sys/src/cmd/vac/file.c - 664 sys sys 1213558399 38892
+sys/src/cmd/vac/fns.h - 664 sys sys 1213558385 778
+sys/src/cmd/vac/mkfile - 664 sys sys 1213498239 333
+sys/src/cmd/vac/pack.c - 664 sys sys 1213558400 11975
+sys/src/cmd/vac/stdinc.h - 664 sys sys 1213498240 92
+sys/src/cmd/vac/unvac.c - 664 sys sys 1213504395 5186
+sys/src/cmd/vac/vac.c - 664 sys sys 1213558401 12310
+sys/src/cmd/vac/vac.h - 664 sys sys 1213558389 3987
+sys/src/cmd/vac/vacfs.c - 664 sys sys 1213558401 13323
 sys/src/cmd/vc - 20000000775 sys sys 1039727599 0
 sys/src/cmd/vc - 20000000775 sys sys 1039727599 0
 sys/src/cmd/vc/cgen.c - 664 sys sys 1143241861 20147
 sys/src/cmd/vc/cgen.c - 664 sys sys 1143241861 20147
 sys/src/cmd/vc/enam.c - 664 sys sys 1089299165 1093
 sys/src/cmd/vc/enam.c - 664 sys sys 1089299165 1093
@@ -15848,13 +15839,13 @@ sys/src/libventi/dtype.c - 664 sys sys 1177189441 1117
 sys/src/libventi/entry.c - 664 sys sys 1177189441 1779
 sys/src/libventi/entry.c - 664 sys sys 1177189441 1779
 sys/src/libventi/fcall.c - 664 sys sys 1177189441 3765
 sys/src/libventi/fcall.c - 664 sys sys 1177189441 3765
 sys/src/libventi/fcallfmt.c - 664 sys sys 1177189441 1912
 sys/src/libventi/fcallfmt.c - 664 sys sys 1177189441 1912
-sys/src/libventi/file.c - 664 sys sys 1177189441 23509
+sys/src/libventi/file.c - 664 sys sys 1213500942 23782
 sys/src/libventi/hangup.c - 664 sys sys 1177189441 547
 sys/src/libventi/hangup.c - 664 sys sys 1177189441 547
-sys/src/libventi/log.c - 664 sys sys 1190092827 3936
-sys/src/libventi/mem.c - 664 sys sys 1177189441 1184
+sys/src/libventi/log.c - 664 sys sys 1213500951 3742
+sys/src/libventi/mem.c - 664 sys sys 1213503856 1176
 sys/src/libventi/mkfile - 664 sys sys 1188621815 512
 sys/src/libventi/mkfile - 664 sys sys 1188621815 512
 sys/src/libventi/packet.acid - 664 sys sys 1143389340 21446
 sys/src/libventi/packet.acid - 664 sys sys 1143389340 21446
-sys/src/libventi/packet.c - 664 sys sys 1177189441 15894
+sys/src/libventi/packet.c - 664 sys sys 1213500964 15896
 sys/src/libventi/parsescore.c - 664 sys sys 1177189441 719
 sys/src/libventi/parsescore.c - 664 sys sys 1177189441 719
 sys/src/libventi/queue.c - 664 sys sys 1177189441 1571
 sys/src/libventi/queue.c - 664 sys sys 1177189441 1571
 sys/src/libventi/queue.h - 664 sys sys 1177189441 233
 sys/src/libventi/queue.h - 664 sys sys 1177189441 233
@@ -15862,7 +15853,7 @@ sys/src/libventi/root.c - 664 sys sys 1177189441 1218
 sys/src/libventi/rpc.acid - 664 sys sys 1143491745 12592
 sys/src/libventi/rpc.acid - 664 sys sys 1143491745 12592
 sys/src/libventi/rpc.c - 664 sys sys 1177189442 3174
 sys/src/libventi/rpc.c - 664 sys sys 1177189442 3174
 sys/src/libventi/scorefmt.c - 664 sys sys 1177189442 248
 sys/src/libventi/scorefmt.c - 664 sys sys 1177189442 248
-sys/src/libventi/send.c - 664 sys sys 1177189442 4395
+sys/src/libventi/send.c - 664 sys sys 1213500967 4396
 sys/src/libventi/server.c - 664 sys sys 1179957527 3693
 sys/src/libventi/server.c - 664 sys sys 1179957527 3693
 sys/src/libventi/srvhello.c - 664 sys sys 1177189442 833
 sys/src/libventi/srvhello.c - 664 sys sys 1177189442 833
 sys/src/libventi/strdup.c - 664 sys sys 1177189442 201
 sys/src/libventi/strdup.c - 664 sys sys 1177189442 201

+ 18 - 27
dist/replica/plan9.db

@@ -7515,7 +7515,7 @@ sys/man/1/tweak - 664 sys sys 1196638936 4762
 sys/man/1/uniq - 664 sys sys 1196638933 995
 sys/man/1/uniq - 664 sys sys 1196638933 995
 sys/man/1/units - 664 sys sys 1196638933 2046
 sys/man/1/units - 664 sys sys 1196638933 2046
 sys/man/1/uptime - 664 sys sys 1196638936 380
 sys/man/1/uptime - 664 sys sys 1196638936 380
-sys/man/1/vac - 664 sys sys 1161727008 3244
+sys/man/1/vac - 664 sys sys 1213503568 4017
 sys/man/1/venti - 664 sys sys 1203807503 2321
 sys/man/1/venti - 664 sys sys 1203807503 2321
 sys/man/1/vi - 664 sys sys 1196638936 2904
 sys/man/1/vi - 664 sys sys 1196638936 2904
 sys/man/1/vnc - 664 sys sys 1196638933 4313
 sys/man/1/vnc - 664 sys sys 1196638933 4313
@@ -14324,27 +14324,18 @@ sys/src/cmd/va/l.s - 664 sys sys 944961340 12696
 sys/src/cmd/va/lex.c - 664 sys sys 1143293804 12095
 sys/src/cmd/va/lex.c - 664 sys sys 1143293804 12095
 sys/src/cmd/va/mkfile - 664 sys sys 944961340 215
 sys/src/cmd/va/mkfile - 664 sys sys 944961340 215
 sys/src/cmd/vac - 20000000775 sys sys 1055699701 0
 sys/src/cmd/vac - 20000000775 sys sys 1055699701 0
-sys/src/cmd/vac/cache.c - 664 sys sys 1189020077 15843
-sys/src/cmd/vac/dat.h - 664 sys sys 1162951177 4029
-sys/src/cmd/vac/error.c - 664 sys sys 1036006057 633
-sys/src/cmd/vac/error.h - 664 sys sys 1036024048 327
-sys/src/cmd/vac/file.c - 664 sys sys 1168307519 19922
-sys/src/cmd/vac/fns.h - 664 sys sys 1036006061 1746
-sys/src/cmd/vac/fs.c - 664 sys sys 1189020075 2950
-sys/src/cmd/vac/mkfile - 664 sys sys 1189020070 435
-sys/src/cmd/vac/pack.c - 664 sys sys 1036006059 10126
-sys/src/cmd/vac/rtest.c - 664 sys sys 1019678787 1116
-sys/src/cmd/vac/source.c - 664 sys sys 1162327879 6767
-sys/src/cmd/vac/srcload.c - 664 sys sys 1036024047 4925
-sys/src/cmd/vac/stdinc.h - 664 sys sys 1189020065 122
-sys/src/cmd/vac/util.c - 664 sys sys 1019678787 930
-sys/src/cmd/vac/vac.c - 664 sys sys 1162350579 23803
-sys/src/cmd/vac/vac.h - 664 sys sys 1091904424 3598
-sys/src/cmd/vac/vacfs.c - 664 sys sys 1162402257 13621
-sys/src/cmd/vac/vactest.c - 664 sys sys 1036024047 2742
-sys/src/cmd/vac/vtdump.c - 664 sys sys 1162951782 8007
-sys/src/cmd/vac/vtread.c - 664 sys sys 1162951740 2016
-sys/src/cmd/vac/wtest.c - 664 sys sys 1019678788 766
+sys/src/cmd/vac/dat.h - 664 sys sys 1213498239 801
+sys/src/cmd/vac/error.c - 664 sys sys 1213498239 709
+sys/src/cmd/vac/error.h - 664 sys sys 1213498239 444
+sys/src/cmd/vac/file.c - 664 sys sys 1213558399 38892
+sys/src/cmd/vac/fns.h - 664 sys sys 1213558385 778
+sys/src/cmd/vac/mkfile - 664 sys sys 1213498239 333
+sys/src/cmd/vac/pack.c - 664 sys sys 1213558400 11975
+sys/src/cmd/vac/stdinc.h - 664 sys sys 1213498240 92
+sys/src/cmd/vac/unvac.c - 664 sys sys 1213504395 5186
+sys/src/cmd/vac/vac.c - 664 sys sys 1213558401 12310
+sys/src/cmd/vac/vac.h - 664 sys sys 1213558389 3987
+sys/src/cmd/vac/vacfs.c - 664 sys sys 1213558401 13323
 sys/src/cmd/vc - 20000000775 sys sys 1039727599 0
 sys/src/cmd/vc - 20000000775 sys sys 1039727599 0
 sys/src/cmd/vc/cgen.c - 664 sys sys 1143241861 20147
 sys/src/cmd/vc/cgen.c - 664 sys sys 1143241861 20147
 sys/src/cmd/vc/enam.c - 664 sys sys 1089299165 1093
 sys/src/cmd/vc/enam.c - 664 sys sys 1089299165 1093
@@ -15848,13 +15839,13 @@ sys/src/libventi/dtype.c - 664 sys sys 1177189441 1117
 sys/src/libventi/entry.c - 664 sys sys 1177189441 1779
 sys/src/libventi/entry.c - 664 sys sys 1177189441 1779
 sys/src/libventi/fcall.c - 664 sys sys 1177189441 3765
 sys/src/libventi/fcall.c - 664 sys sys 1177189441 3765
 sys/src/libventi/fcallfmt.c - 664 sys sys 1177189441 1912
 sys/src/libventi/fcallfmt.c - 664 sys sys 1177189441 1912
-sys/src/libventi/file.c - 664 sys sys 1177189441 23509
+sys/src/libventi/file.c - 664 sys sys 1213500942 23782
 sys/src/libventi/hangup.c - 664 sys sys 1177189441 547
 sys/src/libventi/hangup.c - 664 sys sys 1177189441 547
-sys/src/libventi/log.c - 664 sys sys 1190092827 3936
-sys/src/libventi/mem.c - 664 sys sys 1177189441 1184
+sys/src/libventi/log.c - 664 sys sys 1213500951 3742
+sys/src/libventi/mem.c - 664 sys sys 1213503856 1176
 sys/src/libventi/mkfile - 664 sys sys 1188621815 512
 sys/src/libventi/mkfile - 664 sys sys 1188621815 512
 sys/src/libventi/packet.acid - 664 sys sys 1143389340 21446
 sys/src/libventi/packet.acid - 664 sys sys 1143389340 21446
-sys/src/libventi/packet.c - 664 sys sys 1177189441 15894
+sys/src/libventi/packet.c - 664 sys sys 1213500964 15896
 sys/src/libventi/parsescore.c - 664 sys sys 1177189441 719
 sys/src/libventi/parsescore.c - 664 sys sys 1177189441 719
 sys/src/libventi/queue.c - 664 sys sys 1177189441 1571
 sys/src/libventi/queue.c - 664 sys sys 1177189441 1571
 sys/src/libventi/queue.h - 664 sys sys 1177189441 233
 sys/src/libventi/queue.h - 664 sys sys 1177189441 233
@@ -15862,7 +15853,7 @@ sys/src/libventi/root.c - 664 sys sys 1177189441 1218
 sys/src/libventi/rpc.acid - 664 sys sys 1143491745 12592
 sys/src/libventi/rpc.acid - 664 sys sys 1143491745 12592
 sys/src/libventi/rpc.c - 664 sys sys 1177189442 3174
 sys/src/libventi/rpc.c - 664 sys sys 1177189442 3174
 sys/src/libventi/scorefmt.c - 664 sys sys 1177189442 248
 sys/src/libventi/scorefmt.c - 664 sys sys 1177189442 248
-sys/src/libventi/send.c - 664 sys sys 1177189442 4395
+sys/src/libventi/send.c - 664 sys sys 1213500967 4396
 sys/src/libventi/server.c - 664 sys sys 1179957527 3693
 sys/src/libventi/server.c - 664 sys sys 1179957527 3693
 sys/src/libventi/srvhello.c - 664 sys sys 1177189442 833
 sys/src/libventi/srvhello.c - 664 sys sys 1177189442 833
 sys/src/libventi/strdup.c - 664 sys sys 1177189442 201
 sys/src/libventi/strdup.c - 664 sys sys 1177189442 201

+ 38 - 0
dist/replica/plan9.log

@@ -19847,3 +19847,41 @@
 1213362005 0 c sys/games/lib/fortunes - 664 sys sys 1213360784 269499
 1213362005 0 c sys/games/lib/fortunes - 664 sys sys 1213360784 269499
 1213470005 0 c sys/man/1/vac - 664 sys sys 1213469074 4017
 1213470005 0 c sys/man/1/vac - 664 sys sys 1213469074 4017
 1213475409 0 c sys/man/1/vac - 664 sys sys 1161727008 3244
 1213475409 0 c sys/man/1/vac - 664 sys sys 1161727008 3244
+1213502404 0 c sys/src/libventi/file.c - 664 sys sys 1213500942 23782
+1213502404 1 c sys/src/libventi/log.c - 664 sys sys 1213500951 3742
+1213502404 2 c sys/src/libventi/packet.c - 664 sys sys 1213500964 15896
+1213502404 3 c sys/src/libventi/send.c - 664 sys sys 1213500967 4396
+1213504204 0 c sys/man/1/vac - 664 sys sys 1213503568 4017
+1213504204 1 c sys/src/cmd/vac/dat.h - 664 sys sys 1213498239 801
+1213504204 2 c sys/src/cmd/vac/error.c - 664 sys sys 1213498239 709
+1213504204 3 c sys/src/cmd/vac/error.h - 664 sys sys 1213498239 444
+1213504204 4 c sys/src/cmd/vac/file.c - 664 sys sys 1213501512 37620
+1213504204 5 c sys/src/cmd/vac/fns.h - 664 sys sys 1213498239 738
+1213504204 6 c sys/src/cmd/vac/mkfile - 664 sys sys 1213498239 333
+1213504204 7 c sys/src/cmd/vac/pack.c - 664 sys sys 1213498240 11976
+1213504204 8 c sys/src/cmd/vac/stdinc.h - 664 sys sys 1213498240 92
+1213504204 9 a sys/src/cmd/vac/unvac.c - 664 sys sys 1213498240 5455
+1213504204 10 c sys/src/cmd/vac/vac.c - 664 sys sys 1213498240 12468
+1213504204 11 c sys/src/cmd/vac/vac.h - 664 sys sys 1213503433 3824
+1213504204 12 c sys/src/cmd/vac/vacfs.c - 664 sys sys 1213498240 14179
+1213504204 13 c sys/src/cmd/vac/vtdump.c - 664 sys sys 1213498240 6977
+1213504204 14 c sys/src/libventi/mem.c - 664 sys sys 1213503856 1176
+1213504204 15 d sys/src/cmd/vac/wtest.c - 664 sys sys 1019678788 0
+1213504204 16 d sys/src/cmd/vac/vtread.c - 664 sys sys 1162951740 0
+1213504204 17 d sys/src/cmd/vac/vactest.c - 664 sys sys 1036024047 0
+1213504204 18 d sys/src/cmd/vac/util.c - 664 sys sys 1019678787 0
+1213504204 19 d sys/src/cmd/vac/srcload.c - 664 sys sys 1036024047 0
+1213504204 20 d sys/src/cmd/vac/source.c - 664 sys sys 1162327879 0
+1213504204 21 d sys/src/cmd/vac/rtest.c - 664 sys sys 1019678787 0
+1213504204 22 d sys/src/cmd/vac/fs.c - 664 sys sys 1189020075 0
+1213504204 23 d sys/src/cmd/vac/cache.c - 664 sys sys 1189020077 0
+1213506005 0 c sys/src/cmd/vac/unvac.c - 664 sys sys 1213504395 5186
+1213506005 1 c sys/src/cmd/vac/vac.c - 664 sys sys 1213504573 11455
+1213506005 2 c sys/src/cmd/vac/vacfs.c - 664 sys sys 1213504498 13305
+1213560004 0 c sys/src/cmd/vac/file.c - 664 sys sys 1213558399 38892
+1213560004 1 c sys/src/cmd/vac/fns.h - 664 sys sys 1213558385 778
+1213560004 2 c sys/src/cmd/vac/pack.c - 664 sys sys 1213558400 11975
+1213560004 3 c sys/src/cmd/vac/vac.c - 664 sys sys 1213558401 12310
+1213560004 4 c sys/src/cmd/vac/vac.h - 664 sys sys 1213558389 3987
+1213560004 5 c sys/src/cmd/vac/vacfs.c - 664 sys sys 1213558401 13323
+1213560004 6 d sys/src/cmd/vac/vtdump.c - 664 sys sys 1213498240 0

+ 39 - 1
sys/man/1/vac

@@ -1,6 +1,6 @@
 .TH VAC 1
 .TH VAC 1
 .SH NAME
 .SH NAME
-vac \- create a vac archive on Venti
+vac, unvac \- create, extract a vac archive on Venti
 .SH SYNOPSIS
 .SH SYNOPSIS
 .B vac
 .B vac
 [
 [
@@ -25,6 +25,18 @@ vac \- create a vac archive on Venti
 .I host
 .I host
 ]
 ]
 .I file ...
 .I file ...
+.PP
+.B unvac
+[
+.B -Tctv
+] [
+.B -h
+.I host
+]
+.I vacfile
+[
+.I file ...
+]
 .SH DESCRIPTION
 .SH DESCRIPTION
 .I Vac
 .I Vac
 creates an archival copy of Plan 9 file trees on Venti. It can be used
 creates an archival copy of Plan 9 file trees on Venti. It can be used
@@ -123,6 +135,32 @@ Print out various statistics on standard error.
 .B -v
 .B -v
 Produce more verbose output on standard error, including the name of the files added to the archive
 Produce more verbose output on standard error, including the name of the files added to the archive
 and the vac archives that are expanded and merged.
 and the vac archives that are expanded and merged.
+.PP
+.I Unvac
+lists or extracts files stored in the vac archive
+.IR vacfile ,
+which can be either a vac archive string in the format
+given above or the name of a file containing one.
+If
+.I file
+arguments are given, only those files or directories
+will be extracted.
+The options are:
+.TP
+.B -T
+Set the modification time on extracted files
+to the time listed in the archive.
+.TP
+.B -c
+Write extracted files to standard output instead of creating a file.
+.TP
+.B -t
+Print a list of the files to standard output rather than extracting them.
+.TP
+.B -v
+If extracting files, print the name of each file and directory
+to standard error.
+If listing files, print metadata in addition to the names.
 .SH SOURCE
 .SH SOURCE
 .B /sys/src/cmd/vac
 .B /sys/src/cmd/vac
 .SH "SEE ALSO"
 .SH "SEE ALSO"

+ 0 - 877
sys/src/cmd/vac/cache.c

@@ -1,877 +0,0 @@
-#include "stdinc.h"
-#include "vac.h"
-#include "dat.h"
-#include "fns.h"
-
-typedef struct Label Label;
-
-enum {
-	BadHeap = ~0,
-};
-
-/*
- * the plan is to store data to the cache in c->size blocks
- * with the block zero extended to fill it out.  When writing to
- * venti, the block will be zero truncated.  The walker will also check
- * that the block fits within psize or dsize as the case may be.
- */
-
-struct Cache
-{
-	VtLock	*lk;
-	VtSession *z;
-	u32int	now;			/* ticks for usage timestamps */
-	int	size;			/* max. size of any block; allocated to each block */
-	Lump	**heads;		/* hash table for finding address */
-	int	nheap;			/* number of available victims */
-	Lump	**heap;			/* heap for locating victims */
-	long	nblocks;		/* number of blocks allocated */
-	Lump	*blocks;		/* array of block descriptors */
-	u8int	*mem;			/* memory for all block descriptors */
-	Lump	*free;			/* free list of lumps */
-
-	long hashSize;
-};
-
-/*
- * the tag for a block is hash(index, parent tag)
- */
-
-struct Label {
-	uchar gen[4];
-	uchar state;
-	uchar type;		/* top bit indicates it is part of a directory */
-	uchar tag[4];		/* tag of file it is in */
-};
-
-
-static char ENoDir[] = "directory entry is not allocated";
-
-static void fixHeap(int si, Lump *b);
-static int upHeap(int i, Lump *b);
-static int downHeap(int i, Lump *b);
-static char	*lumpState(int);
-static void	lumpSetState(Lump *u, int state);
-
-Cache *
-cacheAlloc(VtSession *z, int blockSize, long nblocks)
-{
-	int i;
-	Cache *c;
-	Lump *b;
-
-	c = vtMemAllocZ(sizeof(Cache));
-	
-	c->lk = vtLockAlloc();
-	c->z = z;
-	c->size = blockSize;
-	c->nblocks = nblocks;
-	c->hashSize = nblocks;
-	c->heads = vtMemAllocZ(c->hashSize*sizeof(Lump*));
-	c->heap = vtMemAllocZ(nblocks*sizeof(Lump*));
-	c->blocks = vtMemAllocZ(nblocks*sizeof(Lump));
-	c->mem = vtMemAllocZ(nblocks * blockSize);
-	for(i = 0; i < nblocks; i++){
-		b = &c->blocks[i];
-		b->lk = vtLockAlloc();
-		b->c = c;
-		b->data = &c->mem[i * blockSize];
-		b->addr = i+1;
-		b->state = LumpFree;
-		b->heap = BadHeap;
-		b->next = c->free;
-		c->free = b;
-	}
-	c->nheap = 0;
-
-	return c;
-}
-
-long
-cacheGetSize(Cache *c)
-{
-	return c->nblocks;
-}
-
-int
-cacheGetBlockSize(Cache *c)
-{
-	return c->size;
-}
-
-int
-cacheSetSize(Cache *c, long nblocks)
-{
-	USED(c);
-	USED(nblocks);
-	return 0;
-}
-
-void
-cacheFree(Cache *c)
-{
-	int i;
-
-	for(i = 0; i < c->nblocks; i++){
-		assert(c->blocks[i].ref == 0);
-		vtLockFree(c->blocks[i].lk);
-	}
-	vtMemFree(c->heads);
-	vtMemFree(c->blocks);
-	vtMemFree(c->mem);
-	vtMemFree(c);
-}
-
-static u32int
-hash(Cache *c, uchar score[VtScoreSize], int type)
-{
-	u32int h;
-	uchar *p = score + VtScoreSize-4;
-
-	h = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
-	h += type;
-	return h % c->hashSize;
-}
-
-static void
-findLump(Cache *c, Lump *bb)
-{
-	Lump *b, *last;
-	int h;
-
-	last = nil;
-	h = hash(c, bb->score, bb->type);
-	for(b = c->heads[h]; b != nil; b = b->next){
-		if(last != b->prev)
-			vtFatal("bad prev link");
-		if(b == bb)
-			return;
-		last = b;
-	}
-	vtFatal("block missing from hash table");
-}
-
-void
-cacheCheck(Cache *c)
-{
-	u32int size, now;
-	int i, k, refed, free;
-	static uchar zero[VtScoreSize];
-	Lump *p;
-
-	size = c->size;
-	now = c->now;
-
-	free = 0;
-	for(p=c->free; p; p=p->next)
-		free++;
-	for(i = 0; i < c->nheap; i++){
-		if(c->heap[i]->heap != i)
-			vtFatal("mis-heaped at %d: %d", i, c->heap[i]->heap);
-		if(i > 0 && c->heap[(i - 1) >> 1]->used2 - now > c->heap[i]->used2 - now)
-			vtFatal("bad heap ordering");
-		k = (i << 1) + 1;
-		if(k < c->nheap && c->heap[i]->used2 - now > c->heap[k]->used2 - now)
-			vtFatal("bad heap ordering");
-		k++;
-		if(k < c->nheap && c->heap[i]->used2 - now > c->heap[k]->used2 - now)
-			vtFatal("bad heap ordering");
-	}
-
-	refed = 0;
-	for(i = 0; i < c->nblocks; i++){
-		if(c->blocks[i].data != &c->mem[i * size])
-			vtFatal("mis-blocked at %d", i);
-		if(c->blocks[i].ref && c->blocks[i].heap == BadHeap){
-			refed++;
-		}
-		if(memcmp(zero, c->blocks[i].score, VtScoreSize))
-			findLump(c, &c->blocks[i]);
-	}
-if(refed > 0)fprint(2, "cacheCheck: nheap %d refed %d free %d\n", c->nheap, refed, free);
-	assert(c->nheap + refed + free == c->nblocks);
-	refed = 0;
-	for(i = 0; i < c->nblocks; i++){
-		if(c->blocks[i].ref) {
-if(1)fprint(2, "%d %V %d %s\n", c->blocks[i].type, c->blocks[i].score, c->blocks[i].ref, lumpState(c->blocks[i].state));
-			refed++;
-		}
-	}
-if(refed > 0)fprint(2, "cacheCheck: in used %d\n", refed);
-}
-
-/*
- * delete an arbitrary block from the heap
- */
-static void
-delHeap(Lump *db)
-{
-	fixHeap(db->heap, db->c->heap[--db->c->nheap]);
-	db->heap = BadHeap;
-}
-
-static void
-fixHeap(int si, Lump *b)
-{
-	int i;
-
-	i = upHeap(si, b);
-	if(i == si)
-		downHeap(i, b);
-}
-
-static int
-upHeap(int i, Lump *b)
-{
-	Lump *bb;
-	u32int now;
-	int p;
-	Cache *c;
-	
-	c = b->c;
-	now = c->now;
-	for(; i != 0; i = p){
-		p = (i - 1) >> 1;
-		bb = c->heap[p];
-		if(b->used2 - now >= bb->used2 - now)
-			break;
-		c->heap[i] = bb;
-		bb->heap = i;
-	}
-	c->heap[i] = b;
-	b->heap = i;
-
-	return i;
-}
-
-static int
-downHeap(int i, Lump *b)
-{
-	Lump *bb;
-	u32int now;
-	int k;
-	Cache *c;
-	
-	c = b->c;
-	now = c->now;
-	for(; ; i = k){
-		k = (i << 1) + 1;
-		if(k >= c->nheap)
-			break;
-		if(k + 1 < c->nheap && c->heap[k]->used2 - now > c->heap[k + 1]->used2 - now)
-			k++;
-		bb = c->heap[k];
-		if(b->used2 - now <= bb->used2 - now)
-			break;
-		c->heap[i] = bb;
-		bb->heap = i;
-	}
-	c->heap[i] = b;
-	b->heap = i;
-	return i;
-}
-
-
-/* called with c->lk held */
-Lump *
-cacheBumpLump(Cache *c)
-{
-	Lump *b;
-
-	/*
-	 * missed: locate the block with the oldest second to last use.
-	 * remove it from the heap, and fix up the heap.
-	 */
-	if(c->free) {
-		b = c->free;
-		c->free = b->next;
-	} else {
-		for(;;){
-			if(c->nheap == 0) {
-				cacheCheck(c);
-				assert(0);
-				return nil;
-			}
-			b = c->heap[0];
-			delHeap(b);
-			if(b->ref == 0)
-				break;
-		}
-
-		/*
-		 * unchain the block from hash chain
-		 */
-		if(b->prev == nil)
-			c->heads[hash(c, b->score, b->type)] = b->next;
-		else
-			b->prev->next = b->next;
-		if(b->next != nil)
-			b->next->prev = b->prev;
-
-	}
-
-	/*
-	 * the new block has no last use, so assume it happens sometime in the middle
-	 */
-	b->used = (b->used2 + c->now) / 2;
-	b->asize = 0;
-
-	return b;
-}
-
-Lump *
-cacheAllocLump(Cache *c, int type, int size, int dir)
-{
-	Lump *b;
-	ulong h;
-
-	assert(size <= c->size);
-
-again:
-	vtLock(c->lk);
-	b = cacheBumpLump(c);
-	if(b == nil) {
-		vtUnlock(c->lk);
-fprint(2, "cache is full\n");
-		/* XXX should be better */
-		sleep(100);
-		goto again;
-	}
-
-	vtLock(b->lk);
-
-	assert(b->ref == 0);
-	b->ref++;
-	b->used2 = b->used;
-	b->used = c->now++;
-
-	/* convert addr into score */
-	memset(b->score, 0, VtScoreSize-4);
-	b->score[VtScoreSize-4] = b->addr>>24;
-	b->score[VtScoreSize-3] = b->addr>>16;
-	b->score[VtScoreSize-2] = b->addr>>8;
-	b->score[VtScoreSize-1] = b->addr;
-	
-	b->dir = dir;
-	b->type = type;
-	b->gen = 0;
-	b->asize = size;
-	b->state = LumpFree;
-
-	h = hash(c, b->score, b->type);
-
-	/* chain onto correct hash */
-	b->next = c->heads[h];
-	c->heads[h] = b;
-	if(b->next != nil)
-		b->next->prev = b;
-	b->prev = nil;
-
-	vtUnlock(c->lk);
-
-	vtZeroExtend(type, b->data, 0, size);
-	lumpSetState(b, LumpActive);
-
-	return b;
-}
-
-int
-scoreIsLocal(uchar score[VtScoreSize])
-{
-	static uchar zero[VtScoreSize];
-	
-	return memcmp(score, zero, VtScoreSize-4) == 0;
-}
-
-Lump *
-cacheGetLump(Cache *c, uchar score[VtScoreSize], int type, int size)
-{
-	Lump *b;
-	ulong h;
-	int n;
-	static uchar zero[VtScoreSize];
-
-	assert(size <= c->size);
-
-	h = hash(c, score, type);
-
-again:
-	/*
-	 * look for the block in the cache
-	 */
-	vtLock(c->lk);
-	for(b = c->heads[h]; b != nil; b = b->next){
-		if(memcmp(b->score, score, VtScoreSize) == 0 && b->type == type)
-			goto found;
-	}
-
-	/* should not be looking for a temp block */
-	if(scoreIsLocal(score)) {
-		if(memcmp(score, zero, VtScoreSize) == 0)
-			vtSetError("looking for zero score");
-		else
-			vtSetError("missing local block");
-		vtUnlock(c->lk);
-		return nil;
-	}
-
-	b = cacheBumpLump(c);
-	if(b == nil) {
-		vtUnlock(c->lk);
-		sleep(100);
-		goto again;
-	}
-
-	/* chain onto correct hash */
-	b->next = c->heads[h];
-	c->heads[h] = b;
-	if(b->next != nil)
-		b->next->prev = b;
-	b->prev = nil;
-
-	memmove(b->score, score, VtScoreSize);	
-	b->type = type;
-	b->state = LumpFree;
-
-found:
-	b->ref++;
-	b->used2 = b->used;
-	b->used = c->now++;
-	if(b->heap != BadHeap)
-		fixHeap(b->heap, b);
-
-	vtUnlock(c->lk);
-
-	vtLock(b->lk);
-	if(b->state != LumpFree)
-		return b;
-	
-	n = vtRead(c->z, score, type, b->data, size);
-	if(n < 0) {
-		fprint(2, "read %V: %r\n", score);
-		lumpDecRef(b, 1);
-		return nil;
-	}
-	if(!vtSha1Check(score, b->data, n)) {
-		vtSetError("vtSha1Check failed");
-		lumpDecRef(b, 1);
-		return nil;
-	}
-	vtZeroExtend(type, b->data, n, size);
-	b->asize = size;
-	lumpSetState(b, LumpVenti);
-
-	return b;
-}
-
-static char *
-lumpState(int state)
-{
-	switch(state) {
-	default:
-		return "Unknown!!";
-	case LumpFree:
-		return "Free";
-	case LumpActive:
-		return "Active";
-	case LumpSnap:
-		return "Snap";
-	case LumpZombie:
-		return "Zombie";
-	case LumpVenti:
-		return "Venti";
-	}
-}
-
-static void
-lumpSetState(Lump *u, int state)
-{
-//	if(u->state != LumpFree)
-//		fprint(2, "%V: %s -> %s\n", u->score, lumpState(u->state), lumpState(state));
-	u->state = state;
-}
-	
-int
-lumpGetScore(Lump *u, int offset, uchar score[VtScoreSize])
-{
-	uchar *sp;
-	VtRoot root;
-	VtEntry dir;
-
-	vtLock(u->lk);
-
-	switch(u->type) {
-	default:
-		vtSetError("bad type");
-		goto Err;
-	case VtPointerType0:
-	case VtPointerType1:
-	case VtPointerType2:
-	case VtPointerType3:
-	case VtPointerType4:
-	case VtPointerType5:
-	case VtPointerType6:
-		if((offset+1)*VtScoreSize > u->asize)
-			sp = nil;
-		else
-			sp = u->data + offset*VtScoreSize;
-		break;
-	case VtRootType:
-		if(u->asize < VtRootSize) {
-			vtSetError("runt root block");
-			goto Err;
-		}
-		if(!vtRootUnpack(&root, u->data))
-			goto Err;
-		sp = root.score;
-		break;
-	case VtDirType:
-		if((offset+1)*VtEntrySize > u->asize) {
-			vtSetError(ENoDir);
-			goto Err;
-		}
-		if(!vtEntryUnpack(&dir, u->data, offset))
-			goto Err;
-		if(!dir.flags & VtEntryActive) {
-			vtSetError(ENoDir);
-			goto Err;
-		}
-		sp = dir.score;
-		break;
-	}
-
-	if(sp == nil)
-		memmove(score, vtZeroScore, VtScoreSize);
-	else
-		memmove(score, sp, VtScoreSize);
-
-	vtUnlock(u->lk);
-	return !scoreIsLocal(score);
-Err:
-	vtUnlock(u->lk);
-	return 0;
-}
-
-Lump *
-lumpWalk(Lump *u, int offset, int type, int size, int readOnly, int lock)
-{
-	Lump *v, *vv;
-	Cache *c;
-	uchar score[VtScoreSize], *sp;
-	VtRoot root;
-	VtEntry dir;
-	int split, isdir;
-
-	c = u->c;
-	vtLock(u->lk);
-
-Again:
-	v = nil;
-	vv = nil;
-
-	isdir = u->dir;
-	switch(u->type) {
-	default:
-		vtSetError("bad type");
-		goto Err;
-	case VtPointerType0:
-	case VtPointerType1:
-	case VtPointerType2:
-	case VtPointerType3:
-	case VtPointerType4:
-	case VtPointerType5:
-	case VtPointerType6:
-		if((offset+1)*VtScoreSize > u->asize)
-			sp = nil;
-		else
-			sp = u->data + offset*VtScoreSize;
-		break;
-	case VtRootType:
-		if(u->asize < VtRootSize) {
-			vtSetError("runt root block");
-			goto Err;
-		}
-		if(!vtRootUnpack(&root, u->data))
-			goto Err;
-		sp = root.score;
-		break;
-	case VtDirType:
-		if((offset+1)*VtEntrySize > u->asize) {
-			vtSetError(ENoDir);
-			goto Err;
-		}
-		if(!vtEntryUnpack(&dir, u->data, offset))
-			goto Err;
-		if(!(dir.flags & VtEntryActive)) {
-			vtSetError(ENoDir);
-			goto Err;
-		}
-		isdir = (dir.flags & VtEntryDir) != 0;
-//		sp = dir.score;
-		sp = u->data + offset*VtEntrySize + 20;
-		break;
-	}
-
-	if(sp == nil)
-		memmove(score, vtZeroScore, VtScoreSize);
-	else
-		memmove(score, sp, VtScoreSize);
-	
-	vtUnlock(u->lk);
-
-
-if(0)fprint(2, "lumpWalk: %V:%s %d:%d-> %V:%d\n", u->score, lumpState(u->state), u->type, offset, score, type);
-	v = cacheGetLump(c, score, type, size);
-	if(v == nil)
-		return nil;
-
-	split = 1;
-	if(readOnly)
-		split = 0;
-
-	switch(v->state) {
-	default:
-		assert(0);
-	case LumpFree:
-fprint(2, "block is free %V!\n", v->score);
-		vtSetError("phase error");
-		goto Err2;
-	case LumpActive:	
-		if(v->gen < u->gen) {
-print("LumpActive gen\n");
-			lumpSetState(v, LumpSnap);
-			v->gen = u->gen;
-		} else
-			split = 0;
-		break;
-	case LumpSnap:
-	case LumpVenti:
-		break;
-	}
-	
-	/* easy case */
-	if(!split) {
-		if(!lock)
-			vtUnlock(v->lk);
-		return v;
-	}
-
-	if(sp == nil) {
-		vtSetError("bad offset");
-		goto Err2;
-	}
-
-	vv = cacheAllocLump(c, v->type, size, isdir);
-	/* vv is locked */
-	vv->gen = u->gen;
-	memmove(vv->data, v->data, v->asize);
-if(0)fprint(2, "split %V into %V\n", v->score, vv->score);
-
-	lumpDecRef(v, 1);
-	v = nil;
-
-	vtLock(u->lk);
-	if(u->state != LumpActive) {
-		vtSetError("bad parent state: can not happen");
-		goto Err;
-	}
-
-	/* check that nothing changed underfoot */
-	if(memcmp(sp, score, VtScoreSize) != 0) {
-		lumpDecRef(vv, 1);
-fprint(2, "lumpWalk: parent changed under foot\n");
-		goto Again;
-	}
-
-	/* XXX - hold Active blocks up - will go eventually */
-	lumpIncRef(vv);
-
-	/* change the parent */
-	memmove(sp, vv->score, VtScoreSize);
-	
-	vtUnlock(u->lk);
-	
-	if(!lock)
-		vtUnlock(vv->lk);
-	return vv;
-Err:
-	vtUnlock(u->lk);
-	lumpDecRef(v, 0);
-	lumpDecRef(vv, 1);
-	return nil;
-Err2:
-	lumpDecRef(v, 1);
-	return nil;
-	
-}
-
-void
-lumpFreeEntry(Lump *u, int entry)
-{
-	uchar score[VtScoreSize];
-	int type;
-	ulong gen;
-	VtEntry dir;
-	Cache *c;
-
-	c = u->c;
-	vtLock(u->lk);
-	if(u->state == LumpVenti)
-		goto Exit;
-
-	switch(u->type) {
-	default:
-		fprint(2, "freeing bad lump type: %d\n", u->type);
-		return;
-	case VtPointerType0:
-		if((entry+1)*VtScoreSize > u->asize)
-			goto Exit;
-		memmove(score, u->data + entry*VtScoreSize, VtScoreSize);
-		memmove(u->data + entry*VtScoreSize, vtZeroScore, VtScoreSize);
-		type = u->dir?VtDirType:VtDataType;
-		break;
-	case VtPointerType1:
-	case VtPointerType2:
-	case VtPointerType3:
-	case VtPointerType4:
-	case VtPointerType5:
-	case VtPointerType6:
-		if((entry+1)*VtScoreSize > u->asize)
-			goto Exit;
-		memmove(score, u->data + entry*VtScoreSize, VtScoreSize);
-		memmove(u->data + entry*VtScoreSize, vtZeroScore, VtScoreSize);
-		type = u->type-1;
-		break;
-	case VtDirType:
-		if((entry+1)*VtEntrySize > u->asize)
-			goto Exit;
-		if(!vtEntryUnpack(&dir, u->data, entry))
-			goto Exit;
-		if(!dir.flags & VtEntryActive)
-			goto Exit;
-		gen = dir.gen;
-		if(gen != ~0)
-			gen++;
-		if(dir.depth == 0)
-			type = (dir.flags&VtEntryDir)?VtDirType:VtDataType;
-		else
-			type = VtPointerType0 + dir.depth - 1;
-		memmove(score, dir.score, VtScoreSize);
-		memset(&dir, 0, sizeof(dir));
-		dir.gen = gen;
-		vtEntryPack(&dir, u->data, entry);
-		break;
-	case VtDataType:
-		type = VtErrType;
-		break;
-	}
-	vtUnlock(u->lk);
-	if(type == VtErrType || !scoreIsLocal(score))
-		return;
-
-	u = cacheGetLump(c, score, type, c->size);
-	if(u == nil)
-		return;
-	lumpDecRef(u, 1);
-	/* XXX remove extra reference */
-	lumpDecRef(u, 0);
-	return;
-Exit:
-	vtUnlock(u->lk);
-	return;
-
-}
-
-void
-lumpCleanup(Lump *u)
-{
-	int i, n;
-
-	switch(u->type) {
-	default:
-		return;
-	case VtPointerType0:
-	case VtPointerType1:
-	case VtPointerType2:
-	case VtPointerType3:
-	case VtPointerType4:
-	case VtPointerType5:
-	case VtPointerType6:
-		n = u->asize/VtScoreSize;
-		break;	
-	case VtDirType:
-		n = u->asize/VtEntrySize;
-		break;
-	}
-
-	for(i=0; i<n; i++)
-		lumpFreeEntry(u, i);
-}
-
-
-void
-lumpDecRef(Lump *b, int unlock)
-{
-	int i;
-	Cache *c;
-
-	if(b == nil)
-		return;
-
-	if(unlock)
-		vtUnlock(b->lk);
-
-	c = b->c;
-	vtLock(c->lk);
-	if(--b->ref > 0) {
-		vtUnlock(c->lk);
-		return;
-	}
-	assert(b->ref == 0);
-
-	switch(b->state) {
-	default:
-		fprint(2, "bad state: %s\n", lumpState(b->state));
-		assert(0);
-	case LumpActive:
-		/* hack - but will do for now */
-		b->ref++;
-		vtUnlock(c->lk);
-		lumpCleanup(b);
-		vtLock(c->lk);
-		b->ref--;
-		lumpSetState(b, LumpFree);
-		break;
-	case LumpZombie:
-		lumpSetState(b, LumpFree);
-		break;
-	case LumpFree:
-	case LumpVenti:
-		break;
-	}
-
-	/*
-	 * reinsert in the free heap
-	 */
-	if(b->heap == BadHeap) {
-		i = upHeap(c->nheap++, b);
-		c->heap[i] = b;
-		b->heap = i;
-	}
-
-	vtUnlock(c->lk);
-}
-
-Lump *
-lumpIncRef(Lump *b)
-{
-	Cache *c;
-
-	c = b->c;
-
-	vtLock(c->lk);
-	assert(b->ref > 0);
-	b->ref++;
-	vtUnlock(c->lk);
-	return b;
-}

+ 15 - 135
sys/src/cmd/vac/dat.h

@@ -1,62 +1,24 @@
-typedef struct Source Source;
-typedef struct VacFile VacFile;
 typedef struct MetaBlock MetaBlock;
 typedef struct MetaBlock MetaBlock;
 typedef struct MetaEntry MetaEntry;
 typedef struct MetaEntry MetaEntry;
-typedef struct Lump Lump;
-typedef struct Cache Cache;
-#pragma incomplete Cache
-
-enum {
-	NilBlock	= (~0UL),
-	MaxBlock	= (1UL<<31),
-};
 
 
+#define MaxBlock (1UL<<31)
 
 
-struct VacFS {
-	int ref;
-	
-	/* need a read write lock? */
-
-	uchar score[VtScoreSize];
-	VacFile *root;
-	
-	VtSession *z;
-	int readOnly;
-	int bsize;		/* maximum block size */
-	uvlong qid;		/* next qid */
-	Cache *cache;
+enum {
+	BytesPerEntry = 100,	/* estimate of bytes per dir entries - determines number of index entries in the block */
+	FullPercentage = 80,	/* don't allocate in block if more than this percentage full */
+	FlushSize = 200,	/* number of blocks to flush */
+	DirtyPercentage = 50	/* maximum percentage of dirty blocks */
 };
 };
 
 
 
 
-struct Source {
-	VtLock *lk;
-
-	Cache *cache;	/* immutable */
-	int readOnly;	/* immutable */
-
-	VacFile *vf;	/* pointer back */
-
-	Lump *lump;	/* lump containing venti dir entry */
-	ulong block;	/* block number within parent: immutable */
-	int entry;	/* which entry in the block: immutable */
-
-	/* most of a VtEntry, except the score */
-	ulong gen;	/* generation: immutable */
-	int dir;	/* dir flags: immutable */
-	int depth;	/* number of levels of pointer blocks */
-	int psize;	/* pointer block size: immutable */
-	int dsize;	/* data block size: immutable */
-	uvlong size;	/* size in bytes of file */
-
-	int epb;	/* dir entries per block = dize/VtEntrySize: immutable */
-};
-
-struct MetaEntry {
+struct MetaEntry
+{
 	uchar *p;
 	uchar *p;
 	ushort size;
 	ushort size;
 };
 };
 
 
-struct MetaBlock {
+struct MetaBlock
+{
 	int maxsize;		/* size of block */
 	int maxsize;		/* size of block */
 	int size;		/* size used */
 	int size;		/* size used */
 	int free;		/* free space within used size */
 	int free;		/* free space within used size */
@@ -66,93 +28,11 @@ struct MetaBlock {
 	uchar *buf;
 	uchar *buf;
 };
 };
 
 
-/*
- * contains a one block buffer
- * to avoid problems of the block changing underfoot
- * and to enable an interface that supports unget.
- */
-struct VacDirEnum {
+struct VacDirEnum
+{
 	VacFile *file;
 	VacFile *file;
-	
-	ulong block;	/* current block */
-	MetaBlock mb;	/* parsed version of block */
-	int index;	/* index in block */
-};
-
-/* Lump states */
-enum {
-	LumpFree,
-	LumpVenti,	/* on venti server: score > 2^32: just a cached copy */
-	LumpActive,	/* active */
-	LumpActiveRO,	/* active: read only block */
-	LumpActiveA,	/* active: achrived */
-	LumpSnap,	/* snapshot: */
-	LumpSnapRO,	/* snapshot: read only */
-	LumpSnapA,	/* snapshot: achived */
-	LumpZombie,	/* block with no pointer to it: waiting to be freed */
-	
-	LumpMax
-};
-
-/*
- * Each lump has a state and generation
- * The following invariants are maintained
- * 	Each lump has no more than than one parent per generation
- * 	For Active*, no child has a parent of a greater generation
- *	For Snap*, there is a snap parent of given generation and there are
- *		no parents of greater gen - implies no children of a greater gen
- *	For *RO, the lump is fixed - no change can be made - all pointers
- *		are valid venti addresses
- *	For *A, the lump is on the venti server
- *	There are no pointers to Zombie lumps
- *
- * Transitions
- *	Archiver at generation g
- *	Mutator at generation h
- *	
- *	Want to modify a lump
- *		Venti: create new Active(h)
- *		Active(x): x == h: do nothing
- *		Acitve(x): x < h: change to Snap(h-1) + add Active(h)
- *		ActiveRO(x): change to SnapRO(h-1) + add Active(h)
- *		ActiveA(x): add Active(h)
- *		Snap*(x): should not occur
- *		Zombie(x): should not occur
- *	Want to archive
- *		Active(x): x != g: should never happen
- *		Active(x): x == g fix children and free them: move to ActoveRO(g);
- *		ActiveRO(x): x != g: should never happen
- *		ActiveRO(x): x == g: wait until it hits ActiveA or SnapA
- *		ActiveA(x): done
- *		Active(x): x < g: should never happen
- *		Snap(x): x >= g: fix children, freeing all SnapA(y) x == y;
- *		SnapRO(x): wait until it hits SnapA
- *
- */
-
-
-struct Lump {
-	int ref;
-
-	Cache *c;
-
-	VtLock *lk;
-	
-	int state;
-	ulong gen;
-
-	uchar 	*data;
-	uchar	score[VtScoreSize];	/* score of packet */
-	uchar	vscore[VtScoreSize];	/* venti score - when archived */
-	u8int	type;			/* type of packet */
-	int	dir;			/* part of a directory - extension of type */
-	u16int	asize;			/* allocated size of block */
-	Lump	*next;			/* doubly linked hash chains */
-	Lump	*prev;
-	u32int	heap;			/* index in heap table */
-	u32int	used;			/* last reference times */
-	u32int	used2;
-
-	u32int	addr;			/* mutable block address */
+	u32int boff;
+	int i, n;
+	VacDir *buf;
 };
 };
 
 

+ 2 - 0
sys/src/cmd/vac/error.c

@@ -5,6 +5,8 @@
 #include "error.h"
 #include "error.h"
 
 
 char ENoDir[] = "directory entry is not allocated";
 char ENoDir[] = "directory entry is not allocated";
+char ENoFile[] = "no such file or directory";
+char EBadPath[] = "bad path";
 char EBadDir[] = "corrupted directory entry";
 char EBadDir[] = "corrupted directory entry";
 char EBadMeta[] = "corrupted meta data";
 char EBadMeta[] = "corrupted meta data";
 char ENotDir[] = "not a directory";
 char ENotDir[] = "not a directory";

+ 7 - 0
sys/src/cmd/vac/error.h

@@ -1,3 +1,8 @@
+/*
+ * Somehow <errno.h> has been included on Mac OS X
+ */
+#undef EIO
+
 extern char ENoDir[];
 extern char ENoDir[];
 extern char EBadDir[];
 extern char EBadDir[];
 extern char EBadMeta[];
 extern char EBadMeta[];
@@ -12,3 +17,5 @@ extern char ERemoved[];
 extern char ENotEmpty[];
 extern char ENotEmpty[];
 extern char EExists[];
 extern char EExists[];
 extern char ERoot[];
 extern char ERoot[];
+extern char ENoFile[];
+extern char EBadPath[];

+ 1712 - 923
sys/src/cmd/vac/file.c

@@ -4,1260 +4,2049 @@
 #include "fns.h"
 #include "fns.h"
 #include "error.h"
 #include "error.h"
 
 
+#define debug 0
+
 /*
 /*
- * locking order is upwards.  A thread can hold the lock for a VacFile
- * and then acquire the lock of its parent
+ * Vac file system.  This is a simplified version of the same code in Fossil.
+ * 
+ * The locking order in the tree is upward: a thread can hold the lock
+ * for a VacFile and then acquire the lock of f->up (the parent),
+ * but not vice-versa.
+ * 
+ * A vac file is one or two venti files.  Plain data files are one venti file,
+ * while directores are two: a venti data file containing traditional
+ * directory entries, and a venti directory file containing venti 
+ * directory entries.  The traditional directory entries in the data file
+ * contain integers indexing into the venti directory entry file.
+ * It's a little complicated, but it makes the data usable by standard
+ * tools like venti/copy.
+ *
  */
  */
+ 
+static int filemetaflush(VacFile*, char*);
 
 
-struct VacFile {
-	/* meta data for file: protected by the lk in the parent */
-	int ref;		/* holds this data structure up */
-	VacFS *fs;		/* immutable */
-
-	int	removed;	/* file has been removed */
-	int	dirty;		/* dir is dirty with respect to meta data in block */
-	ulong	block;		/* block offset withing msource for this file's meta data */
-
-	VacDir dir;		/* meta data for this file */
-
-	VacFile *up;	/* parent file */
-	VacFile *next;	/* sibling */
+struct VacFile
+{
+	VacFs	*fs;	/* immutable */
 
 
-	/* data for file */
-	VtLock *lk;		/* lock for source and msource */
-	Source *source;
-	Source *msource;	/* for directories: meta data for children */
-	VacFile *down;		/* children */
+	/* meta data for file: protected by the lk in the parent */
+	int		ref;	/* holds this data structure up */
+
+	int		partial;	/* file was never really open */
+	int		removed;	/* file has been removed */
+	int		dirty;	/* dir is dirty with respect to meta data in block */
+	u32int	boff;		/* block offset within msource for this file's metadata */
+	VacDir	dir;		/* metadata for this file */
+	VacFile	*up;		/* parent file */
+	VacFile	*next;	/* sibling */
+
+	RWLock	lk;		/* lock for the following */
+	VtFile	*source;	/* actual data */
+	VtFile	*msource;	/* metadata for children in a directory */
+	VacFile	*down;	/* children */
+	int		mode;
+	
+	uvlong	qidoffset;	/* qid offset */
 };
 };
 
 
-char *vfName(VacFile *, char *);
-
-static int vfMetaFlush(VacFile*);
-static ulong msAlloc(Source *ms, ulong, int n);
+static VacFile*
+filealloc(VacFs *fs)
+{
+	VacFile *f;
+
+	f = vtmallocz(sizeof(VacFile));
+	f->ref = 1;
+	f->fs = fs;
+	f->boff = NilBlock;
+	f->mode = fs->mode;
+	return f;
+}
 
 
 static void
 static void
-vfRUnlock(VacFile *vf)
+filefree(VacFile *f)
 {
 {
-	vtRUnlock(vf->lk);
+	vtfileclose(f->source);
+	vtfileclose(f->msource);
+	vdcleanup(&f->dir);
+	memset(f, ~0, sizeof *f);	/* paranoia */
+	vtfree(f);
 }
 }
 
 
 static int
 static int
-vfRLock(VacFile *vf)
+chksource(VacFile *f)
 {
 {
-	vtRLock(vf->lk);
-	if(vf->source == nil) {
-		vfRUnlock(vf);
-		vtSetError(ERemoved);
+	if(f->partial)
 		return 0;
 		return 0;
+
+	if(f->source == nil
+	|| ((f->dir.mode & ModeDir) && f->msource == nil)){
+		werrstr(ERemoved);
+		return -1;
+	}
+	return 0;
+}
+
+static int
+filelock(VacFile *f)
+{
+	wlock(&f->lk);
+	if(chksource(f) < 0){
+		wunlock(&f->lk);
+		return -1;
 	}
 	}
-	return 1;
+	return 0;
 }
 }
 
 
 static void
 static void
-vfUnlock(VacFile *vf)
+fileunlock(VacFile *f)
 {
 {
-	vtUnlock(vf->lk);
+	wunlock(&f->lk);
 }
 }
 
 
 static int
 static int
-vfLock(VacFile *vf)
+filerlock(VacFile *f)
 {
 {
-	vtLock(vf->lk);
-	if(vf->source == nil) {
-		vfUnlock(vf);
-		vtSetError(ERemoved);
-		return 0;
+	rlock(&f->lk);
+	if(chksource(f) < 0){
+		runlock(&f->lk);
+		return -1;
 	}
 	}
-	return 1;
+	return 0;
 }
 }
 
 
 static void
 static void
-vfMetaLock(VacFile *vf)
+filerunlock(VacFile *f)
 {
 {
-	assert(vf->up->msource != nil);
-	vtLock(vf->up->lk);
+	runlock(&f->lk);
 }
 }
 
 
+/*
+ * The file metadata, like f->dir and f->ref,
+ * are synchronized via the parent's lock.
+ * This is why locking order goes up.
+ */
 static void
 static void
-vfMetaUnlock(VacFile *vf)
+filemetalock(VacFile *f)
 {
 {
-	vtUnlock(vf->up->lk);
+	assert(f->up != nil);
+	wlock(&f->up->lk);
 }
 }
 
 
-
 static void
 static void
-vfRAccess(VacFile* vf)
+filemetaunlock(VacFile *f)
 {
 {
-	vfMetaLock(vf);
-	vf->dir.atime = time(0L);
-	vf->dirty = 1;
-	vfMetaUnlock(vf);
-	vfMetaFlush(vf);
+	wunlock(&f->up->lk);
 }
 }
 
 
-static void
-vfWAccess(VacFile* vf, char *mid)
+uvlong
+vacfilegetid(VacFile *f)
 {
 {
-	vfMetaLock(vf);
-	vf->dir.atime = vf->dir.mtime = time(0L);
-	if(strcmp(vf->dir.mid, mid) != 0) {
-		vtMemFree(vf->dir.mid);
-		vf->dir.mid = vtStrDup(mid);
-	}
-	vf->dir.mcount++;
-	vf->dirty = 1;
-	vfMetaUnlock(vf);
-	vfMetaFlush(vf);
+	/* immutable */
+fprint(2, "getid %s %lld+%lld = %lld\n", f->dir.elem, f->qidoffset, f->dir.qid, f->qidoffset+f->dir.qid);
+	return f->qidoffset + f->dir.qid;
 }
 }
 
 
-void
-vdCleanup(VacDir *dir)
+uvlong
+vacfilegetqidoffset(VacFile *f)
 {
 {
-	vtMemFree(dir->elem);
-	dir->elem = nil;
-	vtMemFree(dir->uid);
-	dir->uid = nil;
-	vtMemFree(dir->gid);
-	dir->gid = nil;
-	vtMemFree(dir->mid);
-	dir->mid = nil;
+	return f->qidoffset;
 }
 }
 
 
-void
-vdCopy(VacDir *dst, VacDir *src)
+ulong
+vacfilegetmcount(VacFile *f)
 {
 {
-	*dst = *src;
-	dst->elem = vtStrDup(src->elem);
-	dst->uid = vtStrDup(src->uid);
-	dst->gid = vtStrDup(src->gid);
-	dst->mid = vtStrDup(src->mid);
+	ulong mcount;
+
+	filemetalock(f);
+	mcount = f->dir.mcount;
+	filemetaunlock(f);
+	return mcount;
 }
 }
 
 
-static int
-mbSearch(MetaBlock *mb, char *elem, int *ri, MetaEntry *me)
+ulong
+vacfilegetmode(VacFile *f)
 {
 {
-	int i;
-	int b, t, x;
-
-	/* binary search within block */
-	b = 0;
-	t = mb->nindex;
-	while(b < t) {
-		i = (b+t)>>1;
-		if(!meUnpack(me, mb, i))
-			return 0;
-		if(mb->unbotch)
-			x = meCmpNew(me, elem);
-		else
-			x = meCmp(me, elem);
+	ulong mode;
 
 
-		if(x == 0) {
-			*ri = i;
-			return 1;
-		}
-
-		if(x < 0)
-			b = i+1;
-		else /* x > 0 */
-			t = i;
-	}
-
-	assert(b == t);
-
-	*ri = b;	/* b is the index to insert this entry */
-	memset(me, 0, sizeof(*me));
-
-	return 1;
+	filemetalock(f);
+	mode = f->dir.mode;
+	filemetaunlock(f);
+	return mode;
 }
 }
 
 
-static void
-mbInit(MetaBlock *mb, uchar *p, int n)
+int
+vacfileisdir(VacFile *f)
 {
 {
-	memset(mb, 0, sizeof(MetaBlock));
-	mb->maxsize = n;
-	mb->buf = p;
-	mb->maxindex = n/100;
-	mb->size = MetaHeaderSize + mb->maxindex*MetaIndexSize;
+	/* immutable */
+	return (f->dir.mode & ModeDir) != 0;
 }
 }
 
 
-static int
-vfMetaFlush(VacFile *vf)
+int
+vacfileisroot(VacFile *f)
 {
 {
-	VacFile *vfp;
-	Lump *u;
-	MetaBlock mb;
-	MetaEntry me, nme;
-	uchar *p;
-	int i, n, moved;
-
-//print("vfMetaFlush %s\n", vf->dir.elem);
-
-	/* assume name has not changed for the moment */
-
-	vfMetaLock(vf);
-
-	vfp = vf->up;
-	moved = 0;
-
-	u = sourceGetLump(vfp->msource, vf->block, 0, 1);
-	if(u == nil)
-		goto Err;
-
-	if(!mbUnpack(&mb, u->data, u->asize))
-		goto Err;
-	if(!mbSearch(&mb, vf->dir.elem, &i, &me) || me.p == nil)
-		goto Err;
-
-	nme = me;
-	n = vdSize(&vf->dir);
-//print("old size %d new size %d\n", me.size, n);
-	if(n <= nme.size) {
-		nme.size = n;
-	} else {
-		/* try expand entry? */
-		p = mbAlloc(&mb, n);
-//print("alloced %ld\n", p - mb.buf);
-		if(p == nil) {
-assert(0);
-			/* much more work */
-		}
-		nme.p = p;
-		nme.size = n;
-	}
-
-	mbDelete(&mb, i, &me);
-	memset(me.p, 0, me.size);
-	if(!moved) {
-		vdPack(&vf->dir, &nme);
-		mbInsert(&mb, i, &nme);
-	}
-
-	mbPack(&mb);
-	lumpDecRef(u, 1);
-
-	vf->dirty = 0;
-
-	vfMetaUnlock(vf);
-	return 1;
-
-Err:
-	lumpDecRef(u, 1);
-	vfMetaUnlock(vf);
-	return 0;
+	return f == f->fs->root;
 }
 }
 
 
-static VacFile *
-vfAlloc(VacFS *fs)
+/*
+ * The files are reference counted, and while the reference
+ * is bigger than zero, each file can be found in its parent's
+ * f->down list (chains via f->next), so that multiple threads
+ * end up sharing a VacFile* when referring to the same file.
+ *
+ * Each VacFile holds a reference to its parent.
+ */
+VacFile*
+vacfileincref(VacFile *vf)
 {
 {
-	VacFile *vf;
-
-	vf = vtMemAllocZ(sizeof(VacFile));
-	vf->lk = vtLockAlloc();
-	vf->ref = 1;
-	vf->fs = fs;
+	filemetalock(vf);
+	assert(vf->ref > 0);
+	vf->ref++;
+	filemetaunlock(vf);
 	return vf;
 	return vf;
 }
 }
 
 
-static void
-vfFree(VacFile *vf)
+int
+vacfiledecref(VacFile *f)
 {
 {
-	sourceFree(vf->source);
-	vtLockFree(vf->lk);
-	sourceFree(vf->msource);
-	vdCleanup(&vf->dir);
+	VacFile *p, *q, **qq;
 
 
-	vtMemFree(vf);
-}
+	if(f->up == nil){
+		/* never linked in */
+		assert(f->ref == 1);
+		filefree(f);
+		return 0;
+	}
+	
+	filemetalock(f);
+	f->ref--;
+	if(f->ref > 0){
+		filemetaunlock(f);
+		return -1;
+	}
+	assert(f->ref == 0);
+	assert(f->down == nil);
 
 
-/* the file is locked already */
-static VacFile *
-dirLookup(VacFile *vf, char *elem)
-{
-	int i, j, nb;
-	MetaBlock mb;
-	MetaEntry me;
-	Lump *u;
-	Source *meta;
-	VacFile *nvf;
-
-	meta = vf->msource;
-	u = nil;
-	nb = sourceGetNumBlocks(meta);
-	for(i=0; i<nb; i++) {
-		u = sourceGetLump(meta, i, 1, 1);
-		if(u == nil)
-			goto Err;
-		if(!mbUnpack(&mb, u->data, u->asize))
-			goto Err;
-		if(!mbSearch(&mb, elem, &j, &me))
-			goto Err;
-		if(me.p != nil) {
-			nvf = vfAlloc(vf->fs);
-			if(!vdUnpack(&nvf->dir, &me)) {
-				vfFree(nvf);
-				goto Err;
-			}
-			lumpDecRef(u, 1);
-			nvf->block = i;
-			return nvf;
-		}
+	if(f->source && vtfilelock(f->source, -1) >= 0){
+		vtfileflush(f->source);
+		vtfileunlock(f->source);
+	}
+	if(f->msource && vtfilelock(f->msource, -1) >= 0){
+		vtfileflush(f->msource);
+		vtfileunlock(f->msource);
+	}
+
+	/*
+	 * Flush f's directory information to the cache.
+	 */
+	filemetaflush(f, nil);
 
 
-		lumpDecRef(u, 1);
-		u = nil;
+	p = f->up;
+	qq = &p->down;
+	for(q = *qq; q; q = *qq){
+		if(q == f)
+			break;
+		qq = &q->next;
 	}
 	}
-	vtSetError("file does not exist");
-	/* fall through */
-Err:
-	lumpDecRef(u, 1);
-	return nil;
-}
+	assert(q != nil);
+	*qq = f->next;
 
 
-/* point r back at vf */
-static void
-pointback(Source *r, VacFile *vf)
-{
-	assert(r->vf == nil);
-	r->vf = vf;
+	filemetaunlock(f);
+	filefree(f);
+	vacfiledecref(p);
+	return 0;
 }
 }
 
 
-VacFile *
-vfRoot(VacFS *fs, uchar *score)
+
+/* 
+ * Construct a vacfile for the root of a vac tree, given the 
+ * venti file for the root information.  That venti file is a 
+ * directory file containing VtEntries for three more venti files:
+ * the two venti files making up the root directory, and a 
+ * third venti file that would be the metadata half of the 
+ * "root's parent".
+ *
+ * Fossil generates slightly different vac files, due to a now
+ * impossible-to-change bug, which contain a VtEntry
+ * for just one venti file, that itself contains the expected
+ * three directory entries.  Sigh.
+ */
+VacFile*
+_vacfileroot(VacFs *fs, VtFile *r)
 {
 {
-	VtEntry e;
-	Lump *u, *v;
-	Source *r, *r0, *r1, *r2;
+	int redirected;
+	char err[ERRMAX];	
+	VtBlock *b;
+	VtFile *r0, *r1, *r2;
 	MetaBlock mb;
 	MetaBlock mb;
 	MetaEntry me;
 	MetaEntry me;
 	VacFile *root, *mr;
 	VacFile *root, *mr;
 
 
+	redirected = 0;
+Top:
+	b = nil;
 	root = nil;
 	root = nil;
 	mr = nil;
 	mr = nil;
-	r0 = nil;
 	r1 = nil;
 	r1 = nil;
 	r2 = nil;
 	r2 = nil;
-	v = nil;
-	r = nil;
 
 
-	u = cacheGetLump(fs->cache, score, VtDirType, fs->bsize);
-	if(u == nil)
+	if(vtfilelock(r, -1) < 0)
+		return nil;
+	r0 = vtfileopen(r, 0, fs->mode);
+	if(debug)
+		fprint(2, "r0 %p\n", r0);
+	if(r0 == nil)
 		goto Err;
 		goto Err;
-	if(!fs->readOnly) {
-		v = cacheAllocLump(fs->cache, VtDirType, fs->bsize, 1);
-		if(v == nil) {
-			vtUnlock(u->lk);
-			goto Err;
+	r2 = vtfileopen(r, 2, fs->mode);
+	if(debug)
+		fprint(2, "r2 %p\n", r2);
+	if(r2 == nil){
+		/*
+		 * some vac files (e.g., from fossil)
+		 * have an extra layer of indirection.
+		 */
+		rerrstr(err, sizeof err);
+		if(!redirected && strstr(err, "not active")){
+			redirected = 1;
+			vtfileunlock(r);
+			r = r0;
+			goto Top;
 		}
 		}
-		v->gen = u->gen;
-		v->asize = u->asize;
-		v->state = LumpActive;
-		memmove(v->data, u->data, v->asize);
-		lumpDecRef(u, 1);
-		u = v;
-		v = nil;
-	}
-	vtUnlock(u->lk);
-	vtEntryUnpack(&e, u->data, 2);
-	if(e.flags == 0){		/* just one entry */
-		r = sourceAlloc(fs->cache, u, 0, 0, fs->readOnly);
-		if(r == nil)
-			goto Err;
-		r0 = sourceOpen(r, 0, fs->readOnly);
-		if(r0 == nil)
-			goto Err;
-		r1 = sourceOpen(r, 1, fs->readOnly);
-		if(r1 == nil)
-			goto Err;
-		r2 = sourceOpen(r, 2, fs->readOnly);
-		if(r2 == nil)
-			goto Err;
-		sourceFree(r);
-		r = nil;
-	}else{
-		r0 = sourceAlloc(fs->cache, u, 0, 0, fs->readOnly);
-		if(r0 == nil)
-			goto Err;
-		r1 = sourceAlloc(fs->cache, u, 0, 1, fs->readOnly);
-		if(r1 == nil)
-			goto Err;
-		r2 = sourceAlloc(fs->cache, u, 0, 2, fs->readOnly);
-		if(r2 == nil)
-			goto Err;
+		goto Err;
 	}
 	}
-	lumpDecRef(u, 0);
-	u = sourceGetLump(r2, 0, 1, 0);
-	if(u == nil)
+	r1 = vtfileopen(r, 1, fs->mode);
+	if(debug)
+		fprint(2, "r1 %p\n", r1);
+	if(r1 == nil)
 		goto Err;
 		goto Err;
 
 
-	mr = vfAlloc(fs);
+	mr = filealloc(fs);
 	mr->msource = r2;
 	mr->msource = r2;
-	pointback(r2, mr);
 	r2 = nil;
 	r2 = nil;
 
 
-	root = vfAlloc(fs);
+	root = filealloc(fs);
+	root->boff = 0;
 	root->up = mr;
 	root->up = mr;
 	root->source = r0;
 	root->source = r0;
-	pointback(r0, root);
 	r0 = nil;
 	r0 = nil;
 	root->msource = r1;
 	root->msource = r1;
-	pointback(r1, root);
 	r1 = nil;
 	r1 = nil;
 
 
 	mr->down = root;
 	mr->down = root;
+	vtfileunlock(r);
 
 
-	if(!mbUnpack(&mb, u->data, u->asize))
-		goto Err;
+	if(vtfilelock(mr->msource, VtOREAD) < 0)
+		goto Err1;
+	b = vtfileblock(mr->msource, 0, VtOREAD);
+	vtfileunlock(mr->msource);
+	if(b == nil)
+		goto Err1;
 
 
-	if(!meUnpack(&me, &mb, 0))
-		goto Err;
-	if(!vdUnpack(&root->dir, &me))
-		goto Err;
+	if(mbunpack(&mb, b->data, mr->msource->dsize) < 0)
+		goto Err1;
 
 
-	vfRAccess(root);
-	lumpDecRef(u, 0);
-	sourceFree(r2);
+	meunpack(&me, &mb, 0);
+	if(vdunpack(&root->dir, &me) < 0)
+		goto Err1;
+	vtblockput(b);
 
 
 	return root;
 	return root;
 Err:
 Err:
-	lumpDecRef(u, 0);
-	lumpDecRef(v, 0);
+	vtfileunlock(r);
+Err1:
+	vtblockput(b);
 	if(r0)
 	if(r0)
-		sourceFree(r0);
+		vtfileclose(r0);
 	if(r1)
 	if(r1)
-		sourceFree(r1);
+		vtfileclose(r1);
 	if(r2)
 	if(r2)
-		sourceFree(r2);
-	if(r)
-		sourceFree(r);
+		vtfileclose(r2);
 	if(mr)
 	if(mr)
-		vfFree(mr);
+		filefree(mr);
 	if(root)
 	if(root)
-		vfFree(root);
+		filefree(root);
 
 
 	return nil;
 	return nil;
 }
 }
 
 
-VacFile *
-vfWalk(VacFile *vf, char *elem)
+/*
+ * Vac directories are a sequence of metablocks, each of which
+ * contains a bunch of metaentries sorted by file name.
+ * The whole sequence isn't sorted, though, so you still have
+ * to look at every block to find a given name.
+ * Dirlookup looks in f for an element name elem.
+ * It returns a new VacFile with the dir, boff, and mode
+ * filled in, but the sources (venti files) are not, and f is 
+ * not yet linked into the tree.  These details must be taken
+ * care of by the caller.
+ *
+ * f must be locked, f->msource must not.
+ */
+static VacFile*
+dirlookup(VacFile *f, char *elem)
 {
 {
-	VacFile *nvf;
+	int i;
+	MetaBlock mb;
+	MetaEntry me;
+	VtBlock *b;
+	VtFile *meta;
+	VacFile *ff;
+	u32int bo, nb;
+
+	meta = f->msource;
+	b = nil;
+	if(vtfilelock(meta, -1) < 0)
+		return nil;
+	nb = (vtfilegetsize(meta)+meta->dsize-1)/meta->dsize;
+	for(bo=0; bo<nb; bo++){
+		b = vtfileblock(meta, bo, VtOREAD);
+		if(b == nil)
+			goto Err;
+		if(mbunpack(&mb, b->data, meta->dsize) < 0)
+			goto Err;
+		if(mbsearch(&mb, elem, &i, &me) >= 0){
+			ff = filealloc(f->fs);
+			if(vdunpack(&ff->dir, &me) < 0){
+				filefree(ff);
+				goto Err;
+			}
+fprint(2, "offset %s %lld\n", ff->dir.elem, ff->dir.qidoffset);
+			ff->qidoffset = f->qidoffset + ff->dir.qidoffset;
+			vtfileunlock(meta);
+			vtblockput(b);
+			ff->boff = bo;
+			ff->mode = f->mode;
+			return ff;
+		}
+		vtblockput(b);
+		b = nil;
+	}
+	werrstr(ENoFile);
+	/* fall through */
+Err:
+	vtfileunlock(meta);
+	vtblockput(b);
+	return nil;
+}
 
 
-	vfRAccess(vf);
+/*
+ * Open the venti file at offset in the directory f->source.
+ * f is locked.
+ */
+static VtFile *
+fileopensource(VacFile *f, u32int offset, u32int gen, int dir, uint mode)
+{
+	VtFile *r;
 
 
-	if(elem[0] == 0) {
-		vtSetError("illegal path element");
+	if((r = vtfileopen(f->source, offset, mode)) == nil)
+		return nil;
+	if(r == nil)
+		return nil;
+	if(r->gen != gen){
+		werrstr(ERemoved);
+		vtfileclose(r);
 		return nil;
 		return nil;
 	}
 	}
-	if(!vfIsDir(vf)) {
-		vtSetError("not a directory");
+	if(r->dir != dir && r->mode != -1){
+		werrstr(EBadMeta);
+		vtfileclose(r);
 		return nil;
 		return nil;
 	}
 	}
+	return r;
+}
+
+VacFile*
+vacfilegetparent(VacFile *f)
+{
+	if(vacfileisroot(f))
+		return vacfileincref(f);
+	return vacfileincref(f->up);
+}
 
 
-	if(strcmp(elem, ".") == 0) {
-		return vfIncRef(vf);
+/*
+ * Given an unlocked vacfile (directory) f,
+ * return the vacfile named elem in f.
+ * Interprets . and .. as a convenience to callers.
+ */
+VacFile*
+vacfilewalk(VacFile *f, char *elem)
+{
+	VacFile *ff;
+
+	if(elem[0] == 0){
+		werrstr(EBadPath);
+		return nil;
 	}
 	}
 
 
-	if(strcmp(elem, "..") == 0) {
-		if(vfIsRoot(vf))
-			return vfIncRef(vf);
-		return vfIncRef(vf->up);
+	if(!vacfileisdir(f)){
+		werrstr(ENotDir);
+		return nil;
 	}
 	}
 
 
-	if(!vfLock(vf))
+	if(strcmp(elem, ".") == 0)
+		return vacfileincref(f);
+
+	if(strcmp(elem, "..") == 0)
+		return vacfilegetparent(f);
+
+	if(filelock(f) < 0)
 		return nil;
 		return nil;
 
 
-	for(nvf = vf->down; nvf; nvf=nvf->next) {
-		if(strcmp(elem, nvf->dir.elem) == 0 && !nvf->removed) {
-			nvf->ref++;
+	for(ff = f->down; ff; ff=ff->next){
+		if(strcmp(elem, ff->dir.elem) == 0 && !ff->removed){
+			ff->ref++;
 			goto Exit;
 			goto Exit;
 		}
 		}
 	}
 	}
 
 
-	nvf = dirLookup(vf, elem);
-	if(nvf == nil)
+	ff = dirlookup(f, elem);
+	if(ff == nil)
 		goto Err;
 		goto Err;
-	nvf->source = sourceOpen(vf->source, nvf->dir.entry, vf->fs->readOnly);
-	if(nvf->source == nil)
+
+	if(ff->dir.mode & ModeSnapshot)
+		ff->mode = VtOREAD;
+
+	if(vtfilelock(f->source, f->mode) < 0)
 		goto Err;
 		goto Err;
-	pointback(nvf->source, nvf);
-	if(nvf->dir.mode & ModeDir) {
-		nvf->msource = sourceOpen(vf->source, nvf->dir.mentry, vf->fs->readOnly);
-		if(nvf->msource == nil)
-			goto Err;
-		pointback(nvf->msource, nvf);
+	if(ff->dir.mode & ModeDir){
+		ff->source = fileopensource(f, ff->dir.entry, ff->dir.gen, 1, ff->mode);
+		ff->msource = fileopensource(f, ff->dir.mentry, ff->dir.mgen, 0, ff->mode);
+		if(ff->source == nil || ff->msource == nil)
+			goto Err1;
+	}else{
+		ff->source = fileopensource(f, ff->dir.entry, ff->dir.gen, 0, ff->mode);
+		if(ff->source == nil)
+			goto Err1;
 	}
 	}
+	vtfileunlock(f->source);
 
 
 	/* link in and up parent ref count */
 	/* link in and up parent ref count */
-	nvf->next = vf->down;
-	vf->down = nvf;
-	nvf->up = vf;
-	vfIncRef(vf);
+	ff->next = f->down;
+	f->down = ff;
+	ff->up = f;
+	vacfileincref(f);
 Exit:
 Exit:
-	vfUnlock(vf);
-	return nvf;
+	fileunlock(f);
+	return ff;
+
+Err1:
+	vtfileunlock(f->source);
 Err:
 Err:
-	vfUnlock(vf);
-	if(nvf != nil)
-		vfFree(nvf);
+	fileunlock(f);
+	if(ff != nil)
+		vacfiledecref(ff);
 	return nil;
 	return nil;
 }
 }
 
 
-VacFile *
-vfOpen(VacFS *fs, char *path)
+/* 
+ * Open a path in the vac file system: 
+ * just walk each element one at a time.
+ */
+VacFile*
+vacfileopen(VacFs *fs, char *path)
 {
 {
-	VacFile *vf, *nvf;
-	char *p, elem[VtMaxStringSize];
+	VacFile *f, *ff;
+	char *p, elem[VtMaxStringSize], *opath;
 	int n;
 	int n;
 
 
-	vf = fs->root;
-	vfIncRef(vf);
-	while(*path != 0) {
+	f = fs->root;
+	vacfileincref(f);
+	opath = path;
+	while(*path != 0){
 		for(p = path; *p && *p != '/'; p++)
 		for(p = path; *p && *p != '/'; p++)
 			;
 			;
 		n = p - path;
 		n = p - path;
-		if(n > 0) {
-			if(n > VtMaxStringSize) {
-				vtSetError("path element too long");
+		if(n > 0){
+			if(n > VtMaxStringSize){
+				werrstr("%s: element too long", EBadPath);
 				goto Err;
 				goto Err;
 			}
 			}
 			memmove(elem, path, n);
 			memmove(elem, path, n);
 			elem[n] = 0;
 			elem[n] = 0;
-			nvf = vfWalk(vf, elem);
-			if(nvf == nil)
+			ff = vacfilewalk(f, elem);
+			if(ff == nil){
+				werrstr("%.*s: %r", utfnlen(opath, p-opath), opath);
 				goto Err;
 				goto Err;
-			vfDecRef(vf);
-			vf = nvf;
+			}
+			vacfiledecref(f);
+			f = ff;
 		}
 		}
 		if(*p == '/')
 		if(*p == '/')
 			p++;
 			p++;
 		path = p;
 		path = p;
 	}
 	}
-	return vf;
+	return f;
 Err:
 Err:
-	vfDecRef(vf);
+	vacfiledecref(f);
 	return nil;
 	return nil;
 }
 }
 
 
-VacFile *
-vfCreate(VacFile *vf, char *elem, ulong mode, char *user)
+/*
+ * Extract the score for the bn'th block in f.
+ */
+int
+vacfileblockscore(VacFile *f, u32int bn, u8int *score)
 {
 {
-	VacFile *nvf;
-	VacDir *dir;
-	int n, i;
-	uchar *p;
-	Source *pr, *r, *mr;
-	int isdir;
-	MetaBlock mb;
-	MetaEntry me;
-	Lump *u;
+	VtFile *s;
+	uvlong size;
+	int dsize, ret;
 
 
-	if(!vfLock(vf))
-		return nil;
+	ret = -1;
+	if(filerlock(f) < 0)
+		return -1;
+	if(vtfilelock(f->source, VtOREAD) < 0)
+		goto out;
 
 
-	r = nil;
-	mr = nil;
-	u = nil;
+	s = f->source;
+	dsize = s->dsize;
+	size = vtfilegetsize(s);
+	if((uvlong)bn*dsize >= size)
+		goto out;
+	ret = vtfileblockscore(f->source, bn, score);
+
+out:
+	vtfileunlock(f->source);
+	filerunlock(f);
+	return ret;
+}
 
 
-	for(nvf = vf->down; nvf; nvf=nvf->next) {
-		if(strcmp(elem, nvf->dir.elem) == 0 && !nvf->removed) {
-			nvf = nil;
-			vtSetError(EExists);
-			goto Err;
-		}
-	}
+/*
+ * Read data from f.
+ */
+int
+vacfileread(VacFile *f, void *buf, int cnt, vlong offset)
+{
+	int n;
 
 
-	nvf = dirLookup(vf, elem);
-	if(nvf != nil) {
-		vtSetError(EExists);
-		goto Err;
+	if(offset < 0){
+		werrstr(EBadOffset);
+		return -1;
 	}
 	}
-
-	nvf = vfAlloc(vf->fs);
-	isdir = mode & ModeDir;
-
-	pr = vf->source;
-	r = sourceCreate(pr, pr->psize, pr->dsize, isdir, 0);
-	if(r == nil)
-		goto Err;
-	if(isdir) {
-		mr = sourceCreate(pr, pr->psize, pr->dsize, 0, r->block*pr->epb + r->entry);
-		if(mr == nil)
-			goto Err;
+	if(filerlock(f) < 0)
+		return -1;
+	if(vtfilelock(f->source, VtOREAD) < 0){
+		filerunlock(f);
+		return -1;
 	}
 	}
+	n = vtfileread(f->source, buf, cnt, offset);
+	vtfileunlock(f->source);
+	filerunlock(f);
+	return n;
+}
 
 
-	dir = &nvf->dir;
-	dir->elem = vtStrDup(elem);
-	dir->entry = r->block*pr->epb + r->entry;
-	dir->gen = r->gen;
-	if(isdir) {
-		dir->mentry = mr->block*pr->epb + mr->entry;
-		dir->mgen = mr->gen;
+static int
+getentry(VtFile *f, VtEntry *e)
+{
+	if(vtfilelock(f, VtOREAD) < 0)
+		return -1;
+	if(vtfilegetentry(f, e) < 0){
+		vtfileunlock(f);
+		return -1;
+	}
+	vtfileunlock(f);
+	if(vtglobaltolocal(e->score) != NilBlock){
+		werrstr("internal error - data not on venti");
+		return -1;
 	}
 	}
-	dir->size = 0;
-	dir->qid = vf->fs->qid++;
-	dir->uid = vtStrDup(user);
-	dir->gid = vtStrDup(vf->dir.gid);
-	dir->mid = vtStrDup(user);
-	dir->mtime = time(0L);
-	dir->mcount = 0;
-	dir->ctime = dir->mtime;
-	dir->atime = dir->mtime;
-	dir->mode = mode;
-
-	n = vdSize(dir);
-	nvf->block = msAlloc(vf->msource, 0, n);
-	if(nvf->block == NilBlock)
-		goto Err;
-	u = sourceGetLump(vf->msource, nvf->block, 0, 1);
-	if(u == nil)
-		goto Err;
-	if(!mbUnpack(&mb, u->data, u->asize))
-		goto Err;
-	p = mbAlloc(&mb, n);
-	if(p == nil)
-		goto Err;
-
-	if(!mbSearch(&mb, elem, &i, &me))
-		goto Err;
-	assert(me.p == nil);
-	me.p = p;
-	me.size = n;
-
-	vdPack(dir, &me);
-	mbInsert(&mb, i, &me);
-	mbPack(&mb);
-	lumpDecRef(u, 1);
-
-	nvf->source = r;
-	pointback(r, nvf);
-	nvf->msource = mr;
-	pointback(mr, vf);
-
-	/* link in and up parent ref count */
-	nvf->next = vf->down;
-	vf->down = nvf;
-	nvf->up = vf;
-	vfIncRef(vf);
-
-	vfWAccess(vf, user);
-
-	vfUnlock(vf);
-	return nvf;
-
-Err:
-	lumpDecRef(u, 1);
-	if(r)
-		sourceRemove(r);
-	if(mr)
-		sourceRemove(mr);
-	if(nvf)
-		vfFree(nvf);
-	vfUnlock(vf);
 	return 0;
 	return 0;
 }
 }
 
 
+/*
+ * Get the VtEntries for the data contained in f.
+ */
 int
 int
-vfRead(VacFile *vf, void *buf, int cnt, vlong offset)
+vacfilegetentries(VacFile *f, VtEntry *e, VtEntry *me)
 {
 {
-	Source *s;
-	uvlong size;
-	ulong bn;
-	int off, dsize, n, nn;
-	Lump *u;
-	uchar *b;
-
-if(0)fprint(2, "vfRead: %s %d, %lld\n", vf->dir.elem, cnt, offset);
-
-	if(!vfRLock(vf))
+	if(filerlock(f) < 0)
+		return -1;
+	if(e && getentry(f->source, e) < 0){
+		filerunlock(f);
 		return -1;
 		return -1;
-
-	s = vf->source;
-
-	dsize = s->dsize;
-	size = sourceGetSize(s);
-
-	if(offset < 0) {
-		vtSetError(EBadOffset);
-		goto Err;
 	}
 	}
-
-	vfRAccess(vf);
-
-	if(offset >= size)
-		offset = size;
-
-	if(cnt > size-offset)
-		cnt = size-offset;
-	bn = offset/dsize;
-	off = offset%dsize;
-	b = buf;
-	while(cnt > 0) {
-		u = sourceGetLump(s, bn, 1, 0);
-		if(u == nil)
-			goto Err;
-		if(u->asize <= off) {
-			lumpDecRef(u, 0);
-			goto Err;
+	if(me){
+		if(f->msource == nil)
+			memset(me, 0, sizeof *me);
+		if(getentry(f->msource, me) < 0){
+			filerunlock(f);
+			return -1;
 		}
 		}
-		n = cnt;
-		if(n > dsize-off)
-			n = dsize-off;
-		nn = u->asize-off;
-		if(nn > n)
-			nn = n;
-		memmove(b, u->data+off, nn);
-		memset(b+nn, 0, n-nn);
-		off = 0;
-		bn++;
-		cnt -= n;
-		b += n;
-		lumpDecRef(u, 0);
-	}
-	vfRUnlock(vf);
-	return b-(uchar*)buf;
-Err:
-	vfRUnlock(vf);
-	return -1;
+	}
+	filerunlock(f);
+	return 0;
 }
 }
 
 
+/*
+ * Get the file's size.
+ */
 int
 int
-vfWrite(VacFile *vf, void *buf, int cnt, vlong offset, char *user)
+vacfilegetsize(VacFile *f, uvlong *size)
 {
 {
-	Source *s;
-	ulong bn;
-	int off, dsize, n;
-	Lump *u;
-	uchar *b;
+	if(filerlock(f) < 0)
+		return -1;
+	if(vtfilelock(f->source, VtOREAD) < 0){
+		filerunlock(f);
+		return -1;
+	}
+	*size = vtfilegetsize(f->source);
+	vtfileunlock(f->source);
+	filerunlock(f);
 
 
-	USED(user);
+	return 0;
+}
 
 
-	if(!vfLock(vf))
-		return -1;
+/*
+ * Directory reading.
+ *
+ * A VacDirEnum is a buffer containing directory entries.
+ * Directory entries contain malloced strings and need to 
+ * be cleaned up with vdcleanup.  The invariant in the 
+ * VacDirEnum is that the directory entries between
+ * vde->i and vde->n are owned by the vde and need to
+ * be cleaned up if it is closed.  Those from 0 up to vde->i
+ * have been handed to the reader, and the reader must 
+ * take care of calling vdcleanup as appropriate.
+ */
+VacDirEnum*
+vdeopen(VacFile *f)
+{
+	VacDirEnum *vde;
+	VacFile *p;
 
 
-	if(vf->fs->readOnly) {
-		vtSetError(EReadOnly);
-		goto Err;
+	if(!vacfileisdir(f)){
+		werrstr(ENotDir);
+		return nil;
 	}
 	}
 
 
-	if(vf->dir.mode & ModeDir) {
-		vtSetError(ENotFile);
+	/*
+	 * There might be changes to this directory's children
+	 * that have not been flushed out into the cache yet.
+	 * Those changes are only available if we look at the 
+	 * VacFile structures directory.  But the directory reader
+	 * is going to read the cache blocks directly, so update them.
+	 */
+	if(filelock(f) < 0)
+		return nil;
+	for(p=f->down; p; p=p->next)
+		filemetaflush(p, nil);
+	fileunlock(f);
+
+	vde = vtmallocz(sizeof(VacDirEnum));
+	vde->file = vacfileincref(f);
+
+	return vde;
+}
+
+/*
+ * Figure out the size of the directory entry at offset.
+ * The rest of the metadata is kept in the data half,
+ * but since venti has to track the data size anyway,
+ * we just use that one and avoid updating the directory
+ * each time the file size changes.
+ */
+static int
+direntrysize(VtFile *s, ulong offset, ulong gen, uvlong *size)
+{
+	VtBlock *b;
+	ulong bn;
+	VtEntry e;
+	int epb;
+
+	epb = s->dsize/VtEntrySize;
+	bn = offset/epb;
+	offset -= bn*epb;
+
+	b = vtfileblock(s, bn, VtOREAD);
+	if(b == nil)
+		goto Err;
+	if(vtentryunpack(&e, b->data, offset) < 0)
 		goto Err;
 		goto Err;
-	}
-if(0)fprint(2, "vfWrite: %s %d, %lld\n", vf->dir.elem, cnt, offset);
 
 
-	s = vf->source;
-	dsize = s->dsize;
+	/* dangling entries are returned as zero size */
+	if(!(e.flags & VtEntryActive) || e.gen != gen)
+		*size = 0;
+	else
+		*size = e.size;
+	vtblockput(b);
+	return 0;
 
 
-	if(offset < 0) {
-		vtSetError(EBadOffset);
+Err:
+	vtblockput(b);
+	return -1;
+}
+
+/*
+ * Fill in vde with a new batch of directory entries.
+ */
+static int
+vdefill(VacDirEnum *vde)
+{
+	int i, n;
+	VtFile *meta, *source;
+	MetaBlock mb;
+	MetaEntry me;
+	VacFile *f;
+	VtBlock *b;
+	VacDir *de;
+
+	/* clean up first */
+	for(i=vde->i; i<vde->n; i++)
+		vdcleanup(vde->buf+i);
+	vtfree(vde->buf);
+	vde->buf = nil;
+	vde->i = 0;
+	vde->n = 0;
+
+	f = vde->file;
+
+	source = f->source;
+	meta = f->msource;
+
+	b = vtfileblock(meta, vde->boff, VtOREAD);
+	if(b == nil)
+		goto Err;
+	if(mbunpack(&mb, b->data, meta->dsize) < 0)
 		goto Err;
 		goto Err;
-	}
 
 
-	vfWAccess(vf, user);
+	n = mb.nindex;
+	vde->buf = vtmalloc(n * sizeof(VacDir));
 
 
-	bn = offset/dsize;
-	off = offset%dsize;
-	b = buf;
-	while(cnt > 0) {
-		n = cnt;
-		if(n > dsize-off)
-			n = dsize-off;
-		if(!sourceSetDepth(s, offset+n))
-			goto Err;
-		u = sourceGetLump(s, bn, 0, 0);
-		if(u == nil)
+	for(i=0; i<n; i++){
+		de = vde->buf + i;
+		meunpack(&me, &mb, i);
+		if(vdunpack(de, &me) < 0)
 			goto Err;
 			goto Err;
-		if(u->asize < dsize) {
-			vtSetError("runt block");
-			lumpDecRef(u, 0);
-			goto Err;
-		}
-		memmove(u->data+off, b, n);
-		off = 0;
-		cnt -= n;
-		b += n;
-		offset += n;
-		bn++;
-		lumpDecRef(u, 0);
-		if(!sourceSetSize(s, offset))
+		vde->n++;
+		if(!(de->mode & ModeDir))
+		if(direntrysize(source, de->entry, de->gen, &de->size) < 0)
 			goto Err;
 			goto Err;
 	}
 	}
-	vfLock(vf);
-	return b-(uchar*)buf;
+	vde->boff++;
+	vtblockput(b);
+	return 0;
 Err:
 Err:
-	vfLock(vf);
+	vtblockput(b);
 	return -1;
 	return -1;
 }
 }
 
 
+/*
+ * Read a single directory entry from vde into de.
+ * Returns -1 on error, 0 on EOF, and 1 on success.
+ * When it returns 1, it becomes the caller's responsibility
+ * to call vdcleanup(de) to free the strings contained
+ * inside, or else to call vdunread to give it back.
+ */
 int
 int
-vfGetDir(VacFile *vf, VacDir *dir)
+vderead(VacDirEnum *vde, VacDir *de)
 {
 {
-	if(!vfRLock(vf))
-		return 0;
+	int ret;
+	VacFile *f;
+	u32int nb;
+
+	f = vde->file;
+	if(filerlock(f) < 0)
+		return -1;
+
+	if(vtfilelock2(f->source, f->msource, VtOREAD) < 0){
+		filerunlock(f);
+		return -1;
+	}
+
+	nb = (vtfilegetsize(f->msource)+f->msource->dsize-1)/f->msource->dsize;
+
+	while(vde->i >= vde->n){
+		if(vde->boff >= nb){
+			ret = 0;
+			goto Return;
+		}
+		if(vdefill(vde) < 0){
+			ret = -1;
+			goto Return;
+		}
+	}
 
 
-	vfMetaLock(vf);
-	vdCopy(dir, &vf->dir);
-	vfMetaUnlock(vf);
+	memmove(de, vde->buf + vde->i, sizeof(VacDir));
+	vde->i++;
+	ret = 1;
 
 
-	if(!vfIsDir(vf))
-		dir->size = sourceGetSize(vf->source);
-	vfRUnlock(vf);
+Return:
+	vtfileunlock(f->source);
+	vtfileunlock(f->msource);
+	filerunlock(f);
 
 
-	return 1;
+	return ret;
 }
 }
 
 
-uvlong
-vfGetId(VacFile *vf)
+/*
+ * "Unread" the last directory entry that was read,
+ * so that the next vderead will return the same one.
+ * If the caller calls vdeunread(vde) it should not call
+ * vdcleanup on the entry being "unread".
+ */
+int
+vdeunread(VacDirEnum *vde)
 {
 {
-	/* immutable */
-	return vf->dir.qid;
+	if(vde->i > 0){
+		vde->i--;
+		return 0;
+	}
+	return -1;
 }
 }
 
 
-ulong
-vfGetMcount(VacFile *vf)
+/*
+ * Close the enumerator.
+ */
+void
+vdeclose(VacDirEnum *vde)
 {
 {
-	ulong mcount;
-
-	vfMetaLock(vf);
-	mcount = vf->dir.mcount;
-	vfMetaUnlock(vf);
-	return mcount;
+	int i;
+	if(vde == nil)
+		return;
+	/* free the strings */
+	for(i=vde->i; i<vde->n; i++)
+		vdcleanup(vde->buf+i);
+	vtfree(vde->buf);
+	vacfiledecref(vde->file);
+	vtfree(vde);
 }
 }
 
 
 
 
-int
-vfIsDir(VacFile *vf)
-{
-	/* immutable */
-	return (vf->dir.mode & ModeDir) != 0;
-}
+/*
+ * On to mutation.  If the vac file system has been opened
+ * read-write, then the files and directories can all be edited.
+ * Changes are kept in the in-memory cache until flushed out
+ * to venti, so we must be careful to explicitly flush data 
+ * that we're not likely to modify again.
+ *
+ * Each VacFile has its own copy of its VacDir directory entry
+ * in f->dir, but otherwise the cache is the authoratative source
+ * for data.  Thus, for the most part, it suffices if we just 
+ * call vtfileflushbefore and vtfileflush when we modify things.
+ * There are a few places where we have to remember to write
+ * changed VacDirs back into the cache.  If f->dir *is* out of sync,
+ * then f->dirty should be set.
+ *
+ * The metadata in a directory is, to venti, a plain data file,
+ * but as mentioned above it is actually a sequence of 
+ * MetaBlocks that contain sorted lists of VacDir entries.
+ * The filemetaxxx routines manipulate that stream.
+ */
 
 
-int
-vfIsRoot(VacFile *vf)
+/*
+ * Find space in fp for the directory entry dir (not yet written to disk)
+ * and write it to disk, returning NilBlock on failure,
+ * or the block number on success.
+ *
+ * Start is a suggested block number to try.
+ * The caller must have filemetalock'ed f and have
+ * vtfilelock'ed f->up->msource.
+ */
+static u32int
+filemetaalloc(VacFile *fp, VacDir *dir, u32int start)
 {
 {
-	return vf == vf->fs->root;
+	u32int nb, bo;
+	VtBlock *b;
+	MetaBlock mb;
+	int nn;
+	uchar *p;
+	int i, n;
+	MetaEntry me;
+	VtFile *ms;
+	
+	ms = fp->msource;
+	n = vdsize(dir, VacDirVersion);
+	
+	/* Look for a block with room for a new entry of size n. */
+	nb = (vtfilegetsize(ms)+ms->dsize-1)/ms->dsize;
+	if(start == NilBlock){
+		if(nb > 0)
+			start = nb - 1;
+		else
+			start = 0;
+	}
+	
+	if(start > nb)
+		start = nb;
+	for(bo=start; bo<nb; bo++){
+		if((b = vtfileblock(ms, bo, VtOREAD)) == nil)
+			goto Err;
+		if(mbunpack(&mb, b->data, ms->dsize) < 0)
+			goto Err;
+		nn = (mb.maxsize*FullPercentage/100) - mb.size + mb.free;
+		if(n <= nn && mb.nindex < mb.maxindex){
+			/* reopen for writing */
+			vtblockput(b);
+			if((b = vtfileblock(ms, bo, VtORDWR)) == nil)
+				goto Err;
+			goto Found;
+		}
+		vtblockput(b);
+	}
+
+	/* No block found, extend the file by one metablock. */
+	vtfileflushbefore(ms, nb*(uvlong)ms->dsize);
+	if((b = vtfileblock(ms, nb, VtORDWR)) == nil)
+		goto Err;
+	vtfilesetsize(ms, (nb+1)*ms->dsize);
+	mbinit(&mb, b->data, ms->dsize, ms->dsize/BytesPerEntry);
+
+Found:
+	/* Now we have a block; allocate space to write the entry. */
+	p = mballoc(&mb, n);
+	if(p == nil){
+		/* mballoc might have changed block */
+		mbpack(&mb);
+		werrstr(EBadMeta);
+		goto Err;
+	}
+
+	/* Figure out where to put the index entry, and write it. */
+	mbsearch(&mb, dir->elem, &i, &me);
+	assert(me.p == nil);	/* not already there */
+	me.p = p;
+	me.size = n;
+	vdpack(dir, &me, VacDirVersion);
+vdunpack(dir, &me);
+	mbinsert(&mb, i, &me);
+	mbpack(&mb);
+	vtblockput(b);
+	return bo;
+
+Err:
+	vtblockput(b);
+	return NilBlock;
 }
 }
 
 
-int
-vfGetSize(VacFile *vf, uvlong *size)
+/*
+ * Update f's directory entry in the block cache. 
+ * We look for the directory entry by name;
+ * if we're trying to rename the file, oelem is the old name.
+ *
+ * Assumes caller has filemetalock'ed f.
+ */
+static int
+filemetaflush(VacFile *f, char *oelem)
 {
 {
-	if(!vfRLock(vf))
+	int i, n;
+	MetaBlock mb;
+	MetaEntry me, me2;
+	VacFile *fp;
+	VtBlock *b;
+	u32int bo;
+
+	if(!f->dirty)
 		return 0;
 		return 0;
-	*size = sourceGetSize(vf->source);
-	vfRUnlock(vf);
 
 
-	return 1;
+	if(oelem == nil)
+		oelem = f->dir.elem;
+
+	/*
+	 * Locate f's old metadata in the parent's metadata file.
+	 * We know which block it was in, but not exactly where
+	 * in the block.
+	 */
+	fp = f->up;
+	if(vtfilelock(fp->msource, -1) < 0)
+		return -1;
+	/* can happen if source is clri'ed out from under us */
+	if(f->boff == NilBlock)
+		goto Err1;
+	b = vtfileblock(fp->msource, f->boff, VtORDWR);
+	if(b == nil)
+		goto Err1;
+	if(mbunpack(&mb, b->data, fp->msource->dsize) < 0)
+		goto Err;
+	if(mbsearch(&mb, oelem, &i, &me) < 0)
+		goto Err;
+
+	/*
+	 * Check whether we can resize the entry and keep it 
+	 * in this block.
+	 */
+	n = vdsize(&f->dir, VacDirVersion);
+	if(mbresize(&mb, &me, n) >= 0){
+		/* Okay, can be done without moving to another block. */
+
+		/* Remove old data */
+		mbdelete(&mb, i, &me);
+
+		/* Find new location if renaming */
+		if(strcmp(f->dir.elem, oelem) != 0)
+			mbsearch(&mb, f->dir.elem, &i, &me2);
+
+		/* Pack new data into new location. */
+		vdpack(&f->dir, &me, VacDirVersion);
+vdunpack(&f->dir, &me);
+		mbinsert(&mb, i, &me);
+		mbpack(&mb);
+		
+		/* Done */
+		vtblockput(b);
+		vtfileunlock(fp->msource);
+		f->dirty = 0;
+		return 0;
+	}
+	
+	/*
+	 * The entry must be moved to another block.
+	 * This can only really happen on renames that
+	 * make the name very long.
+	 */
+	
+	/* Allocate a spot in a new block. */
+	if((bo = filemetaalloc(fp, &f->dir, f->boff+1)) == NilBlock){
+		/* mbresize above might have modified block */
+		mbpack(&mb);
+		goto Err;
+	}
+	f->boff = bo;
+
+	/* Now we're committed.  Delete entry in old block. */
+	mbdelete(&mb, i, &me);
+	mbpack(&mb);
+	vtblockput(b);
+	vtfileunlock(fp->msource);
+
+	f->dirty = 0;
+	return 0;
+
+Err:
+	vtblockput(b);
+Err1:
+	vtfileunlock(fp->msource);
+	return -1;
 }
 }
 
 
+/*
+ * Remove the directory entry for f.
+ */
 static int
 static int
-vfMetaRemove(VacFile *vf, char *user)
+filemetaremove(VacFile *f)
 {
 {
-	Lump *u;
+	VtBlock *b;
 	MetaBlock mb;
 	MetaBlock mb;
 	MetaEntry me;
 	MetaEntry me;
 	int i;
 	int i;
-	VacFile *vfp;
-
-	vfp = vf->up;
+	VacFile *fp;
 
 
-	vfWAccess(vfp, user);
+	b = nil;
+	fp = f->up;
+	filemetalock(f);
 
 
-	vfMetaLock(vf);
-
-	u = sourceGetLump(vfp->msource, vf->block, 0, 1);
-	if(u == nil)
+	if(vtfilelock(fp->msource, VtORDWR) < 0)
+		goto Err;
+	b = vtfileblock(fp->msource, f->boff, VtORDWR);
+	if(b == nil)
 		goto Err;
 		goto Err;
 
 
-	if(!mbUnpack(&mb, u->data, u->asize))
+	if(mbunpack(&mb, b->data, fp->msource->dsize) < 0)
 		goto Err;
 		goto Err;
-	if(!mbSearch(&mb, vf->dir.elem, &i, &me) || me.p == nil)
+	if(mbsearch(&mb, f->dir.elem, &i, &me) < 0)
 		goto Err;
 		goto Err;
-print("deleting %d entry\n", i);
-	mbDelete(&mb, i, &me);
-	memset(me.p, 0, me.size);
-	mbPack(&mb);
+	mbdelete(&mb, i, &me);
+	mbpack(&mb);
+	vtblockput(b);
+	vtfileunlock(fp->msource);
 
 
-	lumpDecRef(u, 1);
+	f->removed = 1;
+	f->boff = NilBlock;
+	f->dirty = 0;
 
 
-	vf->removed = 1;
-	vf->block = NilBlock;
-
-	vfMetaUnlock(vf);
-	return 1;
+	filemetaunlock(f);
+	return 0;
 
 
 Err:
 Err:
-	lumpDecRef(u, 1);
-	vfMetaUnlock(vf);
-	return 0;
+	vtfileunlock(fp->msource);
+	vtblockput(b);
+	filemetaunlock(f);
+	return -1;
 }
 }
 
 
+/*
+ * That was far too much effort for directory entries.
+ * Now we can write code that *does* things.
+ */
 
 
-static int
-vfCheckEmpty(VacFile *vf)
+/*
+ * Flush all data associated with f out of the cache and onto venti.
+ * If recursive is set, flush f's children too.
+ */
+int
+vacfileflush(VacFile *f, int recursive)
 {
 {
-	int i, n;
-	Lump *u;
-	MetaBlock mb;
-	Source *r;
+	int ret;
+	VacFile **kids, *p;
+	int i, nkids;
+	
+	if(f->mode == VtOREAD)
+		return 0;
 
 
-	r = vf->msource;
-	n = sourceGetNumBlocks(r);
-	for(i=0; i<n; i++) {
-		u = sourceGetLump(r, i, 1, 1);
-		if(u == nil)
-			goto Err;
-		if(!mbUnpack(&mb, u->data, u->asize))
-			goto Err;
-		if(mb.nindex > 0) {
-			vtSetError(ENotEmpty);
-			goto Err;
+	ret = 0;
+	filemetalock(f);
+	if(filemetaflush(f, nil) < 0)
+		ret = -1;
+	filemetaunlock(f);
+
+	/*
+	 * Vacfiledecref knows how to flush source and msource too.
+	 */
+	if(filelock(f) < 0)
+		return -1;
+	vtfilelock(f->source, -1);
+	if(vtfileflush(f->source) < 0)
+		ret = -1;
+	vtfileunlock(f->source);
+	if(f->msource){
+		vtfilelock(f->msource, -1);
+		if(vtfileflush(f->msource) < 0)
+			ret = -1;
+		vtfileunlock(f->msource);
+	}
+	
+	/*
+	 * Lock order prevents us from flushing kids while holding
+	 * lock, so make a list.
+	 */
+	nkids = 0;
+	kids = nil;
+	if(recursive){
+		nkids = 0;
+		for(p=f->down; p; p=p->next)
+			nkids++;
+		kids = vtmalloc(nkids*sizeof(VacFile*));
+		i = 0;
+		for(p=f->down; p; p=p->next){
+			kids[i++] = p;
+			p->ref++;
 		}
 		}
-		lumpDecRef(u, 1);
 	}
 	}
-	return 1;
-Err:
-	lumpDecRef(u, 1);
-	return 0;
+	fileunlock(f);
+	
+	for(i=0; i<nkids; i++){
+		if(vacfileflush(kids[i], 1) < 0)
+			ret = -1;
+		vacfiledecref(kids[i]);
+	}
+	free(kids);
+	return ret;
 }
 }
-
-int
-vfRemove(VacFile *vf, char *user)
+		
+/*
+ * Create a new file named elem in fp with the given mode.
+ * The mode can be changed later except for the ModeDir bit.
+ */
+VacFile*
+vacfilecreate(VacFile *fp, char *elem, ulong mode)
 {
 {
-	/* can not remove the root */
-	if(vfIsRoot(vf)) {
-		vtSetError(ERoot);
-		return 0;
+	VacFile *ff;
+	VacDir *dir;
+	VtFile *pr, *r, *mr;
+	int type;
+	u32int bo;
+
+	if(filelock(fp) < 0)
+		return nil;
+
+	/*
+	 * First, look to see that there's not a file in memory
+	 * with the same name.
+	 */
+	for(ff = fp->down; ff; ff=ff->next){
+		if(strcmp(elem, ff->dir.elem) == 0 && !ff->removed){
+			ff = nil;
+			werrstr(EExists);
+			goto Err1;
+		}
 	}
 	}
 
 
-	if(!vfLock(vf))
-		return 0;
+	/*
+	 * Next check the venti blocks.
+	 */
+	ff = dirlookup(fp, elem);
+	if(ff != nil){
+		werrstr(EExists);
+		goto Err1;
+	}
 
 
-	if(vfIsDir(vf) && !vfCheckEmpty(vf))
-		goto Err;
+	/*
+	 * By the way, you can't create in a read-only file system.
+	 */
+	pr = fp->source;
+	if(pr->mode != VtORDWR){
+		werrstr(EReadOnly);
+		goto Err1;
+	}
 
 
-	assert(vf->down == nil);
+	/*
+	 * Okay, time to actually create something.  Lock the two
+	 * halves of the directory and create a file.
+	 */
+	if(vtfilelock2(fp->source, fp->msource, -1) < 0)
+		goto Err1;
+	ff = filealloc(fp->fs);
+	ff->qidoffset = fp->qidoffset;	/* hopefully fp->qidoffset == 0 */
+	type = VtDataType;
+	if(mode & ModeDir)
+		type = VtDirType;
+	mr = nil;
+	if((r = vtfilecreate(pr, pr->psize, pr->dsize, type)) == nil)
+		goto Err;
+	if(mode & ModeDir)
+	if((mr = vtfilecreate(pr, pr->psize, pr->dsize, VtDataType)) == nil)
+		goto Err;
 
 
-	sourceRemove(vf->source);
-	vf->source = nil;
-	if(vf->msource) {
-		sourceRemove(vf->msource);
-		vf->msource = nil;
+	/*
+	 * Fill in the directory entry and write it to disk.
+	 */
+	dir = &ff->dir;
+	dir->elem = vtstrdup(elem);
+	dir->entry = r->offset;
+	dir->gen = r->gen;
+	if(mode & ModeDir){
+		dir->mentry = mr->offset;
+		dir->mgen = mr->gen;
 	}
 	}
+	dir->size = 0;
+	if(_vacfsnextqid(fp->fs, &dir->qid) < 0)
+		goto Err;
+	dir->uid = vtstrdup(fp->dir.uid);
+	dir->gid = vtstrdup(fp->dir.gid);
+	dir->mid = vtstrdup("");
+	dir->mtime = time(0L);
+	dir->mcount = 0;
+	dir->ctime = dir->mtime;
+	dir->atime = dir->mtime;
+	dir->mode = mode;
+	if((bo = filemetaalloc(fp, &ff->dir, NilBlock)) == NilBlock)
+		goto Err;
 
 
-	vfUnlock(vf);
+	/*
+	 * Now we're committed.
+	 */
+	vtfileunlock(fp->source);
+	vtfileunlock(fp->msource);
+	ff->source = r;
+	ff->msource = mr;
+	ff->boff = bo;
 
 
-	if(!vfMetaRemove(vf, user))
-		return 0;
+	/* Link into tree. */
+	ff->next = fp->down;
+	fp->down = ff;
+	ff->up = fp;
+	vacfileincref(fp);
 
 
-	return 1;
+	fileunlock(fp);
+	return ff;
 
 
 Err:
 Err:
-	vfUnlock(vf);
-	return 0;
+	vtfileunlock(fp->source);
+	vtfileunlock(fp->msource);
+	if(r){
+		vtfilelock(r, -1);
+		vtfileremove(r);
+	}
+	if(mr){
+		vtfilelock(mr, -1);
+		vtfileremove(mr);
+	}
+Err1:
+	if(ff)
+		vacfiledecref(ff);
+	fileunlock(fp);
+	return nil;
 }
 }
 
 
-VacFile *
-vfIncRef(VacFile *vf)
+/*
+ * Change the size of the file f.
+ */
+int
+vacfilesetsize(VacFile *f, uvlong size)
 {
 {
-	vfMetaLock(vf);
-	assert(vf->ref > 0);
-	vf->ref++;
-	vfMetaUnlock(vf);
-	return vf;
+	if(vacfileisdir(f)){
+		werrstr(ENotFile);
+		return -1;
+	}
+	
+	if(filelock(f) < 0)
+		return -1;
+
+	if(f->source->mode != VtORDWR){
+		werrstr(EReadOnly);
+		goto Err;
+	}
+	if(vtfilelock(f->source, -1) < 0)
+		goto Err;
+	if(vtfilesetsize(f->source, size) < 0){
+		vtfileunlock(f->source);
+		goto Err;
+	}
+	vtfileunlock(f->source);
+	fileunlock(f);
+	return 0;
+
+Err:
+	fileunlock(f);
+	return -1;
 }
 }
 
 
-void
-vfDecRef(VacFile *vf)
+/*
+ * Write data to f.
+ */
+int
+vacfilewrite(VacFile *f, void *buf, int cnt, vlong offset)
 {
 {
-	VacFile *p, *q, **qq;
-
-	if(vf->up == nil) {
-		vfFree(vf);
-		return;
+	if(vacfileisdir(f)){
+		werrstr(ENotFile);
+		return -1;
+	}
+	if(filelock(f) < 0)
+		return -1;
+	if(f->source->mode != VtORDWR){
+		werrstr(EReadOnly);
+		goto Err;
+	}
+	if(offset < 0){
+		werrstr(EBadOffset);
+		goto Err;
 	}
 	}
 
 
-	vfMetaLock(vf);
-	vf->ref--;
-	if(vf->ref > 0) {
-		vfMetaUnlock(vf);
-		return;
+	if(vtfilelock(f->source, -1) < 0)
+		goto Err;
+	if(f->dir.mode & ModeAppend)
+		offset = vtfilegetsize(f->source);
+	if(vtfilewrite(f->source, buf, cnt, offset) != cnt
+	|| vtfileflushbefore(f->source, offset) < 0){
+		vtfileunlock(f->source);
+		goto Err;
 	}
 	}
-	assert(vf->ref == 0);
-	assert(vf->down == nil);
+	vtfileunlock(f->source);
+	fileunlock(f);
+	return cnt;
 
 
-	p = vf->up;
-	qq = &p->down;
-	for(q = *qq; q; qq=&q->next,q=*qq)
-		if(q == vf)
-			break;
-	assert(q != nil);
-	*qq = vf->next;
+Err:
+	fileunlock(f);
+	return -1;
+}
 
 
-	vfMetaUnlock(vf);
-	vfFree(vf);
+/*
+ * Set (!) the VtEntry for the data contained in f.
+ * This let's us efficiently copy data from one file to another.
+ */
+int
+vacfilesetentries(VacFile *f, VtEntry *e, VtEntry *me)
+{
+	int ret;
 
 
-	vfDecRef(p);
+	vacfileflush(f, 0);	/* flush blocks to venti, since we won't see them again */
+
+	if(!(e->flags&VtEntryActive)){
+		werrstr("missing entry for source");
+		return -1;
+	}
+	if(me && !(me->flags&VtEntryActive))
+		me = nil;
+	if(f->msource && !me){
+		werrstr("missing entry for msource");
+		return -1;
+	}
+	if(me && !f->msource){
+		werrstr("no msource to set");
+		return -1;
+	}
+
+	if(filelock(f) < 0)
+		return -1;
+	if(f->source->mode != VtORDWR
+	|| (f->msource && f->msource->mode != VtORDWR)){
+		werrstr(EReadOnly);
+		fileunlock(f);
+		return -1;
+	}
+	if(vtfilelock2(f->source, f->msource, -1) < 0){
+		fileunlock(f);
+		return -1;
+	}
+	ret = 0;
+	if(vtfilesetentry(f->source, e) < 0)
+		ret = -1;
+	else if(me && vtfilesetentry(f->msource, me) < 0)
+		ret = -1;
+
+	vtfileunlock(f->source);
+	if(f->msource)
+		vtfileunlock(f->msource);
+	fileunlock(f);
+	return ret;
 }
 }
 
 
+/*
+ * Get the directory entry for f.
+ */
 int
 int
-vfGetVtEntry(VacFile *vf, VtEntry *e)
+vacfilegetdir(VacFile *f, VacDir *dir)
 {
 {
-	int res;
+	if(filerlock(f) < 0)
+		return -1;
 
 
-	if(!vfRLock(vf))
-		return 0;
-	res = sourceGetVtEntry(vf->source, e);
-	vfRUnlock(vf);
-	return res;
+	filemetalock(f);
+	vdcopy(dir, &f->dir);
+	filemetaunlock(f);
+
+	if(!vacfileisdir(f)){
+		if(vtfilelock(f->source, VtOREAD) < 0){
+			filerunlock(f);
+			return -1;
+		}
+		dir->size = vtfilegetsize(f->source);
+		vtfileunlock(f->source);
+	}
+	filerunlock(f);
+
+	return 0;
 }
 }
 
 
+/*
+ * Set the directory entry for f.
+ */
 int
 int
-vfGetBlockScore(VacFile *vf, ulong bn, uchar score[VtScoreSize])
+vacfilesetdir(VacFile *f, VacDir *dir)
 {
 {
-	Lump *u;
-	int ret, off;
-	Source *r;
+	VacFile *ff;
+	char *oelem;
+	u32int mask;
+	u64int size;
+
+	/* can not set permissions for the root */
+	if(vacfileisroot(f)){
+		werrstr(ERoot);
+		return -1;
+	}
 
 
-	if(!vfRLock(vf))
-		return 0;
+	if(filelock(f) < 0)
+		return -1;
+	filemetalock(f);
+	
+	if(f->source->mode != VtORDWR){
+		werrstr(EReadOnly);
+		goto Err;
+	}
 
 
-	r = vf->source;
+	/* On rename, check new name does not already exist */
+	if(strcmp(f->dir.elem, dir->elem) != 0){
+		for(ff = f->up->down; ff; ff=ff->next){
+			if(strcmp(dir->elem, ff->dir.elem) == 0 && !ff->removed){
+				werrstr(EExists);
+				goto Err;
+			}
+		}
+		ff = dirlookup(f->up, dir->elem);
+		if(ff != nil){
+			vacfiledecref(ff);
+			werrstr(EExists);
+			goto Err;
+		}
+		werrstr("");	/* "failed" dirlookup poisoned it */
+	}
 
 
-	u = sourceWalk(r, bn, 1, &off);
-	if(u == nil){
-		vfRUnlock(vf);
-		return 0;
+	/* Get ready... */
+	if(vtfilelock2(f->source, f->msource, -1) < 0)
+		goto Err;
+	if(!vacfileisdir(f)){
+		size = vtfilegetsize(f->source);
+		if(size != dir->size){
+			if(vtfilesetsize(f->source, dir->size) < 0){
+				vtfileunlock(f->source);
+				if(f->msource)
+					vtfileunlock(f->msource);
+				goto Err;
+			}
+		}
+	}
+	/* ... now commited to changing it. */
+	vtfileunlock(f->source);
+	if(f->msource)
+		vtfileunlock(f->msource);
+
+	oelem = nil;
+	if(strcmp(f->dir.elem, dir->elem) != 0){
+		oelem = f->dir.elem;
+		f->dir.elem = vtstrdup(dir->elem);
 	}
 	}
 
 
-	ret = lumpGetScore(u, off, score);
-	lumpDecRef(u, 0);
-	vfRUnlock(vf);
+	if(strcmp(f->dir.uid, dir->uid) != 0){
+		vtfree(f->dir.uid);
+		f->dir.uid = vtstrdup(dir->uid);
+	}
 
 
-	return ret;
-}
+	if(strcmp(f->dir.gid, dir->gid) != 0){
+		vtfree(f->dir.gid);
+		f->dir.gid = vtstrdup(dir->gid);
+	}
 
 
-VacFile *
-vfGetParent(VacFile *vf)
-{
-	if(vfIsRoot(vf))
-		return vfIncRef(vf);
-	return vfIncRef(vf->up);
-}
+	f->dir.mtime = dir->mtime;
+	f->dir.atime = dir->atime;
 
 
-static VacDirEnum *
-vdeAlloc(VacFile *vf)
-{
-	VacDirEnum *ds;
+	mask = ~(ModeDir|ModeSnapshot);
+	f->dir.mode &= ~mask;
+	f->dir.mode |= mask & dir->mode;
+	f->dirty = 1;
 
 
-	if(!(vf->dir.mode & ModeDir)) {
-		vtSetError(ENotDir);
-		vfDecRef(vf);
-		return nil;
+	if(filemetaflush(f, oelem) < 0){
+		vtfree(oelem);
+		goto Err;	/* that sucks */
 	}
 	}
+	vtfree(oelem);
 
 
-	ds = vtMemAllocZ(sizeof(VacDirEnum));
-	ds->file = vf;
+	filemetaunlock(f);
+	fileunlock(f);
+	return 0;
 
 
-	return ds;
+Err:
+	filemetaunlock(f);
+	fileunlock(f);
+	return -1;
 }
 }
 
 
-VacDirEnum *
-vdeOpen(VacFS *fs, char *path)
+/*
+ * Set the qid space.
+ */
+int
+vacfilesetqidspace(VacFile *f, u64int offset, u64int max)
 {
 {
-	VacFile *vf;
+	int ret;
 
 
-	vf = vfOpen(fs, path);
-	if(vf == nil)
-		return nil;
-
-	return vdeAlloc(vf);
+	if(filelock(f) < 0)
+		return -1;
+	if(f->source->mode != VtORDWR){
+		fileunlock(f);
+		werrstr(EReadOnly);
+		return -1;
+	}
+	filemetalock(f);
+	f->dir.qidspace = 1;
+	f->dir.qidoffset = offset;
+	f->dir.qidmax = max;
+	f->dirty = 1;
+	ret = filemetaflush(f, nil);
+	filemetaunlock(f);
+	fileunlock(f);
+	return ret;
 }
 }
 
 
-VacDirEnum *
-vfDirEnum(VacFile *vf)
+/*
+ * Check that the file is empty, returning 0 if it is.
+ * Returns -1 on error (and not being empty is an error).
+ */
+static int
+filecheckempty(VacFile *f)
 {
 {
-	return vdeAlloc(vfIncRef(vf));
+	u32int i, n;
+	VtBlock *b;
+	MetaBlock mb;
+	VtFile *r;
+
+	r = f->msource;
+	n = (vtfilegetsize(r)+r->dsize-1)/r->dsize;
+	for(i=0; i<n; i++){
+		b = vtfileblock(r, i, VtOREAD);
+		if(b == nil)
+			return -1;
+		if(mbunpack(&mb, b->data, r->dsize) < 0)
+			goto Err;
+		if(mb.nindex > 0){
+			werrstr(ENotEmpty);
+			goto Err;
+		}
+		vtblockput(b);
+	}
+	return 0;
+
+Err:
+	vtblockput(b);
+	return -1;
 }
 }
 
 
-static int
-dirEntrySize(Source *s, ulong elem, ulong gen, uvlong *size)
+/*
+ * Remove the vac file f.
+ */
+int
+vacfileremove(VacFile *f)
 {
 {
-	Lump *u;
-	ulong bn;
-	VtEntry e;
+	VacFile *ff;
 
 
-	bn = elem/s->epb;
-	elem -= bn*s->epb;
+	/* Cannot remove the root */
+	if(vacfileisroot(f)){
+		werrstr(ERoot);
+		return -1;
+	}
 
 
-	u = sourceGetLump(s, bn, 1, 1);
-	if(u == nil)
-		goto Err;
-	if(u->asize < (elem+1)*VtEntrySize) {
-		vtSetError(ENoDir);
-		goto Err;
+	if(filelock(f) < 0)
+		return -1;
+	if(f->source->mode != VtORDWR){
+		werrstr(EReadOnly);
+		goto Err1;
 	}
 	}
-	vtEntryUnpack(&e, u->data, elem);
-	if(!(e.flags & VtEntryActive) || e.gen != gen) {
-fprint(2, "gen mismatch\n");
-		vtSetError(ENoDir);
+	if(vtfilelock2(f->source, f->msource, -1) < 0)
+		goto Err1;
+	if(vacfileisdir(f) && filecheckempty(f)<0)
 		goto Err;
 		goto Err;
+
+	for(ff=f->down; ff; ff=ff->next)
+		assert(ff->removed);
+
+	vtfileremove(f->source);
+	f->source = nil;
+	if(f->msource){
+		vtfileremove(f->msource);
+		f->msource = nil;
 	}
 	}
+	fileunlock(f);
 
 
-	*size = e.size;
-	lumpDecRef(u, 1);
-	return 1;
+	if(filemetaremove(f) < 0)
+		return -1;
+	return 0;
 
 
 Err:
 Err:
-	lumpDecRef(u, 1);
-	return 0;
+	vtfileunlock(f->source);
+	if(f->msource)
+		vtfileunlock(f->msource);
+Err1:
+	fileunlock(f);
+	return -1;
 }
 }
 
 
-int
-vdeRead(VacDirEnum *ds, VacDir *dir, int n)
+/*
+ * Vac file system format.
+ */
+static char EBadVacFormat[] = "bad format for vac file";
+
+static VacFs *
+vacfsalloc(VtConn *z, int bsize, int ncache, int mode)
 {
 {
-	ulong nb;
-	int i;
-	Source *meta, *source;
-	MetaBlock mb;
-	MetaEntry me;
-	Lump *u;
+	VacFs *fs;
+
+	fs = vtmallocz(sizeof(VacFs));
+	fs->z = z;
+	fs->bsize = bsize;
+	fs->mode = mode;
+	fs->cache = vtcachealloc(z, bsize, ncache);
+	return fs;
+}
 
 
-	vfRAccess(ds->file);
+static int
+readscore(int fd, uchar score[VtScoreSize])
+{
+	char buf[45], *pref;
+	int n;
 
 
-	if(!vfRLock(ds->file))
+	n = readn(fd, buf, sizeof(buf)-1);
+	if(n < sizeof(buf)-1) {
+		werrstr("short read");
 		return -1;
 		return -1;
+	}
+	buf[n] = 0;
 
 
-	i = 0;
-	u = nil;
-	source = ds->file->source;
-	meta = ds->file->msource;
-	nb = (sourceGetSize(meta) + meta->dsize - 1)/meta->dsize;
-
-	if(ds->block >= nb)
-		goto Exit;
-	u = sourceGetLump(meta, ds->block, 1, 1);
-	if(u == nil)
-		goto Err;
-	if(!mbUnpack(&mb, u->data, u->asize))
-		goto Err;
+	if(vtparsescore(buf, &pref, score) < 0){
+		werrstr(EBadVacFormat);
+		return -1;
+	}
+	if(pref==nil || strcmp(pref, "vac") != 0) {
+		werrstr("not a vac file");
+		return -1;
+	}
+	return 0;
+}
 
 
-	for(i=0; i<n; i++) {
-		while(ds->index >= mb.nindex) {
-			lumpDecRef(u, 1);
-			u = nil;
-			ds->index = 0;
-			ds->block++;
-			if(ds->block >= nb)
-				goto Exit;
-			u = sourceGetLump(meta, ds->block, 1, 1);
-			if(u == nil)
-				goto Err;
-			if(!mbUnpack(&mb, u->data, u->asize))
-				goto Err;
+VacFs*
+vacfsopen(VtConn *z, char *file, int mode, int ncache)
+{
+	int fd;
+	uchar score[VtScoreSize];
+	char *prefix;
+	
+	if(vtparsescore(file, &prefix, score) >= 0){
+		if(strcmp(prefix, "vac") != 0){
+			werrstr("not a vac file");
+			return nil;
 		}
 		}
-		if(!meUnpack(&me, &mb, ds->index))
-			goto Err;
-		if(dir != nil) {
-			if(!vdUnpack(&dir[i], &me))
-				goto Err;
-			if(!(dir[i].mode & ModeDir))
-			if(!dirEntrySize(source, dir[i].entry, dir[i].gen, &dir[i].size))
-				goto Err;
+	}else{
+		fd = open(file, OREAD);
+		if(fd < 0)
+			return nil;
+		if(readscore(fd, score) < 0){
+			close(fd);
+			return nil;
 		}
 		}
-		ds->index++;
+		close(fd);
 	}
 	}
-Exit:
-	lumpDecRef(u, 1);
-	vfRUnlock(ds->file);
-	return i;
+	return vacfsopenscore(z, score, mode, ncache);
+}
+
+VacFs*
+vacfsopenscore(VtConn *z, u8int *score, int mode, int ncache)
+{
+	VacFs *fs;
+	int n;
+	VtRoot rt;
+	uchar buf[VtRootSize];
+	VacFile *root;
+	VtFile *r;
+	VtEntry e;
+
+	n = vtread(z, score, VtRootType, buf, VtRootSize);
+	if(n < 0)
+		return nil;
+	if(n != VtRootSize){
+		werrstr("vtread on root too short");
+		return nil;
+	}
+
+	if(vtrootunpack(&rt, buf) < 0)
+		return nil;
+
+	if(strcmp(rt.type, "vac") != 0) {
+		werrstr("not a vac root");
+		return nil;
+	}
+
+	fs = vacfsalloc(z, rt.blocksize, ncache, mode);
+	memmove(fs->score, score, VtScoreSize);
+	fs->mode = mode;
+
+	memmove(e.score, rt.score, VtScoreSize);
+	e.gen = 0;
+	e.psize = (rt.blocksize/VtEntrySize)*VtEntrySize;
+	e.dsize = rt.blocksize;
+	e.type = VtDirType;
+	e.flags = VtEntryActive;
+	e.size = 3*VtEntrySize;
+
+	root = nil;
+	if((r = vtfileopenroot(fs->cache, &e)) == nil)
+		goto Err;
+	if(debug)
+		fprint(2, "r %p\n", r);
+	root = _vacfileroot(fs, r);
+	if(debug)
+		fprint(2, "root %p\n", root);
+	vtfileclose(r);
+	if(root == nil)
+		goto Err;
+	fs->root = root;
+	return fs;
 Err:
 Err:
-	lumpDecRef(u, 1);
-	vfRUnlock(ds->file);
-	n = i;
-	for(i=0; i<n ; i++)
-		vdCleanup(&dir[i]);
-	return -1;
+	if(root)
+		vacfiledecref(root);
+	vacfsclose(fs);
+	return nil;
 }
 }
 
 
-void
-vdeFree(VacDirEnum *ds)
+int
+vacfsmode(VacFs *fs)
 {
 {
-	if(ds == nil)
-		return;
-	vfDecRef(ds->file);
-	vtMemFree(ds);
+	return fs->mode;
 }
 }
 
 
-static ulong
-msAlloc(Source *ms, ulong start, int n)
+VacFile*
+vacfsgetroot(VacFs *fs)
 {
 {
-	ulong nb, i;
-	Lump *u;
-	MetaBlock mb;
+	return vacfileincref(fs->root);
+}
 
 
-	nb = sourceGetNumBlocks(ms);
-	u = nil;
-	if(start > nb)
-		start = nb;
-	for(i=start; i<nb; i++) {
-		u = sourceGetLump(ms, i, 1, 1);
-		if(u == nil)
-			goto Err;
-		if(!mbUnpack(&mb, u->data, ms->dsize))
-			goto Err;
-		if(mb.maxsize - mb.size + mb.free >= n && mb.nindex < mb.maxindex)
-			break;
-		lumpDecRef(u, 1);
-		u = nil;
-	}
-	/* add block to meta file */
-	if(i == nb) {
-		if(!sourceSetDepth(ms, (i+1)*ms->dsize))
-			goto Err;
-		u = sourceGetLump(ms, i, 0, 1);
-		if(u == nil)
-			goto Err;
-		sourceSetSize(ms, (nb+1)*ms->dsize);
-		mbInit(&mb, u->data, u->asize);
-		mbPack(&mb);
-	}
-	lumpDecRef(u, 1);
-	return i;
-Err:
-	lumpDecRef(u, 1);
-	return NilBlock;
+int
+vacfsgetblocksize(VacFs *fs)
+{
+	return fs->bsize;
 }
 }
 
 
-VacFS *
-vacfs(VacFile *vf)
+int
+vacfsgetscore(VacFs *fs, u8int *score)
 {
 {
-	if (vf == nil)
-		return nil;
-	return vf->fs;
+	memmove(score, fs->score, VtScoreSize);
+	return 0;
+}
+
+int
+_vacfsnextqid(VacFs *fs, uvlong *qid)
+{
+	++fs->qid;
+	*qid = fs->qid;
+	return 0;
+}
+
+void
+vacfsjumpqid(VacFs *fs, uvlong step)
+{
+	fs->qid += step;
 }
 }
 
 
 /*
 /*
- * path may be nil; it's the right-hand part of the path so far.
- * result is malloced, path must be malloced or nil.
+ * Set *maxqid to the maximum qid expected in this file system.
+ * In newer vac archives, the maximum qid is stored in the
+ * qidspace VacDir annotation.  In older vac archives, the root
+ * got created last, so it had the maximum qid.
  */
  */
-char *
-vfName(VacFile *vf, char *path)
+int
+vacfsgetmaxqid(VacFs *fs, uvlong *maxqid)
 {
 {
-	char *nname, *rname, *elem;
-
-	if (vf == nil || vf == vf->up) {		/* at the root? */
-		if (path == nil)
-			return strdup("/");
-		return path;
-	}
-	elem = vf->dir.elem;
-	if (elem != nil && path != nil)
-		rname = smprint("%s/%s", elem, path);
-	else if (elem != nil)
-		rname = strdup(elem);
+	VacDir vd;
+	
+	if(vacfilegetdir(fs->root, &vd) < 0)
+		return -1;
+	if(vd.qidspace)
+		*maxqid = vd.qidmax;
 	else
 	else
-		return vfName(vf->up, path);
-	nname = vfName(vf->up, rname);
-	if (nname != rname)
-		free(rname);
-	return nname;
+		*maxqid = vd.qid;
+	vdcleanup(&vd);
+	return 0;
+}
+
+
+void
+vacfsclose(VacFs *fs)
+{
+	if(fs->root)
+		vacfiledecref(fs->root);
+	fs->root = nil;
+	vtcachefree(fs->cache);
+	vtfree(fs);
+}
+
+/*
+ * Create a fresh vac fs.
+ */
+VacFs *
+vacfscreate(VtConn *z, int bsize, int ncache)
+{
+	VacFs *fs;
+	VtFile *f;
+	uchar buf[VtEntrySize], metascore[VtScoreSize];
+	VtEntry e;
+	VtBlock *b;
+	MetaBlock mb;
+	VacDir vd;
+	MetaEntry me;
+	int psize;
+	
+	if((fs = vacfsalloc(z, bsize, ncache, VtORDWR)) == nil)
+		return nil;
+	
+	/*
+	 * Fake up an empty vac fs.
+	 */
+	psize = bsize/VtEntrySize*VtEntrySize;
+	f = vtfilecreateroot(fs->cache, psize, bsize, VtDirType);
+	vtfilelock(f, VtORDWR);
+	
+	/* Write metablock containing root directory VacDir. */
+	b = vtcacheallocblock(fs->cache, VtDataType);
+	mbinit(&mb, b->data, bsize, bsize/BytesPerEntry);
+	memset(&vd, 0, sizeof vd);
+	vd.elem = "/";
+	vd.mode = 0777|ModeDir;
+	vd.uid = "vac";
+	vd.gid = "vac";
+	vd.mid = "";
+	me.size = vdsize(&vd, VacDirVersion);
+	me.p = mballoc(&mb, me.size);
+	vdpack(&vd, &me, VacDirVersion);
+	mbinsert(&mb, 0, &me);
+	mbpack(&mb);
+	vtblockwrite(b);
+	memmove(metascore, b->score, VtScoreSize);
+	vtblockput(b);
+	
+	/* First entry: empty venti directory stream. */
+	memset(&e, 0, sizeof e);
+	e.flags = VtEntryActive;
+	e.psize = psize;
+	e.dsize = bsize;
+	e.type = VtDirType;
+	memmove(e.score, vtzeroscore, VtScoreSize);
+	vtentrypack(&e, buf, 0);
+	vtfilewrite(f, buf, VtEntrySize, 0);
+	
+	/* Second entry: empty metadata stream. */
+	e.type = VtDataType;
+	vtentrypack(&e, buf, 0);
+	vtfilewrite(f, buf, VtEntrySize, VtEntrySize);
+
+	/* Third entry: metadata stream with root directory. */
+	memmove(e.score, metascore, VtScoreSize);
+	e.size = bsize;
+	vtentrypack(&e, buf, 0);
+	vtfilewrite(f, buf, VtEntrySize, VtEntrySize*2);
+
+	vtfileflush(f);
+	vtfileunlock(f);
+	
+	/* Now open it as a vac fs. */
+	fs->root = _vacfileroot(fs, f);
+	if(fs->root == nil){
+		werrstr("vacfileroot: %r");
+		vacfsclose(fs);
+		return nil;
+	}
+
+	return fs;
+}
+
+int
+vacfssync(VacFs *fs)
+{
+	uchar buf[1024];
+	VtEntry e;
+	VtFile *f;
+	VtRoot root;
+
+	/* Sync the entire vacfs to disk. */
+	if(vacfileflush(fs->root, 1) < 0)
+		return -1;
+	if(vtfilelock(fs->root->up->msource, -1) < 0)
+		return -1;
+	if(vtfileflush(fs->root->up->msource) < 0){
+		vtfileunlock(fs->root->up->msource);
+		return -1;
+	}
+	vtfileunlock(fs->root->up->msource);
+
+	/* Prepare the dir stream for the root block. */
+	if(getentry(fs->root->source, &e) < 0)
+		return -1;
+	vtentrypack(&e, buf, 0);
+	if(getentry(fs->root->msource, &e) < 0)
+		return -1;
+	vtentrypack(&e, buf, 1);
+	if(getentry(fs->root->up->msource, &e) < 0)
+		return -1;
+	vtentrypack(&e, buf, 2);
+
+	f = vtfilecreateroot(fs->cache, fs->bsize, fs->bsize, VtDirType);
+	vtfilelock(f, VtORDWR);
+	if(vtfilewrite(f, buf, 3*VtEntrySize, 0) < 0
+	|| vtfileflush(f) < 0){
+		vtfileunlock(f);
+		vtfileclose(f);
+		return -1;
+	}
+	vtfileunlock(f);
+	if(getentry(f, &e) < 0){
+		vtfileclose(f);
+		return -1;
+	}
+	vtfileclose(f);
+	
+	/* Build a root block. */
+	memset(&root, 0, sizeof root);
+	strcpy(root.type, "vac");
+	strcpy(root.name, fs->name);
+	memmove(root.score, e.score, VtScoreSize);
+	root.blocksize = fs->bsize;
+	memmove(root.prev, fs->score, VtScoreSize);
+	vtrootpack(&root, buf);
+	if(vtwrite(fs->z, fs->score, VtRootType, buf, VtRootSize) < 0){
+		werrstr("writing root: %r");
+		return -1;
+	}
+	if(vtsync(fs->z) < 0)
+		return -1;
+	return 0;
 }
 }

+ 21 - 42
sys/src/cmd/vac/fns.h

@@ -1,46 +1,25 @@
-Source	*sourceAlloc(Cache*, Lump *u, ulong block, int elem, int readonly);
-Source 	*sourceOpen(Source*, ulong entry, int readOnly);
-Source 	*sourceCreate(Source*, int psize, int dsize, int isdir, ulong entry);
-Lump	*sourceGetLump(Source*, ulong block, int readOnly, int lock);
-Lump	*sourceWalk(Source *r, ulong block, int readOnly, int *);
-int	sourceSetDepth(Source *r, uvlong size);
-int	sourceSetSize(Source *r, uvlong size);
-uvlong	sourceGetSize(Source *r);
-int	sourceSetDirSize(Source *r, ulong size);
-ulong	sourceGetDirSize(Source *r);
-void	sourceRemove(Source*);
-void	sourceFree(Source*);
-int	sourceGetVtEntry(Source *r, VtEntry *dir);
-ulong	sourceGetNumBlocks(Source *r);
+int	mbunpack(MetaBlock *mb, uchar *p, int n);
+void	mbinsert(MetaBlock *mb, int i, MetaEntry*);
+void	mbdelete(MetaBlock *mb, int i, MetaEntry*);
+void	mbpack(MetaBlock *mb);
+uchar	*mballoc(MetaBlock *mb, int n);
+void		mbinit(MetaBlock *mb, uchar *p, int n, int entries);
+int mbsearch(MetaBlock*, char*, int*, MetaEntry*);
+int mbresize(MetaBlock*, MetaEntry*, int);
 
 
-Lump	*lumpWalk(Lump *u, int offset, int type, int size, int readOnly, int lock);
-int	lumpGetScore(Lump *u, int offset, uchar score[VtScoreSize]);
-void	lumpDecRef(Lump*, int unlock);
-Lump	*lumpIncRef(Lump*);
-void	lumpFreeEntry(Lump *u, int entry);
+int	meunpack(MetaEntry*, MetaBlock *mb, int i);
+int	mecmp(MetaEntry*, char *s);
+int	mecmpnew(MetaEntry*, char *s);
 
 
-Cache 	*cacheAlloc(VtSession *z, int blockSize, long nblocks);
-Lump 	*cacheAllocLump(Cache *c, int type, int size, int dir);
-void	cacheFree(Cache *c);
-long	cacheGetSize(Cache*);
-int	cacheSetSize(Cache*, long);
-int	cacheGetBlockSize(Cache *c);
-Lump 	*cacheGetLump(Cache *c, uchar score[VtScoreSize], int type, int size);
-void	cacheCheck(Cache*);
+enum {
+	VacDirVersion = 8,
+	FossilDirVersion = 9,
+};
+int	vdsize(VacDir *dir, int);
+int	vdunpack(VacDir *dir, MetaEntry*);
+void	vdpack(VacDir *dir, MetaEntry*, int);
 
 
-int	mbUnpack(MetaBlock *mb, uchar *p, int n);
-void	mbInsert(MetaBlock *mb, int i, MetaEntry*);
-void	mbDelete(MetaBlock *mb, int i, MetaEntry*);
-void	mbPack(MetaBlock *mb);
-uchar	*mbAlloc(MetaBlock *mb, int n);
-
-int	meUnpack(MetaEntry*, MetaBlock *mb, int i);
-int	meCmp(MetaEntry*, char *s);
-int	meCmpNew(MetaEntry*, char *s);
-
-int	vdSize(VacDir *dir);
-int	vdUnpack(VacDir *dir, MetaEntry*);
-void	vdPack(VacDir *dir, MetaEntry*);
-
-VacFile *vfRoot(VacFS *fs, uchar *score);
+VacFile *_vacfileroot(VacFs *fs, VtFile *file);
 
 
+int	_vacfsnextqid(VacFs *fs, uvlong *qid);
+void	vacfsjumpqid(VacFs*, uvlong step);

+ 0 - 185
sys/src/cmd/vac/fs.c

@@ -1,185 +0,0 @@
-#include "stdinc.h"
-#include "vac.h"
-#include "dat.h"
-#include "fns.h"
-
-static char EBadVacFormat[] = "bad format for vac file";
-
-static VacFS *
-vfsAlloc(VtSession *z, int bsize, long ncache)
-{
-	VacFS *fs;
-
-	fs = vtMemAllocZ(sizeof(VacFS));
-	fs->ref = 1;
-	fs->z = z;
-	fs->bsize = bsize;
-	fs->cache = cacheAlloc(z, bsize, ncache);
-	return fs;
-}
-
-static int
-readScore(char* file, uchar score[VtScoreSize])
-{
-	char buf[44];
-	int fd, i, n, c;
-
-	fd = open(file, OREAD);
-	if(fd < 0) {
-		vtSetError("can't open '%s': %r", file);
-		return 0;
-	}
-
-	n = readn(fd, buf, sizeof(buf));
-	close(fd);
-	if(n < sizeof(buf)) {
-		vtSetError("read '%s': too short", file);
-		return 0;
-	}
-	if(strncmp(buf, "vac:", 4) != 0) {
-		vtSetError("'%s': not a vac file", file);
-		return 0;
-	}
-	memset(score, 0, VtScoreSize);
-	for(i=4; i<sizeof(buf); i++) {
-		if(buf[i] >= '0' && buf[i] <= '9')
-			c = buf[i] - '0';
-		else if(buf[i] >= 'a' && buf[i] <= 'f')
-			c = buf[i] - 'a' + 10;
-		else if(buf[i] >= 'A' && buf[i] <= 'F')
-			c = buf[i] - 'A' + 10;
-		else {
-			vtSetError("'%s': bad format for venti score", file);
-			return 0;
-		}
-		if((i & 1) == 0)
-			c <<= 4;
-	
-		score[(i>>1)-2] |= c;
-	}
-	return 1;
-}
-
-VacFS *
-vfsOpen(VtSession *z, char *file, int readOnly, long ncache)
-{
-	VacFS *fs;
-	int n;
-	VtRoot rt;
-	uchar score[VtScoreSize], buf[VtRootSize];
-	VacFile *root;
-
-	if(!readScore(file, score))
-		return nil;
-
-	n = vtRead(z, score, VtRootType, buf, VtRootSize);
-	if(n < 0){
-		fprint(2, "cannot read %V: %r\n", score);
-		return nil;
-	}
-	if(n != VtRootSize) {
-		vtSetError("vtRead on root too short");
-		return nil;
-	}
-
-	if(!vtSha1Check(score, buf, VtRootSize)) {
-		vtSetError("vtSha1Check failed on root block");	
-		return nil;
-	}
-
-	if(!vtRootUnpack(&rt, buf))
-		return nil;
-
-	if(strcmp(rt.type, "vac") != 0) {
-		vtSetError("not a vac root");
-		return nil;
-	}
-
-	fs = vfsAlloc(z, rt.blockSize, ncache);
-	vfsGetScore(fs, score);
-	fs->readOnly = readOnly;
-	root = vfRoot(fs, rt.score);
-	if(root == nil)
-		goto Err;
-	fs->root = root;
-
-	return fs;
-Err:
-	if(root)
-		vfDecRef(root);
-	vfsClose(fs);
-	return nil;
-}
-
-VacFS *
-vacFsCreate(VtSession *z, int bsize, long ncache)
-{
-	return vfsAlloc(z, bsize, ncache);
-}
-
-int
-vfsIsReadOnly(VacFS *fs)
-{
-	return fs->readOnly != 0;
-}
-
-VacFile *
-vfsGetRoot(VacFS *fs)
-{
-	return vfIncRef(fs->root);
-}
-
-int
-vfsGetBlockSize(VacFS *fs)
-{
-	return fs->bsize;
-}
-
-int
-vfsGetScore(VacFS *fs, uchar score[VtScoreSize])
-{
-	memmove(fs->score, score, VtScoreSize);
-	return 1;
-}
-
-long
-vfsGetCacheSize(VacFS *fs)
-{
-	return cacheGetSize(fs->cache);
-}
-
-int
-vfsSetCacheSize(VacFS *fs, long size)
-{
-	return cacheSetSize(fs->cache, size);
-}
-
-int
-vfsSnapshot(VacFS *fs, char *src, char *dst)
-{
-	USED(fs);
-	USED(src);
-	USED(dst);
-	return 1;
-}
-
-int
-vfsSync(VacFS*)
-{
-	return 1;
-}
-
-int
-vfsClose(VacFS *fs)
-{
-	if(fs->root)
-		vfDecRef(fs->root);
-	fs->root = nil;
-	cacheCheck(fs->cache);
-	cacheFree(fs->cache);
-	memset(fs, 0, sizeof(VacFS));
-	vtMemFree(fs);
-	return 1;
-}
-
-

+ 3 - 8
sys/src/cmd/vac/mkfile

@@ -1,27 +1,24 @@
 </$objtype/mkfile
 </$objtype/mkfile
 
 
 LIBFILES=\
 LIBFILES=\
-	cache\
 	error\
 	error\
 	file\
 	file\
-	fs\
-	source\
 	pack\
 	pack\
 
 
 LIB=${LIBFILES:%=%.$O}
 LIB=${LIBFILES:%=%.$O}
 
 
 HFILES=\
 HFILES=\
-	/sys/include/oventi.h\
+	/sys/include/venti.h\
 	stdinc.h\
 	stdinc.h\
 	error.h\
 	error.h\
 	vac.h\
 	vac.h\
 	dat.h\
 	dat.h\
 	fns.h\
 	fns.h\
 
 
-TARG=vacfs vac vtdump
+TARG=vac unvac vacfs
 BIN=/$objtype/bin
 BIN=/$objtype/bin
 
 
-CFILES=${TARG:%=%.c} ${LIBFILES:%=%.c} srcload.c vactest.c
+CFILES=${TARG:%=%.c} ${LIBFILES:%=%.c}
 
 
 UPDATE=\
 UPDATE=\
 	mkfile\
 	mkfile\
@@ -31,6 +28,4 @@ UPDATE=\
 
 
 default:V: all
 default:V: all
 
 
-test:V: $O.srcload $O.wtest $O.rtest $O.vtdump $O.vtread
-
 </sys/src/cmd/mkmany
 </sys/src/cmd/mkmany

+ 228 - 101
sys/src/cmd/vac/pack.c

@@ -12,7 +12,7 @@ struct MetaChunk {
 	ushort index;
 	ushort index;
 };
 };
 
 
-static int	stringUnpack(char **s, uchar **p, int *n);
+static int	stringunpack(char **s, uchar **p, int *n);
 
 
 /*
 /*
  * integer conversion routines
  * integer conversion routines
@@ -23,35 +23,35 @@ static int	stringUnpack(char **s, uchar **p, int *n);
 #define	U48GET(p)	(((uvlong)U16GET(p)<<32)|(uvlong)U32GET((p)+2))
 #define	U48GET(p)	(((uvlong)U16GET(p)<<32)|(uvlong)U32GET((p)+2))
 #define	U64GET(p)	(((uvlong)U32GET(p)<<32)|(uvlong)U32GET((p)+4))
 #define	U64GET(p)	(((uvlong)U32GET(p)<<32)|(uvlong)U32GET((p)+4))
 
 
-#define	U8PUT(p,v)	(p)[0]=(v)
-#define	U16PUT(p,v)	(p)[0]=(v)>>8;(p)[1]=(v)
-#define	U32PUT(p,v)	(p)[0]=(v)>>24;(p)[1]=(v)>>16;(p)[2]=(v)>>8;(p)[3]=(v)
+#define	U8PUT(p,v)	(p)[0]=(v)&0xFF
+#define	U16PUT(p,v)	(p)[0]=((v)>>8)&0xFF;(p)[1]=(v)&0xFF
+#define	U32PUT(p,v)	(p)[0]=((v)>>24)&0xFF;(p)[1]=((v)>>16)&0xFF;(p)[2]=((v)>>8)&0xFF;(p)[3]=(v)&0xFF
 #define	U48PUT(p,v,t32)	t32=(v)>>32;U16PUT(p,t32);t32=(v);U32PUT((p)+2,t32)
 #define	U48PUT(p,v,t32)	t32=(v)>>32;U16PUT(p,t32);t32=(v);U32PUT((p)+2,t32)
 #define	U64PUT(p,v,t32)	t32=(v)>>32;U32PUT(p,t32);t32=(v);U32PUT((p)+4,t32)
 #define	U64PUT(p,v,t32)	t32=(v)>>32;U32PUT(p,t32);t32=(v);U32PUT((p)+4,t32)
 
 
 static int
 static int
-stringUnpack(char **s, uchar **p, int *n)
+stringunpack(char **s, uchar **p, int *n)
 {
 {
 	int nn;
 	int nn;
 
 
 	if(*n < 2)
 	if(*n < 2)
-		return 0;
+		return -1;
 	
 	
 	nn = U16GET(*p);
 	nn = U16GET(*p);
 	*p += 2;
 	*p += 2;
 	*n -= 2;
 	*n -= 2;
 	if(nn > *n)
 	if(nn > *n)
-		return 0;
-	*s = vtMemAlloc(nn+1);
+		return -1;
+	*s = vtmalloc(nn+1);
 	memmove(*s, *p, nn);
 	memmove(*s, *p, nn);
 	(*s)[nn] = 0;
 	(*s)[nn] = 0;
 	*p += nn;
 	*p += nn;
 	*n -= nn;
 	*n -= nn;
-	return 1;
+	return 0;
 }
 }
 
 
 static int
 static int
-stringPack(char *s, uchar *p)
+stringpack(char *s, uchar *p)
 {
 {
 	int n;
 	int n;
 
 
@@ -63,7 +63,7 @@ stringPack(char *s, uchar *p)
 
 
 
 
 int
 int
-mbUnpack(MetaBlock *mb, uchar *p, int n)
+mbunpack(MetaBlock *mb, uchar *p, int n)
 {
 {
 	u32int magic;
 	u32int magic;
 
 
@@ -72,13 +72,13 @@ mbUnpack(MetaBlock *mb, uchar *p, int n)
 
 
 	if(n == 0) {
 	if(n == 0) {
 		memset(mb, 0, sizeof(MetaBlock));
 		memset(mb, 0, sizeof(MetaBlock));
-		return 1;
+		return 0;
 	}
 	}
 
 
 	magic = U32GET(p);
 	magic = U32GET(p);
 	if(magic != MetaMagic && magic != MetaMagic+1) {
 	if(magic != MetaMagic && magic != MetaMagic+1) {
-		vtSetError("bad meta block magic");
-		return 0;
+		werrstr("bad meta block magic");
+		return -1;
 	}
 	}
 	mb->size = U16GET(p+4);
 	mb->size = U16GET(p+4);
 	mb->free = U16GET(p+6);
 	mb->free = U16GET(p+6);
@@ -87,22 +87,22 @@ mbUnpack(MetaBlock *mb, uchar *p, int n)
 	mb->unbotch = (magic == MetaMagic+1);
 	mb->unbotch = (magic == MetaMagic+1);
 
 
 	if(mb->size > n) {
 	if(mb->size > n) {
-		vtSetError("bad meta block size");
-		return 0;
+		werrstr("bad meta block size");
+		return -1;
 	}
 	}
 	p += MetaHeaderSize;
 	p += MetaHeaderSize;
 	n -= MetaHeaderSize;
 	n -= MetaHeaderSize;
 
 
 	USED(p);
 	USED(p);
 	if(n < mb->maxindex*MetaIndexSize) {
 	if(n < mb->maxindex*MetaIndexSize) {
- 		vtSetError("truncated meta block 2");
-		return 0;
+ 		werrstr("truncated meta block 2");
+		return -1;
 	}
 	}
-	return 1;
+	return 0;
 }
 }
 
 
 void
 void
-mbPack(MetaBlock *mb)
+mbpack(MetaBlock *mb)
 {
 {
 	uchar *p;
 	uchar *p;
 
 
@@ -117,7 +117,7 @@ mbPack(MetaBlock *mb)
 
 
 
 
 void
 void
-mbDelete(MetaBlock *mb, int i, MetaEntry *me)
+mbdelete(MetaBlock *mb, int i, MetaEntry *me)
 {
 {
 	uchar *p;
 	uchar *p;
 	int n;
 	int n;
@@ -137,7 +137,7 @@ mbDelete(MetaBlock *mb, int i, MetaEntry *me)
 }
 }
 
 
 void
 void
-mbInsert(MetaBlock *mb, int i, MetaEntry *me)
+mbinsert(MetaBlock *mb, int i, MetaEntry *me)
 {
 {
 	uchar *p;
 	uchar *p;
 	int o, n;
 	int o, n;
@@ -161,14 +161,14 @@ mbInsert(MetaBlock *mb, int i, MetaEntry *me)
 }
 }
 
 
 int
 int
-meUnpack(MetaEntry *me, MetaBlock *mb, int i)
+meunpack(MetaEntry *me, MetaBlock *mb, int i)
 {
 {
 	uchar *p;
 	uchar *p;
 	int eo, en;
 	int eo, en;
 
 
 	if(i < 0 || i >= mb->nindex) {
 	if(i < 0 || i >= mb->nindex) {
-		vtSetError("bad meta entry index");
-		return 0;
+		werrstr("bad meta entry index");
+		return -1;
 	}
 	}
 
 
 	p = mb->buf + MetaHeaderSize + i*MetaIndexSize;
 	p = mb->buf + MetaHeaderSize + i*MetaIndexSize;
@@ -177,32 +177,32 @@ meUnpack(MetaEntry *me, MetaBlock *mb, int i)
 
 
 if(0)print("eo = %d en = %d\n", eo, en);
 if(0)print("eo = %d en = %d\n", eo, en);
 	if(eo < MetaHeaderSize + mb->maxindex*MetaIndexSize) {
 	if(eo < MetaHeaderSize + mb->maxindex*MetaIndexSize) {
-		vtSetError("corrupted entry in meta block");
-		return 0;
+		werrstr("corrupted entry in meta block");
+		return -1;
 	}
 	}
 
 
 	if(eo+en > mb->size) {
 	if(eo+en > mb->size) {
- 		vtSetError("truncated meta block");
-		return 0;
+ 		werrstr("truncated meta block");
+		return -1;
 	}
 	}
 
 
 	p = mb->buf + eo;
 	p = mb->buf + eo;
 	
 	
 	/* make sure entry looks ok and includes an elem name */
 	/* make sure entry looks ok and includes an elem name */
 	if(en < 8 || U32GET(p) != DirMagic || en < 8 + U16GET(p+6)) {
 	if(en < 8 || U32GET(p) != DirMagic || en < 8 + U16GET(p+6)) {
-		vtSetError("corrupted meta block entry");
-		return 0;
+		werrstr("corrupted meta block entry");
+		return -1;
 	}
 	}
 
 
 	me->p = p;
 	me->p = p;
 	me->size = en;
 	me->size = en;
 
 
-	return 1;
+	return 0;
 }
 }
 
 
-/* assumes a small amount of checking has been done in mbEntry */
+/* assumes a small amount of checking has been done in mbentry */
 int
 int
-meCmp(MetaEntry *me, char *s)
+mecmp(MetaEntry *me, char *s)
 {
 {
 	int n;
 	int n;
 	uchar *p;
 	uchar *p;
@@ -230,7 +230,7 @@ meCmp(MetaEntry *me, char *s)
 }
 }
 
 
 int
 int
-meCmpNew(MetaEntry *me, char *s)
+mecmpnew(MetaEntry *me, char *s)
 {
 {
 	int n;
 	int n;
 	uchar *p;
 	uchar *p;
@@ -258,9 +258,9 @@ meCmpNew(MetaEntry *me, char *s)
 }
 }
 
 
 static int
 static int
-offsetCmp(void *s0, void *s1)
+offsetcmp(const void *s0, const void *s1)
 {
 {
-	MetaChunk *mc0, *mc1;
+	const MetaChunk *mc0, *mc1;
 
 
 	mc0 = s0;
 	mc0 = s0;
 	mc1 = s1;
 	mc1 = s1;
@@ -272,13 +272,13 @@ offsetCmp(void *s0, void *s1)
 }
 }
 
 
 static MetaChunk *
 static MetaChunk *
-metaChunks(MetaBlock *mb)
+metachunks(MetaBlock *mb)
 {
 {
 	MetaChunk *mc;
 	MetaChunk *mc;
 	int oo, o, n, i;
 	int oo, o, n, i;
 	uchar *p;
 	uchar *p;
 
 
-	mc = vtMemAlloc(mb->nindex*sizeof(MetaChunk));
+	mc = vtmalloc(mb->nindex*sizeof(MetaChunk));
 	p = mb->buf + MetaHeaderSize;
 	p = mb->buf + MetaHeaderSize;
 	for(i = 0; i<mb->nindex; i++) {
 	for(i = 0; i<mb->nindex; i++) {
 		mc[i].offset = U16GET(p);
 		mc[i].offset = U16GET(p);
@@ -287,7 +287,7 @@ metaChunks(MetaBlock *mb)
 		p += MetaIndexSize;
 		p += MetaIndexSize;
 	}
 	}
 
 
-	qsort(mc, mb->nindex, sizeof(MetaChunk), offsetCmp);
+	qsort(mc, mb->nindex, sizeof(MetaChunk), offsetcmp);
 
 
 	/* check block looks ok */
 	/* check block looks ok */
 	oo = MetaHeaderSize + mb->maxindex*MetaIndexSize;
 	oo = MetaHeaderSize + mb->maxindex*MetaIndexSize;
@@ -307,12 +307,12 @@ metaChunks(MetaBlock *mb)
 
 
 	return mc;
 	return mc;
 Err:
 Err:
-	vtMemFree(mc);
+	vtfree(mc);
 	return nil;
 	return nil;
 }
 }
 
 
 static void
 static void
-mbCompact(MetaBlock *mb, MetaChunk *mc)
+mbcompact(MetaBlock *mb, MetaChunk *mc)
 {
 {
 	int oo, o, n, i;
 	int oo, o, n, i;
 
 
@@ -333,7 +333,7 @@ mbCompact(MetaBlock *mb, MetaChunk *mc)
 }
 }
 
 
 uchar *
 uchar *
-mbAlloc(MetaBlock *mb, int n)
+mballoc(MetaBlock *mb, int n)
 {
 {
 	int i, o;
 	int i, o;
 	MetaChunk *mc;
 	MetaChunk *mc;
@@ -346,44 +346,43 @@ mbAlloc(MetaBlock *mb, int n)
 	if(mb->maxsize - mb->size + mb->free < n)
 	if(mb->maxsize - mb->size + mb->free < n)
 		return nil;
 		return nil;
 
 
-	mc = metaChunks(mb);
+	mc = metachunks(mb);
 
 
 	/* look for hole */
 	/* look for hole */
 	o = MetaHeaderSize + mb->maxindex*MetaIndexSize;
 	o = MetaHeaderSize + mb->maxindex*MetaIndexSize;
 	for(i=0; i<mb->nindex; i++) {
 	for(i=0; i<mb->nindex; i++) {
 		if(mc[i].offset - o >= n) {
 		if(mc[i].offset - o >= n) {
-			vtMemFree(mc);
+			vtfree(mc);
 			return mb->buf + o;
 			return mb->buf + o;
 		}
 		}
 		o = mc[i].offset + mc[i].size;
 		o = mc[i].offset + mc[i].size;
 	}
 	}
 
 
 	if(mb->maxsize - o >= n) {
 	if(mb->maxsize - o >= n) {
-		vtMemFree(mc);
+		vtfree(mc);
 		return mb->buf + o;
 		return mb->buf + o;
 	}
 	}
 
 
 	/* compact and return off the end */
 	/* compact and return off the end */
-	mbCompact(mb, mc);
-	vtMemFree(mc);
+	mbcompact(mb, mc);
+	vtfree(mc);
 
 
 	assert(mb->maxsize - mb->size >= n);
 	assert(mb->maxsize - mb->size >= n);
 	return mb->buf + mb->size;
 	return mb->buf + mb->size;
 }
 }
 
 
 int
 int
-vdSize(VacDir *dir)
+vdsize(VacDir *dir, int version)
 {
 {
 	int n;
 	int n;
 	
 	
-	/* constant part */
+	if(version < 8 || version > 9)
+		sysfatal("bad version %d in vdpack", version);
 
 
+	/* constant part */
 	n = 	4 +	/* magic */
 	n = 	4 +	/* magic */
 		2 + 	/* version */
 		2 + 	/* version */
 		4 +	/* entry */
 		4 +	/* entry */
-		4 + 	/* guid */
-		4 + 	/* mentry */
-		4 + 	/* mgen */
 		8 +	/* qid */
 		8 +	/* qid */
 		4 + 	/* mtime */
 		4 + 	/* mtime */
 		4 + 	/* mcount */
 		4 + 	/* mcount */
@@ -392,6 +391,13 @@ vdSize(VacDir *dir)
 		4 +	/* mode */
 		4 +	/* mode */
 		0;
 		0;
 
 
+	if(version == 9){
+		n += 	4 +	/* gen */
+			4 + 	/* mentry */
+			4 + 	/* mgen */
+			0;
+	}
+
 	/* strings */
 	/* strings */
 	n += 2 + strlen(dir->elem);
 	n += 2 + strlen(dir->elem);
 	n += 2 + strlen(dir->uid);
 	n += 2 + strlen(dir->uid);
@@ -399,39 +405,57 @@ vdSize(VacDir *dir)
 	n += 2 + strlen(dir->mid);
 	n += 2 + strlen(dir->mid);
 
 
 	/* optional sections */
 	/* optional sections */
-	if(dir->qidSpace) {
+	if(version < 9 && dir->plan9) {
+		n += 	3 + 	/* option header */
+			8 + 	/* path */
+			4;	/* version */
+	}
+	if(dir->qidspace) {
 		n += 	3 + 	/* option header */
 		n += 	3 + 	/* option header */
-			8 + 	/* qidOffset */
-			8;	/* qid Max */
+			8 + 	/* qid offset */
+			8;	/* qid max */
+	}
+	if(version < 9 && dir->gen) {
+		n += 	3 + 	/* option header */
+			4;	/* gen */
 	}
 	}
 
 
 	return n;
 	return n;
 }
 }
 
 
 void
 void
-vdPack(VacDir *dir, MetaEntry *me)
+vdpack(VacDir *dir, MetaEntry *me, int version)
 {
 {
 	uchar *p;
 	uchar *p;
 	ulong t32;
 	ulong t32;
 
 
+	if(version < 8 || version > 9)
+		sysfatal("bad version %d in vdpack", version);
+
 	p = me->p;
 	p = me->p;
 	
 	
 	U32PUT(p, DirMagic);
 	U32PUT(p, DirMagic);
-	U16PUT(p+4, 9);		/* version */
+	U16PUT(p+4, version);		/* version */
 	p += 6;
 	p += 6;
 
 
-	p += stringPack(dir->elem, p);
+	p += stringpack(dir->elem, p);
 
 
 	U32PUT(p, dir->entry);
 	U32PUT(p, dir->entry);
-	U32PUT(p+4, dir->gen);
-	U32PUT(p+8, dir->mentry);
-	U32PUT(p+12, dir->mgen);
-	U64PUT(p+16, dir->qid, t32);
-	p += 24;
-
-	p += stringPack(dir->uid, p);
-	p += stringPack(dir->gid, p);
-	p += stringPack(dir->mid, p);
+	p += 4;
+	
+	if(version == 9){
+		U32PUT(p, dir->gen);
+		U32PUT(p+4, dir->mentry);
+		U32PUT(p+8, dir->mgen);
+		p += 12;
+	}
+
+	U64PUT(p, dir->qid, t32);
+	p += 8;
+
+	p += stringpack(dir->uid, p);
+	p += stringpack(dir->gid, p);
+	p += stringpack(dir->mid, p);
 	
 	
 	U32PUT(p, dir->mtime);
 	U32PUT(p, dir->mtime);
 	U32PUT(p+4, dir->mcount);
 	U32PUT(p+4, dir->mcount);
@@ -440,20 +464,37 @@ vdPack(VacDir *dir, MetaEntry *me)
 	U32PUT(p+16, dir->mode);
 	U32PUT(p+16, dir->mode);
 	p += 5*4;
 	p += 5*4;
 
 
-	if(dir->qidSpace) {
+	if(dir->plan9 && version < 9) {
+		U8PUT(p, DirPlan9Entry);
+		U16PUT(p+1, 8+4);
+		p += 3;
+		U64PUT(p, dir->p9path, t32);
+		U32PUT(p+8, dir->p9version);
+		p += 12;
+	}
+
+	if(dir->qidspace) {
 		U8PUT(p, DirQidSpaceEntry);
 		U8PUT(p, DirQidSpaceEntry);
 		U16PUT(p+1, 2*8);
 		U16PUT(p+1, 2*8);
 		p += 3;
 		p += 3;
-		U64PUT(p, dir->qidOffset, t32);
-		U64PUT(p+8, dir->qidMax, t32);
+		U64PUT(p, dir->qidoffset, t32);
+		U64PUT(p+8, dir->qidmax, t32);
+		p += 16;
+	}
+	
+	if(dir->gen && version < 9) {
+		U8PUT(p, DirGenEntry);
+		U16PUT(p+1, 4);
+		p += 3;
+		U32PUT(p, dir->gen);
+		p += 4;
 	}
 	}
 
 
 	assert(p == me->p + me->size);
 	assert(p == me->p + me->size);
 }
 }
 
 
-
 int
 int
-vdUnpack(VacDir *dir, MetaEntry *me)
+vdunpack(VacDir *dir, MetaEntry *me)
 {
 {
 	int t, nn, n, version;
 	int t, nn, n, version;
 	uchar *p;
 	uchar *p;
@@ -463,14 +504,12 @@ vdUnpack(VacDir *dir, MetaEntry *me)
 
 
 	memset(dir, 0, sizeof(VacDir));
 	memset(dir, 0, sizeof(VacDir));
 
 
-if(0)print("vdUnpack\n");
 	/* magic */
 	/* magic */
 	if(n < 4 || U32GET(p) != DirMagic)
 	if(n < 4 || U32GET(p) != DirMagic)
 		goto Err;
 		goto Err;
 	p += 4;
 	p += 4;
 	n -= 4;
 	n -= 4;
 
 
-if(0)print("vdUnpack: got magic\n");
 	/* version */
 	/* version */
 	if(n < 2)
 	if(n < 2)
 		goto Err;
 		goto Err;
@@ -480,14 +519,10 @@ if(0)print("vdUnpack: got magic\n");
 	p += 2;
 	p += 2;
 	n -= 2;	
 	n -= 2;	
 
 
-if(0)print("vdUnpack: got version\n");
-
 	/* elem */
 	/* elem */
-	if(!stringUnpack(&dir->elem, &p, &n))
+	if(stringunpack(&dir->elem, &p, &n) < 0)
 		goto Err;
 		goto Err;
 
 
-if(0)print("vdUnpack: got elem\n");
-
 	/* entry  */
 	/* entry  */
 	if(n < 4)
 	if(n < 4)
 		goto Err;
 		goto Err;
@@ -495,8 +530,6 @@ if(0)print("vdUnpack: got elem\n");
 	p += 4;
 	p += 4;
 	n -= 4;
 	n -= 4;
 
 
-if(0)print("vdUnpack: got entry\n");
-
 	if(version < 9) {
 	if(version < 9) {
 		dir->gen = 0;
 		dir->gen = 0;
 		dir->mentry = dir->entry+1;
 		dir->mentry = dir->entry+1;
@@ -511,8 +544,6 @@ if(0)print("vdUnpack: got entry\n");
 		n -= 3*4;
 		n -= 3*4;
 	}
 	}
 
 
-if(0)print("vdUnpack: got gen etc\n");
-
 	/* size is gotten from DirEntry */
 	/* size is gotten from DirEntry */
 
 
 	/* qid */
 	/* qid */
@@ -522,7 +553,6 @@ if(0)print("vdUnpack: got gen etc\n");
 	p += 8;
 	p += 8;
 	n -= 8;
 	n -= 8;
 
 
-if(0)print("vdUnpack: got qid\n");
 	/* skip replacement */
 	/* skip replacement */
 	if(version == 7) {
 	if(version == 7) {
 		if(n < VtScoreSize)
 		if(n < VtScoreSize)
@@ -532,18 +562,17 @@ if(0)print("vdUnpack: got qid\n");
 	}
 	}
 	
 	
 	/* uid */
 	/* uid */
-	if(!stringUnpack(&dir->uid, &p, &n))
+	if(stringunpack(&dir->uid, &p, &n) < 0)
 		goto Err;
 		goto Err;
 
 
 	/* gid */
 	/* gid */
-	if(!stringUnpack(&dir->gid, &p, &n))
+	if(stringunpack(&dir->gid, &p, &n) < 0)
 		goto Err;
 		goto Err;
 
 
 	/* mid */
 	/* mid */
-	if(!stringUnpack(&dir->mid, &p, &n))
+	if(stringunpack(&dir->mid, &p, &n) < 0)
 		goto Err;
 		goto Err;
 
 
-if(0)print("vdUnpack: got ids\n");
 	if(n < 5*4)
 	if(n < 5*4)
 		goto Err;
 		goto Err;
 	dir->mtime = U32GET(p);
 	dir->mtime = U32GET(p);
@@ -554,7 +583,6 @@ if(0)print("vdUnpack: got ids\n");
 	p += 5*4;
 	p += 5*4;
 	n -= 5*4;
 	n -= 5*4;
 
 
-if(0)print("vdUnpack: got times\n");
 	/* optional meta data */
 	/* optional meta data */
 	while(n > 0) {
 	while(n > 0) {
 		if(n < 3)
 		if(n < 3)
@@ -584,26 +612,125 @@ if(0)print("vdUnpack: got times\n");
 				break;
 				break;
 			break;
 			break;
 		case DirQidSpaceEntry:
 		case DirQidSpaceEntry:
-			if(dir->qidSpace || nn != 16)
+			if(dir->qidspace || nn != 16)
 				goto Err;
 				goto Err;
-			dir->qidSpace = 1;
-			dir->qidOffset = U64GET(p);
-			dir->qidMax = U64GET(p+8);
+			dir->qidspace = 1;
+			dir->qidoffset = U64GET(p);
+			dir->qidmax = U64GET(p+8);
 			break;
 			break;
 		}
 		}
 		p += nn;
 		p += nn;
 		n -= nn;
 		n -= nn;
 	}
 	}
-if(0)print("vdUnpack: got options\n");
 
 
 	if(p != me->p + me->size)
 	if(p != me->p + me->size)
 		goto Err;
 		goto Err;
 
 
-if(0)print("vdUnpack: correct size\n");
-	return 1;
-Err:
-if(0)print("vdUnpack: XXXXXXXXXXXX EbadMeta\n");
-	vtSetError(EBadMeta);
-	vdCleanup(dir);
 	return 0;
 	return 0;
+Err:
+	werrstr(EBadMeta);
+	vdcleanup(dir);
+	return -1;
+}
+
+void
+vdcleanup(VacDir *dir)
+{
+	vtfree(dir->elem);
+	dir->elem = nil;
+	vtfree(dir->uid);
+	dir->uid = nil;
+	vtfree(dir->gid);
+	dir->gid = nil;
+	vtfree(dir->mid);
+	dir->mid = nil;
+}
+
+void
+vdcopy(VacDir *dst, VacDir *src)
+{
+	*dst = *src;
+	dst->elem = vtstrdup(dst->elem);
+	dst->uid = vtstrdup(dst->uid);
+	dst->gid = vtstrdup(dst->gid);
+	dst->mid = vtstrdup(dst->mid);
+}
+
+int
+mbsearch(MetaBlock *mb, char *elem, int *ri, MetaEntry *me)
+{
+	int i;
+	int b, t, x;
+
+	/* binary search within block */
+	b = 0;
+	t = mb->nindex;
+	while(b < t) {
+		i = (b+t)>>1;
+		if(meunpack(me, mb, i) < 0)
+			return 0;
+		if(mb->unbotch)
+			x = mecmpnew(me, elem);
+		else
+			x = mecmp(me, elem);
+
+		if(x == 0) {
+			*ri = i;
+			return 1;
+		}
+	
+		if(x < 0)
+			b = i+1;
+		else /* x > 0 */
+			t = i;
+	}
+
+	assert(b == t);
+	
+	*ri = b;	/* b is the index to insert this entry */
+	memset(me, 0, sizeof(*me));
+
+	return -1;
+}
+
+void
+mbinit(MetaBlock *mb, uchar *p, int n, int entries)
+{
+	memset(mb, 0, sizeof(MetaBlock));
+	mb->maxsize = n;
+	mb->buf = p;
+	mb->maxindex = entries;
+	mb->size = MetaHeaderSize + mb->maxindex*MetaIndexSize;
+}
+
+int
+mbresize(MetaBlock *mb, MetaEntry *me, int n)
+{
+	uchar *p, *ep;
+
+	/* easy case */
+	if(n <= me->size){
+		me->size = n;
+		return 0;
+	}
+
+	/* try and expand entry */
+
+	p = me->p + me->size;
+	ep = mb->buf + mb->maxsize;
+	while(p < ep && *p == 0)
+		p++;
+	if(n <= p - me->p){
+		me->size = n;
+		return 0;
+	}
+
+	p = mballoc(mb, n);
+	if(p != nil){
+		me->p = p;
+		me->size = n;
+		return 0;
+	}
+
+	return -1;
 }
 }

+ 0 - 71
sys/src/cmd/vac/rtest.c

@@ -1,71 +0,0 @@
-#include "stdinc.h"
-
-enum {
-	Nblock = 300000,
-	BlockSize = 8*1024,
-};
-
-uchar data[Nblock*VtScoreSize];
-int rflag;
-int nblock = 10000;
-int perm[Nblock];
-
-void
-main(int argc, char *argv[])
-{
-	VtSession *z;
-	int i, j, t;
-	int start;
-	uchar buf[BlockSize];
-
-	srand(time(0));
-
-	ARGBEGIN{
-	case 'r':
-		rflag++;
-		break;
-	case 'n':
-		nblock = atoi(ARGF());
-		break;
-	}ARGEND
-
-	for(i=0; i<nblock; i++)
-		perm[i] = i;
-
-	if(rflag) {
-		for(i=0; i<nblock; i++) {
-			j = nrand(nblock);
-			t = perm[j];
-			perm[j] = perm[i];
-			perm[i] = t;
-		}
-	}
-
-	if(readn(0, data, VtScoreSize*nblock) < VtScoreSize*nblock)
-		sysfatal("read failed: %r");
-
-	vtAttach();
-
-	z = vtDial("iolaire2");
-	if(z == nil)
-		sysfatal("cound not connect to venti");
-	if(!vtConnect(z, 0))
-		vtFatal("vtConnect: %s", vtGetError());
-
-	print("starting\n");
-
-	start = times(0);
-
-	if(rflag && nblock > 10000)
-		nblock = 10000;
-
-	for(i=0; i<nblock; i++) {
-		if(vtRead(z, data+perm[i]*VtScoreSize, VtDataType, buf, BlockSize) < 0)
-			vtFatal("vtRead failed: %d: %s", i, vtGetError());
-	}
-
-	print("time = %f\n", (times(0) - start)*0.001);
-
-	vtClose(z);
-	vtDetach();
-}

+ 0 - 390
sys/src/cmd/vac/source.c

@@ -1,390 +0,0 @@
-#include "stdinc.h"
-#include "vac.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-static int	sizeToDepth(uvlong s, int psize, int dsize);
-
-static int
-sizeToDepth(uvlong s, int psize, int dsize)
-{
-	int np;
-	int d;
-	
-	/* determine pointer depth */
-	np = psize/VtScoreSize;
-	s = (s + dsize - 1)/dsize;
-	for(d = 0; s > 1; d++)
-		s = (s + np - 1)/np;
-	return d;
-}
-
-/* assumes u is lock? */
-Source *
-sourceAlloc(Cache *c, Lump *u, ulong block, int entry, int readOnly)
-{
-	Source *r;
-	VtEntry d;
-
-	if(u->asize < (entry+1)*VtEntrySize) {
-		vtSetError(ENoDir);
-		return nil;
-	}
-
-	if(!vtEntryUnpack(&d, u->data, entry))
-		return nil;
-	
-	if(!(d.flags & VtEntryActive)) {
-fprint(2, "%s: bad flags %#ux %V\n", argv0, d.flags, d.score);
-		vtSetError(ENoDir);
-		return nil;
-	}
-	
-	/* HACK for backwards compatiblity - should go away at some point */
-	if(d.depth == 0) {
-if(d.size > d.dsize) fprint(2, "%s: depth == 0! size = %ulld\n", argv0, d.size);
-		d.depth = sizeToDepth(d.size, d.psize, d.dsize);
-	}
-
-	if(d.depth < sizeToDepth(d.size, d.psize, d.dsize)) {
-		vtSetError(EBadDir);
-		return nil;
-	}
-
-	r = vtMemAllocZ(sizeof(Source));
-	r->lk = vtLockAlloc();
-	r->cache = c;
-	r->readOnly = readOnly;
-	r->lump = lumpIncRef(u);
-	r->block = block;
-	r->entry = entry;
-	r->gen = d.gen;
-	r->dir = (d.flags & VtEntryDir) != 0;
-	r->depth = d.depth;
-	r->psize = d.psize;
-	r->dsize = d.dsize;
-	r->size = d.size;
-
-	r->epb = r->dsize/VtEntrySize;
-
-	return r;
-}
-
-Source *
-sourceOpen(Source *r, ulong entry, int readOnly)
-{
-	ulong bn;
-	Lump *u;
-
-if(0)fprint(2, "%s: sourceOpen: %V:%d: %lud\n", argv0, r->lump->score, r->entry, entry);
-	if(r->readOnly && !readOnly) {
-		vtSetError(EReadOnly);
-		return nil;
-	}
-
-	bn = entry/r->epb;
-
-	u = sourceGetLump(r, bn, readOnly, 1);
-	if(u == nil)
-		return nil;
-
-	r = sourceAlloc(r->cache, u, bn, entry%r->epb, readOnly);
-	lumpDecRef(u, 1);
-	return r;
-}
-
-Source *
-sourceCreate(Source *r, int psize, int dsize, int isdir, ulong entry)
-{
-	Source *rr;
-	int i;
-	Lump *u;
-	ulong bn;
-	VtEntry dir;
-
-	if(r->readOnly) {
-		vtSetError(EReadOnly);
-		return nil;
-	}
-
-	if(entry == 0) {
-		/*
-		 * look at a random block to see if we can find an empty entry
-		 */
-		entry = sourceGetDirSize(r);
-		entry = r->epb*lnrand(entry/r->epb+1);
-	}
-
-	/*
-	 * need to loop since multiple threads could be trying to allocate
-	 */
-	for(;;) {
-		bn = entry/r->epb;
-		sourceSetDepth(r, (uvlong)(bn+1)*r->dsize);
-		u = sourceGetLump(r, bn, 0, 1);
-		if(u == nil)
-			return nil;
-		for(i=entry%r->epb; i<r->epb; i++) {
-			vtEntryUnpack(&dir, u->data, i);
-			if((dir.flags&VtEntryActive) == 0 && dir.gen != ~0)
-				goto Found;
-		}
-		lumpDecRef(u, 1);
-		entry = sourceGetDirSize(r);
-	}
-Found:
-	/* found an entry */
-	dir.psize = psize;
-	dir.dsize = dsize;
-	dir.flags = VtEntryActive;
-	if(isdir)
-		dir.flags |= VtEntryDir;
-	dir.depth = 0;
-	dir.size = 0;
-	memmove(dir.score, vtZeroScore, VtScoreSize);
-	vtEntryPack(&dir, u->data, i);
-
-	sourceSetDirSize(r, bn*r->epb + i + 1);
-	rr = sourceAlloc(r->cache, u, bn, i, 0);
-	
-	lumpDecRef(u, 1);
-	return rr;
-}
-
-void
-sourceRemove(Source *r)
-{
-	lumpFreeEntry(r->lump, r->entry);
-	sourceFree(r);
-}
-
-int
-sourceSetDepth(Source *r, uvlong size)
-{
-	Lump *u, *v;
-	VtEntry dir;
-	int depth;
-
-	if(r->readOnly){
-		vtSetError(EReadOnly);
-		return 0;
-	}
-
-	depth = sizeToDepth(size, r->psize, r->dsize);
-
-	assert(depth >= 0);
-
-	if(depth > VtPointerDepth) {
-		vtSetError(ETooBig);
-		return 0;
-	}
-
-	vtLock(r->lk);
-
-	if(r->depth >= depth) {
-		vtUnlock(r->lk);
-		return 1;
-	}
-	
-	u = r->lump;
-	vtLock(u->lk);
-	if(!vtEntryUnpack(&dir, u->data, r->entry)) {
-		vtUnlock(u->lk);
-		vtUnlock(r->lk);
-		return 0;
-	}
-	while(dir.depth < depth) {
-		v = cacheAllocLump(r->cache, VtPointerType0+r->depth, r->psize, r->dir);
-		if(v == nil)
-			break;
-		memmove(v->data, dir.score, VtScoreSize);
-		memmove(dir.score, v->score, VtScoreSize);
-		dir.depth++;
-		vtUnlock(v->lk);
-	}
-	vtEntryPack(&dir, u->data, r->entry);
-	vtUnlock(u->lk);
-
-	r->depth = dir.depth;
-	vtUnlock(r->lk);
-
-	return dir.depth == depth;
-}
-
-int
-sourceGetVtEntry(Source *r, VtEntry *dir)
-{
-	Lump *u;
-
-	u = r->lump;
-	vtLock(u->lk);
-	if(!vtEntryUnpack(dir, u->data, r->entry)) {
-		vtUnlock(u->lk);
-		return 0;
-	}
-	vtUnlock(u->lk);
-	return 1;
-}
-
-uvlong
-sourceGetSize(Source *r)
-{
-	uvlong size;
-
-	vtLock(r->lk);
-	size = r->size;
-	vtUnlock(r->lk);
-
-	return size;
-}
-
-
-int
-sourceSetSize(Source *r, uvlong size)
-{
-	Lump *u;
-	VtEntry dir;
-	int depth;
-
-	if(r->readOnly) {
-		vtSetError(EReadOnly);
-		return 0;
-	}
-
-	if(size > VtMaxFileSize || size > ((uvlong)MaxBlock)*r->dsize) {
-		vtSetError(ETooBig);
-		return 0;
-	}
-
-	vtLock(r->lk);
-	depth = sizeToDepth(size, r->psize, r->dsize);
-	if(size < r->size) {
-		vtUnlock(r->lk);
-		return 1;
-	}
-	if(depth > r->depth) {
-		vtSetError(EBadDir);
-		vtUnlock(r->lk);
-		return 0;
-	}
-	
-	u = r->lump;
-	vtLock(u->lk);
-	vtEntryUnpack(&dir, u->data, r->entry);
-	dir.size = size;
-	vtEntryPack(&dir, u->data, r->entry);
-	vtUnlock(u->lk);
-	r->size = size;
-	vtUnlock(r->lk);
-	return 1;
-}
-
-int
-sourceSetDirSize(Source *r, ulong ds)
-{
-	uvlong size;
-
-	size = (uvlong)r->dsize*(ds/r->epb);
-	size += VtEntrySize*(ds%r->epb);
-	return sourceSetSize(r, size);
-}
-
-ulong
-sourceGetDirSize(Source *r)
-{
-	ulong ds;
-	uvlong size;
-
-	size = sourceGetSize(r);
-	ds = r->epb*(size/r->dsize);
-	ds += (size%r->dsize)/VtEntrySize;
-	return ds;
-}
-
-ulong
-sourceGetNumBlocks(Source *r)
-{
-	return (sourceGetSize(r)+r->dsize-1)/r->dsize;
-}
-
-Lump *
-sourceWalk(Source *r, ulong block, int readOnly, int *off)
-{
-	int depth;
-	int i, np;
-	Lump *u, *v;
-	int elem[VtPointerDepth+1];
-	ulong b;
-
-	if(r->readOnly && !readOnly) {
-		vtSetError(EReadOnly);
-		return nil;
-	}
-
-	vtLock(r->lk);
-	np = r->psize/VtScoreSize;
-	b = block;
-	for(i=0; i<r->depth; i++) {
-		elem[i] = b % np;
-		b /= np;
-	}
-	if(b != 0) {
-		vtUnlock(r->lk);
-		vtSetError(EBadOffset);
-		return nil;
-	}
-	elem[i] = r->entry;
-	u = lumpIncRef(r->lump);
-	depth = r->depth;
-	*off = elem[0];
-	vtUnlock(r->lk);
-
-	for(i=depth; i>0; i--) {
-		v = lumpWalk(u, elem[i], VtPointerType0+i-1, r->psize, readOnly, 0);
-		lumpDecRef(u, 0);
-		if(v == nil)
-			return nil;
-		u = v;
-	}
-
-	return u;
-}
-
-Lump *
-sourceGetLump(Source *r, ulong block, int readOnly, int lock)
-{
-	int type, off;
-	Lump *u, *v;
-
-	if(r->readOnly && !readOnly) {
-		vtSetError(EReadOnly);
-		return nil;
-	}
-	if(block == NilBlock) {
-		vtSetError(ENilBlock);
-		return nil;
-	}
-if(0)fprint(2, "%s: sourceGetLump: %V:%d %lud\n", argv0, r->lump->score, r->entry, block);
-	u = sourceWalk(r, block, readOnly, &off);
-	if(u == nil)
-		return nil;
-	if(r->dir)
-		type = VtDirType;
-	else
-		type = VtDataType;
-	v = lumpWalk(u, off, type, r->dsize, readOnly, lock);
-	lumpDecRef(u, 0);
-	return v;
-}
-
-void
-sourceFree(Source *k)
-{
-	if(k == nil)
-		return;
-	lumpDecRef(k->lump, 0);
-	vtLockFree(k->lk);
-	memset(k, ~0, sizeof(*k));
-	vtMemFree(k);
-}

+ 0 - 302
sys/src/cmd/vac/srcload.c

@@ -1,302 +0,0 @@
-#include "stdinc.h"
-#include <bio.h>
-#include "vac.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-int num = 1000;
-int length = 20*1024;
-int block= 1024;
-int bush = 4;
-int iter = 10000;
-Biobuf *bout;
-int maxdepth;
-
-Source *mkroot(Cache*);
-void new(Source*, int trace, int);
-int delete(Source*);
-void dump(Source*, int indent, ulong nentry);
-void dumpone(Source *s);
-int count(Source *s, int);
-void stats(Source *s);
-
-void
-main(int argc, char *argv[])
-{
-	int i;
-	Cache *c;
-	char *host = nil;
-	VtSession *z;
-	int csize = 10000;
-	Source *r;
-	ulong t;
-
-	t = time(0);
-	fprint(1, "time = %lud\n", t);
-
-	srand(t);
-
-	ARGBEGIN{
-	case 'i':
-		iter = atoi(ARGF());
-		break;
-	case 'n':
-		num = atoi(ARGF());
-		break;
-	case 'l':
-		length = atoi(ARGF());
-		break;
-	case 'b':	
-		block = atoi(ARGF());
-		break;
-	case 'h':
-		host = ARGF();
-		break;
-	case 'u':
-		bush = atoi(ARGF());
-		break;
-	case 'c':
-		csize = atoi(ARGF());
-		break;
-	}ARGEND;
-
-	vtAttach();
-
-	bout = vtMemAllocZ(sizeof(Biobuf));
-	Binit(bout, 1, OWRITE);
-
-	fmtinstall('V', vtScoreFmt);
-	fmtinstall('R', vtErrFmt);
-
-	z = vtDial(host);
-	if(z == nil)
-		vtFatal("could not connect to server: %s", vtGetError());
-
-	if(!vtConnect(z, 0))
-		sysfatal("vtConnect: %r");
-
-	c = cacheAlloc(z, block, csize);
-	r = mkroot(c);
-	for(i=0; i<num; i++)
-		new(r, 0, 0);
-
-	for(i=0; i<iter; i++) {
-if(i % 10000 == 0)
-stats(r);
-		new(r, 0, 0);
-		delete(r);
-	}
-
-	fprint(2, "count = %d top = %lud\n", count(r, 0), sourceGetDirSize(r));
-//	cacheCheck(c);
-fprint(2, "deleting\n");
-	for(i=0; i<num; i++)
-		delete(r);
-
-//	dump(r, 0, 0);
-	
-	lumpDecRef(r->lump, 0);
-	sourceRemove(r);
-	cacheCheck(c);
-
-	vtClose(z);
-	vtDetach();
-
-	exits(0);
-}
-
-
-Source *
-mkroot(Cache *c)
-{
-	Lump *u;
-	VtEntry *dir;
-	Source *r;
-
-	u = cacheAllocLump(c, VtDirType, cacheGetBlockSize(c), 1);
-	dir = (VtEntry*)u->data;
-	vtPutUint16(dir->psize, cacheGetBlockSize(c));
-	vtPutUint16(dir->dsize, cacheGetBlockSize(c));
-	dir->flag = VtEntryActive|VtEntryDir;
-	memmove(dir->score, vtZeroScore, VtScoreSize);
-	
-	r = sourceAlloc(c, u, 0, 0);
-	vtUnlock(u->lk);
-	if(r == nil)
-		sysfatal("could not create root source: %R");
-	return r;
-}
-
-void
-new(Source *s, int trace, int depth)
-{
-	int i, n;
-	Source *ss;
-	
-	if(depth > maxdepth)
-		maxdepth = depth;
-
-	n = sourceGetDirSize(s);
-	for(i=0; i<n; i++) {
-		ss = sourceOpen(s, nrand(n), 0);
-		if(ss == nil)
-			continue;
-		if(ss->dir && frand() < 1./bush) {
-			if(trace) {
-				int j;
-				for(j=0; j<trace; j++)
-					Bprint(bout, " ");
-				Bprint(bout, "decend %d\n", i);
-			}
-			new(ss, trace?trace+1:0, depth+1);
-			sourceFree(ss);
-			return;
-		}
-		sourceFree(ss);
-	}
-	ss = sourceCreate(s, s->psize, s->dsize, 1+frand()>.5, 0);
-	if(ss == nil)
-		fprint(2, "could not create directory: %R\n");
-	if(trace) {
-		int j;
-		for(j=1; j<trace; j++)
-			Bprint(bout, " ");
-		Bprint(bout, "create %d %V\n", ss->entry, ss->lump->score);
-	}
-	sourceFree(ss);
-}
-
-int
-delete(Source *s)
-{
-	int i, n;
-	Source *ss;
-	
-	assert(s->dir);
-
-	n = sourceGetDirSize(s);
-	/* check if empty */
-	for(i=0; i<n; i++) {
-		ss = sourceOpen(s, i, 1);
-		if(ss != nil) {
-			sourceFree(ss);
-			break;
-		}
-	}
-	if(i == n)
-		return 0;
-		
-	for(;;) {
-		ss = sourceOpen(s, nrand(n), 0);
-		if(ss == nil)
-			continue;
-		if(ss->dir && delete(ss)) {
-			sourceFree(ss);
-			return 1;
-		}
-		if(1)
-			break;
-		sourceFree(ss);
-	}
-
-
-	sourceRemove(ss);
-	return 1;
-}
-
-void
-dumpone(Source *s)
-{
-	ulong i, n;
-	Source *ss;
-
-	Bprint(bout, "gen %4lud depth %d %V", s->gen, s->depth, s->lump->score);
-	if(!s->dir) {
-		Bprint(bout, " data size: %llud\n", s->size);
-		return;
-	}
-	n = sourceGetDirSize(s);
-	Bprint(bout, " dir size: %lud\n", n);
-	for(i=0; i<n; i++) {
-		ss = sourceOpen(s, i, 1);
-		if(ss == nil) {
-fprint(2, "%lud: %R\n", i);
-			continue;
-		}
-		Bprint(bout, "\t%lud %d %llud %V\n", i, ss->dir, ss->size, ss->lump->score);
-		sourceFree(ss);
-	}
-	return;
-}
-
-
-void
-dump(Source *s, int ident, ulong entry)
-{
-	ulong i, n;
-	Source *ss;
-
-	for(i=0; i<ident; i++)
-		Bprint(bout, " ");
-	Bprint(bout, "%4lud: gen %4lud depth %d", entry, s->gen, s->depth);
-	if(!s->dir) {
-		Bprint(bout, " data size: %llud\n", s->size);
-		return;
-	}
-	n = sourceGetDirSize(s);
-	Bprint(bout, " dir size: %lud\n", n);
-	for(i=0; i<n; i++) {
-		ss = sourceOpen(s, i, 1);
-		if(ss == nil)
-			continue;
-		dump(ss, ident+1, i);
-		sourceFree(ss);
-	}
-	return;
-}
-
-int
-count(Source *s, int rec)
-{
-	ulong i, n;
-	int c;
-	Source *ss;
-
-	if(!s->dir)
-		return 0;
-	n = sourceGetDirSize(s);
-	c = 0;
-	for(i=0; i<n; i++) {
-		ss = sourceOpen(s, i, 1);
-		if(ss == nil)
-			continue;
-		if(rec)
-			c += count(ss, rec);
-		c++;
-		sourceFree(ss);
-	}
-	return c;
-}
-
-void
-stats(Source *s)
-{
-	int n, i, c, cc, max;
-	Source *ss;
-
-	cc = 0;
-	max = 0;
-	n = sourceGetDirSize(s);
-	for(i=0; i<n; i++) {
-		ss = sourceOpen(s, i, 1);
-		if(ss == nil)
-			continue;
-		cc++;
-		c = count(ss, 1);
-		if(c > max)
-			max = c;
-		sourceFree(ss);
-	}
-fprint(2, "count = %d top = %d depth=%d maxcount %d\n", cc, n, maxdepth, max);
-}

+ 3 - 6
sys/src/cmd/vac/stdinc.h

@@ -1,8 +1,5 @@
 #include <u.h>
 #include <u.h>
 #include <libc.h>
 #include <libc.h>
-
-#include "oventi.h"
-
-typedef uvlong	u64int;
-typedef	uchar	u8int;
-typedef ushort	u16int;
+#include <thread.h>
+#include <venti.h>
+#include <libsec.h>

+ 284 - 0
sys/src/cmd/vac/unvac.c

@@ -0,0 +1,284 @@
+#include "stdinc.h"
+#include <fcall.h>	/* dirmodefmt */
+#include "vac.h"
+
+#pragma varargck type "t" ulong
+
+VacFs *fs;
+int tostdout;
+int nwant;
+char **want;
+int *found;
+int chatty;
+VtConn *conn;
+int errors;
+int settimes;
+int table;
+
+int mtimefmt(Fmt*);
+void unvac(VacFile*, char*, VacDir*);
+
+void
+usage(void)
+{
+	fprint(2, "usage: unvac [-TVctv] [-h host] file.vac [file ...]\n");
+	threadexitsall("usage");
+}
+
+void
+threadmain(int argc, char *argv[])
+{
+	int i;
+	char *host;
+	VacFile *f;
+
+	fmtinstall('H', encodefmt);
+	fmtinstall('V', vtscorefmt);
+	fmtinstall('F', vtfcallfmt);
+	fmtinstall('t', mtimefmt);
+	fmtinstall('M', dirmodefmt);
+	
+	host = nil;
+	ARGBEGIN{
+	case 'T':
+		settimes = 1;
+		break;
+	case 'V':
+		chattyventi = 1;
+		break;
+	case 'c':
+		tostdout++;
+		break;
+	case 'h':
+		host = EARGF(usage());
+		break;
+	case 't':
+		table++;
+		break;
+	case 'v':
+		chatty++;
+		break;
+	default:
+		usage();
+	}ARGEND
+
+	if(argc < 1)
+		usage();
+
+	conn = vtdial(host);
+	if(conn == nil)
+		sysfatal("could not connect to server: %r");
+
+	if(vtconnect(conn) < 0)
+		sysfatal("vtconnect: %r");
+
+	fs = vacfsopen(conn, argv[0], VtOREAD, 128);
+	if(fs == nil)
+		sysfatal("vacfsopen: %r");
+
+	nwant = argc-1;
+	want = argv+1;
+	found = vtmallocz(nwant*sizeof found[0]);
+
+	if((f = vacfsgetroot(fs)) == nil)
+		sysfatal("vacfsgetroot: %r");
+	
+	unvac(f, nil, nil);
+	for(i=0; i<nwant; i++){
+		if(want[i] && !found[i]){
+			fprint(2, "warning: didn't find %s\n", want[i]);
+			errors++;
+		}
+	}
+	if(errors)
+		threadexitsall("errors");
+	threadexitsall(0);
+}
+
+int
+writen(int fd, char *buf, int n)
+{
+	int m;
+	int oldn;
+	
+	oldn = n;
+	while(n > 0){
+		m = write(fd, buf, n);
+		if(m <= 0)
+			return -1;
+		buf += m;
+		n -= m;
+	}
+	return oldn;
+}
+
+int
+wantfile(char *name)
+{
+	int i, namelen, n;
+	
+	if(nwant == 0)
+		return 1;
+
+	namelen = strlen(name);
+	for(i=0; i<nwant; i++){
+		if(want[i] == nil)
+			continue;
+		n = strlen(want[i]);
+		if(n < namelen && name[n] == '/' && memcmp(name, want[i], n) == 0)
+			return 1;
+		if(namelen < n && want[i][namelen] == '/' && memcmp(want[i], name, n) == 0)
+			return 1;
+		if(n == namelen && memcmp(name, want[i], n) == 0){
+			found[i] = 1;
+			return 1;
+		}
+	}
+	return 0;
+}
+
+void
+unvac(VacFile *f, char *name, VacDir *vdir)
+{
+	static char buf[65536];
+	int fd, n;
+	ulong mode, mode9;
+	char *newname;
+	char *what;
+	vlong off;
+	Dir d, *dp;
+	VacDirEnum *vde;
+	VacDir newvdir;
+	VacFile *newf;
+
+	if(vdir)
+		mode = vdir->mode;
+	else
+		mode = vacfilegetmode(f);
+
+	if(vdir){
+		if(table){
+			if(chatty){
+				mode9 = vdir->mode&0777;
+				if(mode&ModeDir)
+					mode9 |= DMDIR;
+				if(mode&ModeAppend)
+					mode9 |= DMAPPEND;
+				if(mode&ModeExclusive)
+					mode9 |= DMEXCL;
+				print("%M %-10s %-10s %11lld %t %s\n",
+					mode9, vdir->uid, vdir->gid, vdir->size,
+					vdir->mtime, name);
+			}else
+				print("%s%s\n", name, (mode&ModeDir) ? "/" : "");
+		}
+		else if(chatty)
+			fprint(2, "%s%s\n", name, (mode&ModeDir) ? "/" : "");
+	}
+
+	if(mode&(ModeDevice|ModeLink|ModeNamedPipe|ModeExclusive)){
+		if(table)
+			return;
+		if(mode&ModeDevice)
+			what = "device";
+		else if(mode&ModeLink)
+			what = "link";
+		else if(mode&ModeNamedPipe)
+			what = "named pipe";
+		else if(mode&ModeExclusive)
+			what = "lock";
+		else
+			what = "unknown type of file";
+		fprint(2, "warning: ignoring %s %s\n", what, name);
+		return;
+	}
+	
+	if(mode&ModeDir){
+		if((vde = vdeopen(f)) == nil){
+			fprint(2, "vdeopen %s: %r", name);
+			errors++;
+			return;
+		}
+		if(!table && !tostdout && vdir){
+			// create directory
+			if((dp = dirstat(name)) == nil){
+				if((fd = create(name, OREAD, DMDIR|(mode&0777))) < 0){
+					fprint(2, "mkdir %s: %r\n", name);
+					vdeclose(vde);
+				}
+				close(fd);
+			}else{
+				if(!(dp->mode&DMDIR)){
+					fprint(2, "%s already exists and is not a directory\n", name);
+					errors++;
+					free(dp);
+					vdeclose(vde);
+					return;
+				}
+				free(dp);
+			}
+		}
+		while(vderead(vde, &newvdir) > 0){
+			if(name == nil)
+				newname = newvdir.elem;
+			else
+				newname = smprint("%s/%s", name, newvdir.elem);
+			if(wantfile(newname)){
+				if((newf = vacfilewalk(f, newvdir.elem)) == nil){
+					fprint(2, "walk %s: %r\n", name);
+					errors++;
+				}else if(newf == f){
+					fprint(2, "walk loop: %s\n", newname);
+					vacfiledecref(newf);
+				}else{
+					unvac(newf, newname, &newvdir);
+					vacfiledecref(newf);
+				}
+			}
+			if(newname != newvdir.elem)
+				free(newname);
+			vdcleanup(&newvdir);
+		}
+		vdeclose(vde);
+	}else{
+		if(!table){
+			if(tostdout)
+				fd = dup(1, -1);
+			else if((fd = create(name, OWRITE, mode&0777)) < 0){
+				fprint(2, "create %s: %r\n", name);
+				errors++;
+				return;
+			}
+			off = 0;
+			while((n = vacfileread(f, buf, sizeof buf, off)) > 0){
+				if(writen(fd, buf, n) != n){
+					fprint(2, "write %s: %r\n", name);
+					errors++;
+					close(fd);
+					remove(name);
+					return;
+				}
+				off += n;
+			}
+			close(fd);
+		}
+	}
+	if(vdir && settimes && !tostdout){
+		nulldir(&d);
+		d.mtime = vdir->mtime;
+		if(dirwstat(name, &d) < 0)
+			fprint(2, "warning: setting mtime on %s: %r", name);
+	}
+}
+
+int
+mtimefmt(Fmt *f)
+{
+	Tm *tm;
+	
+	tm = localtime(va_arg(f->args, ulong));
+	fmtprint(f, "%04d-%02d-%02d %02d:%02d",
+		tm->year+1900, tm->mon+1, tm->mday,
+		tm->hour, tm->min);
+	return 0;
+}

+ 0 - 71
sys/src/cmd/vac/util.c

@@ -1,71 +0,0 @@
-#include "stdinc.h"
-#include "vac.h"
-#include "dat.h"
-#include "fns.h"
-
-int
-vtGetUint16(uchar *p)
-{
-	return (p[0]<<8)|p[1];
-}
-
-ulong
-vtGetUint32(uchar *p)
-{
-	return (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3];
-}
-
-uvlong
-vtGetUint48(uchar *p)
-{
-	return ((uvlong)p[0]<<40)|((uvlong)p[1]<<32)|
-		(p[2]<<24)|(p[3]<<16)|(p[4]<<8)|p[5];
-}
-
-uvlong
-vtGetUint64(uchar *p)
-{
-	return ((uvlong)p[0]<<56)|((uvlong)p[1]<<48)|((uvlong)p[2]<<40)|
-		((uvlong)p[3]<<32)|(p[4]<<24)|(p[5]<<16)|(p[6]<<8)|p[7];
-}
-
-
-void
-vtPutUint16(uchar *p, int x)
-{
-	p[0] = x>>8;
-	p[1] = x;
-}
-
-void
-vtPutUint32(uchar *p, ulong x)
-{
-	p[0] = x>>24;
-	p[1] = x>>16;
-	p[2] = x>>8;
-	p[3] = x;
-}
-
-void
-vtPutUint48(uchar *p, uvlong x)
-{
-	p[0] = x>>40;
-	p[1] = x>>32;
-	p[2] = x>>24;
-	p[3] = x>>16;
-	p[4] = x>>8;
-	p[5] = x;
-}
-
-void
-vtPutUint64(uchar *p, uvlong x)
-{
-	p[0] = x>>56;
-	p[1] = x>>48;
-	p[2] = x>>40;
-	p[3] = x>>32;
-	p[4] = x>>24;
-	p[5] = x>>16;
-	p[6] = x>>8;
-	p[7] = x;
-}

File diff suppressed because it is too large
+ 457 - 1087
sys/src/cmd/vac/vac.c


+ 69 - 56
sys/src/cmd/vac/vac.h

@@ -1,15 +1,16 @@
-typedef struct VacFS VacFS;
-#pragma incomplete VacFS
+typedef struct VacFs VacFs;
 typedef struct VacDir VacDir;
 typedef struct VacDir VacDir;
 typedef struct VacFile VacFile;
 typedef struct VacFile VacFile;
-#pragma incomplete VacFile
 typedef struct VacDirEnum VacDirEnum;
 typedef struct VacDirEnum VacDirEnum;
+
+#pragma incomplete VacFile
 #pragma incomplete VacDirEnum
 #pragma incomplete VacDirEnum
 
 
 /*
 /*
  * Mode bits
  * Mode bits
  */
  */
-enum {
+enum
+{
 	ModeOtherExec = (1<<0),		
 	ModeOtherExec = (1<<0),		
 	ModeOtherWrite = (1<<1),
 	ModeOtherWrite = (1<<1),
 	ModeOtherRead = (1<<2),
 	ModeOtherRead = (1<<2),
@@ -31,24 +32,29 @@ enum {
 	ModeArchive = (1<<18),		/* MS-DOS */
 	ModeArchive = (1<<18),		/* MS-DOS */
 	ModeTemporary = (1<<19),	/* MS-DOS */
 	ModeTemporary = (1<<19),	/* MS-DOS */
 	ModeSnapshot = (1<<20),		/* read only snapshot */
 	ModeSnapshot = (1<<20),		/* read only snapshot */
+	ModeDevice = (1<<21),		/* Unix device */
+	ModeNamedPipe = (1<<22)	/* Unix named pipe */
 };
 };
 
 
-enum {
+enum
+{
 	MetaMagic = 0x5656fc79,
 	MetaMagic = 0x5656fc79,
 	MetaHeaderSize = 12,
 	MetaHeaderSize = 12,
 	MetaIndexSize = 4,
 	MetaIndexSize = 4,
 	IndexEntrySize = 8,
 	IndexEntrySize = 8,
-	DirMagic = 0x1c4d9072,
+	DirMagic = 0x1c4d9072
 };
 };
 
 
-enum {
+enum
+{
 	DirPlan9Entry = 1,	/* not valid in version >= 9 */
 	DirPlan9Entry = 1,	/* not valid in version >= 9 */
 	DirNTEntry,		/* not valid in version >= 9 */
 	DirNTEntry,		/* not valid in version >= 9 */
 	DirQidSpaceEntry,
 	DirQidSpaceEntry,
-	DirGenEntry,		/* not valid in version >= 9 */
+	DirGenEntry		/* not valid in version >= 9 */
 };
 };
 
 
-struct VacDir {
+struct VacDir
+{
 	char *elem;		/* path element */
 	char *elem;		/* path element */
 	ulong entry;		/* entry in directory for data */
 	ulong entry;		/* entry in directory for data */
 	ulong gen;		/* generation of data entry */
 	ulong gen;		/* generation of data entry */
@@ -72,58 +78,65 @@ struct VacDir {
 	ulong p9version;
 	ulong p9version;
 
 
 	/* sub space of qid */
 	/* sub space of qid */
-	int qidSpace;
-	uvlong qidOffset;	/* qid offset */
-	uvlong qidMax;		/* qid maximum */
+	int qidspace;
+	uvlong qidoffset;	/* qid offset */
+	uvlong qidmax;		/* qid maximum */
 };
 };
 
 
-VacFS *vfsOpen(VtSession *z, char *file, int readOnly, long ncache);
-VacFS *vfsCreate(VtSession *z, int bsize, long ncache);
-int vfsGetBlockSize(VacFS*);
-int vfsIsReadOnly(VacFS*);
-VacFile *vfsGetRoot(VacFS*);
+struct VacFs
+{
+	char	name[128];
+	uchar	score[VtScoreSize];
+	VacFile	*root;
+	VtConn	*z;
+	int		mode;
+	int		bsize;
+	uvlong	qid;
+	VtCache	*cache;
+};
 
 
-long vfsGetCacheSize(VacFS*);
-int vfsSetCacheSize(VacFS*, long);
-int vfsSnapshot(VacFS*, char *src, char *dst);
-int vfsSync(VacFS*);
-int vfsClose(VacFS*);
-int vfsGetScore(VacFS*, uchar score[VtScoreSize]);
+VacFs	*vacfsopen(VtConn *z, char *file, int mode, int ncache);
+VacFs	*vacfsopenscore(VtConn *z, u8int *score, int mode, int ncache);
+VacFs	*vacfscreate(VtConn *z, int bsize, int ncache);
+void		vacfsclose(VacFs *fs);
+int		vacfssync(VacFs *fs);
+int		vacfssnapshot(VacFs *fs, char *src, char *dst);
+int		vacfsgetscore(VacFs *fs, u8int *score);
+int		vacfsgetmaxqid(VacFs*, uvlong*);
+void		vacfsjumpqid(VacFs*, uvlong);
 
 
-/* 
- * other ideas
- *
- * VacFS *vfsSnapshot(VacFS*, char *src);
- * int vfsGraft(VacFS*, char *name, VacFS*);
- */
+VacFile *vacfsgetroot(VacFs *fs);
+VacFile	*vacfileopen(VacFs *fs, char *path);
+VacFile	*vacfilecreate(VacFile *file, char *elem, ulong perm);
+VacFile	*vacfilewalk(VacFile *file, char *elem);
+int		vacfileremove(VacFile *file);
+int		vacfileread(VacFile *file, void *buf, int n, vlong offset);
+int		vacfileblockscore(VacFile *file, u32int, u8int*);
+int		vacfilewrite(VacFile *file, void *buf, int n, vlong offset);
+uvlong	vacfilegetid(VacFile *file);
+ulong	vacfilegetmcount(VacFile *file);
+int		vacfileisdir(VacFile *file);
+int		vacfileisroot(VacFile *file);
+ulong	vacfilegetmode(VacFile *file);
+int		vacfilegetsize(VacFile *file, uvlong *size);
+int		vacfilegetdir(VacFile *file, VacDir *dir);
+int		vacfilesetdir(VacFile *file, VacDir *dir);
+VacFile	*vacfilegetparent(VacFile *file);
+int		vacfileflush(VacFile*, int);
+VacFile	*vacfileincref(VacFile*);
+int		vacfiledecref(VacFile*);
+int		vacfilesetsize(VacFile *f, uvlong size);
 
 
-VacFile *vfOpen(VacFS*, char *path);
-VacFile *vfCreate(VacFile*, char *elem, ulong perm, char *user);
-VacFile *vfWalk(VacFile*, char *elem);
-int vfRemove(VacFile*, char*);
-int vfRead(VacFile*, void *, int n, vlong offset);
-int vfWrite(VacFile*, void *, int n, vlong offset, char *user);
-int vfReadPacket(VacFile*, Packet**, vlong offset);
-int vfWritePacket(VacFile*, Packet*, vlong offset, char *user);
-uvlong vfGetId(VacFile*);
-ulong vfGetMcount(VacFile*);
-int vfIsDir(VacFile*);
-int vfGetBlockScore(VacFile*, ulong bn, uchar score[VtScoreSize]);
-int vfGetSize(VacFile*, uvlong *size);
-int vfGetDir(VacFile*, VacDir*);
-int vfSetDir(VacFile*, VacDir*);
-int vfGetVtEntry(VacFile*, VtEntry*);
-VacFile *vfGetParent(VacFile*);
-int vfSync(VacFile*);
-VacFile *vfIncRef(VacFile*);
-void vfDecRef(VacFile*);
-VacDirEnum *vfDirEnum(VacFile*);
-int vfIsRoot(VacFile *vf);
+int		vacfilegetentries(VacFile *f, VtEntry *e, VtEntry *me);
+int		vacfilesetentries(VacFile *f, VtEntry *e, VtEntry *me);
 
 
-void	vdCleanup(VacDir *dir);
-void	vdCopy(VacDir *dst, VacDir *src);
+void		vdcleanup(VacDir *dir);
+void		vdcopy(VacDir *dst, VacDir *src);
+int		vacfilesetqidspace(VacFile*, u64int, u64int);
+uvlong	vacfilegetqidoffset(VacFile*);
 
 
-VacDirEnum *vdeOpen(VacFS*, char *path);
-int vdeRead(VacDirEnum*, VacDir *, int n);
-void vdeFree(VacDirEnum*);
+VacDirEnum	*vdeopen(VacFile*);
+int			vderead(VacDirEnum*, VacDir *);
+void			vdeclose(VacDirEnum*);
+int	vdeunread(VacDirEnum*);
 
 

+ 256 - 330
sys/src/cmd/vac/vacfs.c

@@ -1,19 +1,17 @@
 #include "stdinc.h"
 #include "stdinc.h"
-#include <auth.h>
 #include <fcall.h>
 #include <fcall.h>
 #include "vac.h"
 #include "vac.h"
 
 
-typedef struct Fid Fid;
-typedef struct DirBuf DirBuf;
+#define convM2Su(a, b, c, d) convM2S(a, b, c)
+#define convS2Mu(a, b, c, d) convS2M(a, b, c)
+#define convM2Du(a, b, c, d) convM2D(a, b, c)
+#define convD2Mu(a, b, c, d) convD2M(a, b, c)
 
 
-enum
-{
-	OPERM	= 0x3,		/* mask of all permission types in open mode */
-};
+typedef struct Fid Fid;
 
 
 enum
 enum
 {
 {
-	DirBufSize = 20,
+	OPERM	= 0x3		/* mask of all permission types in open mode */
 };
 };
 
 
 struct Fid
 struct Fid
@@ -24,18 +22,8 @@ struct Fid
 	char *user;
 	char *user;
 	Qid qid;
 	Qid qid;
 	VacFile *file;
 	VacFile *file;
-
-	DirBuf *db;
-
-	Fid	*next;
-};
-
-struct DirBuf
-{
 	VacDirEnum *vde;
 	VacDirEnum *vde;
-	VacDir buf[DirBufSize];
-	int i, n;
-	int eof;
+	Fid	*next;
 };
 };
 
 
 enum
 enum
@@ -45,36 +33,37 @@ enum
 	Pread = 	4,
 	Pread = 	4,
 	Pother = 	1,
 	Pother = 	1,
 	Pgroup = 	8,
 	Pgroup = 	8,
-	Powner =	64,
+	Powner =	64
 };
 };
 
 
 Fid	*fids;
 Fid	*fids;
 uchar	*data;
 uchar	*data;
 int	mfd[2];
 int	mfd[2];
+int	srvfd = -1;
 char	*user;
 char	*user;
 uchar	mdata[8192+IOHDRSZ];
 uchar	mdata[8192+IOHDRSZ];
 int messagesize = sizeof mdata;
 int messagesize = sizeof mdata;
 Fcall	rhdr;
 Fcall	rhdr;
 Fcall	thdr;
 Fcall	thdr;
-VacFS	*fs;
-VtSession *session;
+VacFs	*fs;
+VtConn  *conn;
 int	noperm;
 int	noperm;
+int	dotu;
+char *defmnt;
 
 
 Fid *	newfid(int);
 Fid *	newfid(int);
 void	error(char*);
 void	error(char*);
 void	io(void);
 void	io(void);
-void	shutdown(void);
+void	vacshutdown(void);
 void	usage(void);
 void	usage(void);
 int	perm(Fid*, int);
 int	perm(Fid*, int);
 int	permf(VacFile*, char*, int);
 int	permf(VacFile*, char*, int);
 ulong	getl(void *p);
 ulong	getl(void *p);
 void	init(char*, char*, long, int);
 void	init(char*, char*, long, int);
-DirBuf	*dirBufAlloc(VacFile*);
-VacDir	*dirBufGet(DirBuf*);
-int	dirBufUnget(DirBuf*);
-void	dirBufFree(DirBuf*);
 int	vacdirread(Fid *f, char *p, long off, long cnt);
 int	vacdirread(Fid *f, char *p, long off, long cnt);
-int	vdStat(VacDir *vd, uchar *p, int np);
+int	vacstat(VacFile *parent, VacDir *vd, uchar *p, int np);
+void 	srv(void* a);
+
 
 
 char	*rflush(Fid*), *rversion(Fid*),
 char	*rflush(Fid*), *rversion(Fid*),
 	*rauth(Fid*), *rattach(Fid*), *rwalk(Fid*),
 	*rauth(Fid*), *rattach(Fid*), *rwalk(Fid*),
@@ -82,21 +71,25 @@ char	*rflush(Fid*), *rversion(Fid*),
 	*rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),
 	*rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),
 	*rremove(Fid*), *rstat(Fid*), *rwstat(Fid*);
 	*rremove(Fid*), *rstat(Fid*), *rwstat(Fid*);
 
 
-char 	*(*fcalls[])(Fid*) = {
-	[Tflush]	rflush,
-	[Tversion]	rversion,
-	[Tattach]	rattach,
-	[Tauth]		rauth,
-	[Twalk]		rwalk,
-	[Topen]		ropen,
-	[Tcreate]	rcreate,
-	[Tread]		rread,
-	[Twrite]	rwrite,
-	[Tclunk]	rclunk,
-	[Tremove]	rremove,
-	[Tstat]		rstat,
-	[Twstat]	rwstat,
-};
+char 	*(*fcalls[Tmax])(Fid*);
+
+void
+initfcalls(void)
+{
+	fcalls[Tflush]=	rflush;
+	fcalls[Tversion]=	rversion;
+	fcalls[Tattach]=	rattach;
+	fcalls[Tauth]=		rauth;
+	fcalls[Twalk]=		rwalk;
+	fcalls[Topen]=		ropen;
+	fcalls[Tcreate]=	rcreate;
+	fcalls[Tread]=		rread;
+	fcalls[Twrite]=	rwrite;
+	fcalls[Tclunk]=	rclunk;
+	fcalls[Tremove]=	rremove;
+	fcalls[Tstat]=		rstat;
+	fcalls[Twstat]=	rwstat;
+}
 
 
 char	Eperm[] =	"permission denied";
 char	Eperm[] =	"permission denied";
 char	Enotdir[] =	"not a directory";
 char	Enotdir[] =	"not a directory";
@@ -124,26 +117,29 @@ notifyf(void *a, char *s)
 }
 }
 
 
 void
 void
-main(int argc, char *argv[])
+threadmain(int argc, char *argv[])
 {
 {
-	char *defmnt, *defsrv, *srv;
-	int p[2];
-	char buf[12];
-	int fd;
-	int stdio = 0;
+	char *defsrv, *srvname;
+	int p[2], fd;
+	int stdio;
 	char *host = nil;
 	char *host = nil;
-	long ncache = 1000;
-	int readOnly = 1;
-
-	defmnt = "/n/vac";
-	defsrv = "vacfs";
+	long ncache;
+
+	stdio = 0;
+	ncache = 256;
+	fmtinstall('H', encodefmt);
+	fmtinstall('V', vtscorefmt);
+	fmtinstall('F', vtfcallfmt);
+	
+	defmnt = nil;
+	defsrv = nil;
 	ARGBEGIN{
 	ARGBEGIN{
 	case 'd':
 	case 'd':
 		fmtinstall('F', fcallfmt);
 		fmtinstall('F', fcallfmt);
 		dflag = 1;
 		dflag = 1;
 		break;
 		break;
 	case 'c':
 	case 'c':
-		ncache = atoi(ARGF());
+		ncache = atoi(EARGF(usage()));
 		break;
 		break;
 	case 'i':
 	case 'i':
 		defmnt = nil;
 		defmnt = nil;
@@ -152,19 +148,22 @@ main(int argc, char *argv[])
 		mfd[1] = 1;
 		mfd[1] = 1;
 		break;
 		break;
 	case 'h':
 	case 'h':
-		host = ARGF();
+		host = EARGF(usage());
 		break;
 		break;
 	case 'S':
 	case 'S':
-		defsrv = ARGF();
-		/*FALLTHROUGH*/
+		defsrv = EARGF(usage());
+		break;
 	case 's':
 	case 's':
-		defmnt = nil;
+		defsrv = "vacfs";
+		break;
+	case 'm':
+		defmnt = EARGF(usage());
 		break;
 		break;
 	case 'p':
 	case 'p':
 		noperm = 1;
 		noperm = 1;
 		break;
 		break;
-	case 'm':
-		defmnt = ARGF();
+	case 'V':
+		chattyventi = 1;
 		break;
 		break;
 	default:
 	default:
 		usage();
 		usage();
@@ -173,55 +172,69 @@ main(int argc, char *argv[])
 	if(argc != 1)
 	if(argc != 1)
 		usage();
 		usage();
 
 
-	vtAttach();
+	if(defsrv == nil && defmnt == nil && !stdio)
+		defmnt = "/n/vac";
+	if(stdio && defmnt)
+		sysfatal("cannot use -m with -i");
 
 
-	init(argv[0], host, ncache, readOnly);
+	initfcalls();
+
+	notify(notifyf);
+	user = getuser();
+
+	conn = vtdial(host);
+	if(conn == nil)
+		sysfatal("could not connect to server: %r");
+
+	if(vtconnect(conn) < 0)
+		sysfatal("vtconnect: %r");
+
+	fs = vacfsopen(conn, argv[0], VtOREAD, ncache);
+	if(fs == nil)
+		sysfatal("vacfsopen: %r");
 
 
-	if(pipe(p) < 0)
-		sysfatal("pipe failed: %r");
 	if(!stdio){
 	if(!stdio){
+		if(pipe(p) < 0)
+			sysfatal("pipe failed: %r");
 		mfd[0] = p[0];
 		mfd[0] = p[0];
 		mfd[1] = p[0];
 		mfd[1] = p[0];
-		if(defmnt == 0){
-			srv = smprint("/srv/%s", defsrv);
-			fd = create(srv, OWRITE, 0666);
+		srvfd = p[1];
+	}
+
+	procrfork(srv, 0, 32 * 1024, RFFDG|RFNAMEG|RFNOTEG);
+
+	if(!stdio){
+		close(p[0]);
+		if(defsrv){
+			srvname = smprint("/srv/%s", defsrv);
+			fd = create(srvname, OWRITE|ORCLOSE, 0666);
 			if(fd < 0)
 			if(fd < 0)
-				sysfatal("create of %s failed: %r", srv);
-			sprint(buf, "%d", p[1]);
-			if(write(fd, buf, strlen(buf)) < 0)
-				sysfatal("writing %s: %r", srv);
-			free(srv);
+				sysfatal("create %s: %r", srvname);
+			if(fprint(fd, "%d", srvfd) < 0)
+				sysfatal("write %s: %r", srvname);
+			free(srvname);
+		}
+		if(defmnt){
+			if(mount(srvfd, -1, defmnt, MREPL|MCREATE, "") < 0)
+				sysfatal("mount %s: %r", defmnt);
 		}
 		}
 	}
 	}
+	threadexits(0);
+}
 
 
-	switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG)){
-	case -1:
-		sysfatal("fork: %r");
-	case 0:
-		vtAttach();
-		close(p[1]);
-		io();
-		shutdown();
-		break;
-	default:
-		close(p[0]);	/* don't deadlock if child fails */
-		if(defmnt && mount(p[1], -1, defmnt, MREPL|MCREATE, "") < 0)
-			sysfatal("mount failed: %r");
-	}
-	vtDetach();
-	exits(0);
+void
+srv(void *a)
+{
+	USED(a);
+	io();
+	vacshutdown();
 }
 }
 
 
 void
 void
 usage(void)
 usage(void)
 {
 {
-	fprint(2, "usage: %s [-dips]"
-		" [-c ncache]"
-		" [-h host]"
-		" [-m mountpoint]"
-		" [-S srvname]"
-		" vacfile\n", argv0);
-	exits("usage");
+	fprint(2, "usage: %s [-sd] [-h host] [-c ncache] [-m mountpoint] vacfile\n", argv0);
+	threadexitsall("usage");
 }
 }
 
 
 char*
 char*
@@ -236,14 +249,18 @@ rversion(Fid *unused)
 			rclunk(f);
 			rclunk(f);
 
 
 	if(rhdr.msize < 256)
 	if(rhdr.msize < 256)
-		return "version: message size too small";
+		return vtstrdup("version: message size too small");
 	messagesize = rhdr.msize;
 	messagesize = rhdr.msize;
 	if(messagesize > sizeof mdata)
 	if(messagesize > sizeof mdata)
 		messagesize = sizeof mdata;
 		messagesize = sizeof mdata;
 	thdr.msize = messagesize;
 	thdr.msize = messagesize;
 	if(strncmp(rhdr.version, "9P2000", 6) != 0)
 	if(strncmp(rhdr.version, "9P2000", 6) != 0)
-		return "unrecognized 9P version";
+		return vtstrdup("unrecognized 9P version");
 	thdr.version = "9P2000";
 	thdr.version = "9P2000";
+	if(strncmp(rhdr.version, "9P2000.u", 8) == 0){
+		dotu = 1;
+		thdr.version = "9P2000.u";
+	}
 	return nil;
 	return nil;
 }
 }
 
 
@@ -258,7 +275,7 @@ char*
 rauth(Fid *f)
 rauth(Fid *f)
 {
 {
 	USED(f);
 	USED(f);
-	return "vacfs: authentication not required";
+	return vtstrdup("vacfs: authentication not required");
 }
 }
 
 
 char*
 char*
@@ -266,34 +283,27 @@ rattach(Fid *f)
 {
 {
 	/* no authentication for the momment */
 	/* no authentication for the momment */
 	VacFile *file;
 	VacFile *file;
+	char err[80];
+
+	file = vacfsgetroot(fs);
+	if(file == nil) {
+		rerrstr(err, sizeof err);
+		return vtstrdup(err);
+	}
 
 
-	file = vfsGetRoot(fs);
-	if(file == nil)
-		return vtGetError();
 	f->busy = 1;
 	f->busy = 1;
 	f->file = file;
 	f->file = file;
-	f->qid = (Qid){vfGetId(f->file), 0, QTDIR};
+	f->qid.path = vacfilegetid(f->file);
+	f->qid.vers = 0;
+	f->qid.type = QTDIR;
 	thdr.qid = f->qid;
 	thdr.qid = f->qid;
 	if(rhdr.uname[0])
 	if(rhdr.uname[0])
-		f->user = vtStrDup(rhdr.uname);
+		f->user = vtstrdup(rhdr.uname);
 	else
 	else
 		f->user = "none";
 		f->user = "none";
 	return 0;
 	return 0;
 }
 }
 
 
-VacFile*
-_vfWalk(VacFile *file, char *name)
-{
-	VacFile *n;
-
-	n = vfWalk(file, name);
-	if(n)
-		return n;
-	if(strcmp(name, "SLASH") == 0)
-		return vfWalk(file, "/");
-	return nil;
-}
-
 char*
 char*
 rwalk(Fid *f)
 rwalk(Fid *f)
 {
 {
@@ -301,23 +311,24 @@ rwalk(Fid *f)
 	Fid *nf;
 	Fid *nf;
 	int nqid, nwname;
 	int nqid, nwname;
 	Qid qid;
 	Qid qid;
+	char *err = nil;
 
 
 	if(f->busy == 0)
 	if(f->busy == 0)
 		return Enotexist;
 		return Enotexist;
 	nf = nil;
 	nf = nil;
 	if(rhdr.fid != rhdr.newfid){
 	if(rhdr.fid != rhdr.newfid){
 		if(f->open)
 		if(f->open)
-			return Eisopen;
+			return vtstrdup(Eisopen);
 		if(f->busy == 0)
 		if(f->busy == 0)
-			return Enotexist;
+			return vtstrdup(Enotexist);
 		nf = newfid(rhdr.newfid);
 		nf = newfid(rhdr.newfid);
 		if(nf->busy)
 		if(nf->busy)
-			return Eisopen;
+			return vtstrdup(Eisopen);
 		nf->busy = 1;
 		nf->busy = 1;
 		nf->open = 0;
 		nf->open = 0;
 		nf->qid = f->qid;
 		nf->qid = f->qid;
-		nf->file = vfIncRef(f->file);
-		nf->user = vtStrDup(f->user);
+		nf->file = vacfileincref(f->file);
+		nf->user = vtstrdup(f->user);
 		f = nf;
 		f = nf;
 	}
 	}
 
 
@@ -330,28 +341,28 @@ rwalk(Fid *f)
 	}
 	}
 
 
 	file = f->file;
 	file = f->file;
-	vfIncRef(file);
+	vacfileincref(file);
 	qid = f->qid;
 	qid = f->qid;
 
 
 	for(nqid = 0; nqid < nwname; nqid++){
 	for(nqid = 0; nqid < nwname; nqid++){
 		if((qid.type & QTDIR) == 0){
 		if((qid.type & QTDIR) == 0){
-			vtSetError(Enotdir);
+			err = Enotdir;
 			break;
 			break;
 		}
 		}
 		if(!permf(file, f->user, Pexec)) {
 		if(!permf(file, f->user, Pexec)) {
-			vtSetError(Eperm);
+			err = Eperm;
 			break;
 			break;
 		}
 		}
-		nfile = _vfWalk(file, rhdr.wname[nqid]);
+		nfile = vacfilewalk(file, rhdr.wname[nqid]);
 		if(nfile == nil)
 		if(nfile == nil)
 			break;
 			break;
-		vfDecRef(file);
+		vacfiledecref(file);
 		file = nfile;
 		file = nfile;
 		qid.type = QTFILE;
 		qid.type = QTFILE;
-		if(vfIsDir(file))
+		if(vacfileisdir(file))
 			qid.type = QTDIR;
 			qid.type = QTDIR;
-		qid.vers = vfGetMcount(file);
-		qid.path = vfGetId(file);
+		qid.vers = vacfilegetmcount(file);
+		qid.path = vacfilegetid(file);
 		thdr.wqid[nqid] = qid;
 		thdr.wqid[nqid] = qid;
 	}
 	}
 
 
@@ -360,18 +371,18 @@ rwalk(Fid *f)
 	if(nqid == nwname){
 	if(nqid == nwname){
 		/* success */
 		/* success */
 		f->qid = thdr.wqid[nqid-1];
 		f->qid = thdr.wqid[nqid-1];
-		vfDecRef(f->file);
+		vacfiledecref(f->file);
 		f->file = file;
 		f->file = file;
 		return 0;
 		return 0;
 	}
 	}
 
 
-	vfDecRef(file);
+	vacfiledecref(file);
 	if(nf != nil)
 	if(nf != nil)
 		rclunk(nf);
 		rclunk(nf);
 
 
 	/* only error on the first element */
 	/* only error on the first element */
 	if(nqid == 0)
 	if(nqid == 0)
-		return vtGetError();
+		return vtstrdup(err);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -382,34 +393,35 @@ ropen(Fid *f)
 	int mode, trunc;
 	int mode, trunc;
 
 
 	if(f->open)
 	if(f->open)
-		return Eisopen;
+		return vtstrdup(Eisopen);
 	if(!f->busy)
 	if(!f->busy)
-		return Enotexist;
+		return vtstrdup(Enotexist);
+
 	mode = rhdr.mode;
 	mode = rhdr.mode;
 	thdr.iounit = messagesize - IOHDRSZ;
 	thdr.iounit = messagesize - IOHDRSZ;
 	if(f->qid.type & QTDIR){
 	if(f->qid.type & QTDIR){
 		if(mode != OREAD)
 		if(mode != OREAD)
-			return Eperm;
+			return vtstrdup(Eperm);
 		if(!perm(f, Pread))
 		if(!perm(f, Pread))
-			return Eperm;
+			return vtstrdup(Eperm);
 		thdr.qid = f->qid;
 		thdr.qid = f->qid;
-		f->db = nil;
+		f->vde = nil;
 		f->open = 1;
 		f->open = 1;
 		return 0;
 		return 0;
 	}
 	}
 	if(mode & ORCLOSE)
 	if(mode & ORCLOSE)
-		return Erdonly;
+		return vtstrdup(Erdonly);
 	trunc = mode & OTRUNC;
 	trunc = mode & OTRUNC;
 	mode &= OPERM;
 	mode &= OPERM;
 	if(mode==OWRITE || mode==ORDWR || trunc)
 	if(mode==OWRITE || mode==ORDWR || trunc)
 		if(!perm(f, Pwrite))
 		if(!perm(f, Pwrite))
-			return Eperm;
+			return vtstrdup(Eperm);
 	if(mode==OREAD || mode==ORDWR)
 	if(mode==OREAD || mode==ORDWR)
 		if(!perm(f, Pread))
 		if(!perm(f, Pread))
-			return Eperm;
+			return vtstrdup(Eperm);
 	if(mode==OEXEC)
 	if(mode==OEXEC)
 		if(!perm(f, Pexec))
 		if(!perm(f, Pexec))
-			return Eperm;
+			return vtstrdup(Eperm);
 	thdr.qid = f->qid;
 	thdr.qid = f->qid;
 	thdr.iounit = messagesize - IOHDRSZ;
 	thdr.iounit = messagesize - IOHDRSZ;
 	f->open = 1;
 	f->open = 1;
@@ -423,45 +435,50 @@ rcreate(Fid* fid)
 	ulong mode;
 	ulong mode;
 
 
 	if(fid->open)
 	if(fid->open)
-		return Eisopen;
+		return vtstrdup(Eisopen);
 	if(!fid->busy)
 	if(!fid->busy)
-		return Enotexist;
-	if(vfsIsReadOnly(fs))
-		return Erdonly;
+		return vtstrdup(Enotexist);
+	if(fs->mode & ModeSnapshot)
+		return vtstrdup(Erdonly);
 	vf = fid->file;
 	vf = fid->file;
-	if(!vfIsDir(vf))
-		return Enotdir;
+	if(!vacfileisdir(vf))
+		return vtstrdup(Enotdir);
 	if(!permf(vf, fid->user, Pwrite))
 	if(!permf(vf, fid->user, Pwrite))
-		return Eperm;
+		return vtstrdup(Eperm);
 
 
 	mode = rhdr.perm & 0777;
 	mode = rhdr.perm & 0777;
 
 
 	if(rhdr.perm & DMDIR){
 	if(rhdr.perm & DMDIR){
 		if((rhdr.mode & OTRUNC) || (rhdr.perm & DMAPPEND))
 		if((rhdr.mode & OTRUNC) || (rhdr.perm & DMAPPEND))
-			return Emode;
+			return vtstrdup(Emode);
 		switch(rhdr.mode & OPERM){
 		switch(rhdr.mode & OPERM){
 		default:
 		default:
-			return Emode;
+			return vtstrdup(Emode);
 		case OEXEC:
 		case OEXEC:
 		case OREAD:
 		case OREAD:
 			break;
 			break;
 		case OWRITE:
 		case OWRITE:
 		case ORDWR:
 		case ORDWR:
-			return Eperm;
+			return vtstrdup(Eperm);
 		}
 		}
 		mode |= ModeDir;
 		mode |= ModeDir;
 	}
 	}
-	vf = vfCreate(vf, rhdr.name, mode, "none");
-	if(vf == nil)
-		return vtGetError();
-	vfDecRef(fid->file);
+	vf = vacfilecreate(vf, rhdr.name, mode);
+	if(vf == nil) {
+		char err[80];
+		rerrstr(err, sizeof err);
+
+		return vtstrdup(err);
+	}
+
+	vacfiledecref(fid->file);
 
 
 	fid->file = vf;
 	fid->file = vf;
 	fid->qid.type = QTFILE;
 	fid->qid.type = QTFILE;
-	if(vfIsDir(vf))
+	if(vacfileisdir(vf))
 		fid->qid.type = QTDIR;
 		fid->qid.type = QTDIR;
-	fid->qid.vers = vfGetMcount(vf);
-	fid->qid.path = vfGetId(vf);
+	fid->qid.vers = vacfilegetmcount(vf);
+	fid->qid.path = vacfilegetid(vf);
 
 
 	thdr.qid = fid->qid;
 	thdr.qid = fid->qid;
 	thdr.iounit = messagesize - IOHDRSZ;
 	thdr.iounit = messagesize - IOHDRSZ;
@@ -476,11 +493,11 @@ rread(Fid *f)
 	vlong off;
 	vlong off;
 	int cnt;
 	int cnt;
 	VacFile *vf;
 	VacFile *vf;
-	char *err;
+	char err[80];
 	int n;
 	int n;
 
 
 	if(!f->busy)
 	if(!f->busy)
-		return Enotexist;
+		return vtstrdup(Enotexist);
 	vf = f->file;
 	vf = f->file;
 	thdr.count = 0;
 	thdr.count = 0;
 	off = rhdr.offset;
 	off = rhdr.offset;
@@ -488,13 +505,17 @@ rread(Fid *f)
 	cnt = rhdr.count;
 	cnt = rhdr.count;
 	if(f->qid.type & QTDIR)
 	if(f->qid.type & QTDIR)
 		n = vacdirread(f, buf, off, cnt);
 		n = vacdirread(f, buf, off, cnt);
+	else if(vacfilegetmode(f->file)&ModeDevice)
+		return vtstrdup("device");
+	else if(vacfilegetmode(f->file)&ModeLink)
+		return vtstrdup("symbolic link");
+	else if(vacfilegetmode(f->file)&ModeNamedPipe)
+		return vtstrdup("named pipe");
 	else
 	else
-		n = vfRead(vf, buf, cnt, off);
+		n = vacfileread(vf, buf, cnt, off);
 	if(n < 0) {
 	if(n < 0) {
-		err = vtGetError();
-		if(err == nil)
-			err = "unknown error!";
-		return err;
+		rerrstr(err, sizeof err);
+		return vtstrdup(err);
 	}
 	}
 	thdr.count = n;
 	thdr.count = n;
 	return 0;
 	return 0;
@@ -503,27 +524,8 @@ rread(Fid *f)
 char*
 char*
 rwrite(Fid *f)
 rwrite(Fid *f)
 {
 {
-	char *buf;
-	vlong off;
-	int cnt;
-	VacFile *vf;
-
-	if(!f->busy)
-		return Enotexist;
-	vf = f->file;
-	thdr.count = 0;
-	off = rhdr.offset;
-	buf = rhdr.data;
-	cnt = rhdr.count;
-	if(f->qid.type & QTDIR)
-		return "file is a directory";
-	cnt = vfWrite(vf, buf, cnt, off, "none");
-	if(cnt < 0) {
-fprint(2, "write failed: %s\n", vtGetError());
-		return vtGetError();
-	}
-	thdr.count = cnt;
-	return 0;
+	USED(f);
+	return vtstrdup(Erdonly);
 }
 }
 
 
 char *
 char *
@@ -531,12 +533,13 @@ rclunk(Fid *f)
 {
 {
 	f->busy = 0;
 	f->busy = 0;
 	f->open = 0;
 	f->open = 0;
-	vtMemFree(f->user);
+	vtfree(f->user);
 	f->user = nil;
 	f->user = nil;
-	vfDecRef(f->file);
+	if(f->file)
+		vacfiledecref(f->file);
 	f->file = nil;
 	f->file = nil;
-	dirBufFree(f->db);
-	f->db = nil;
+	vdeclose(f->vde);
+	f->vde = nil;
 	return 0;
 	return 0;
 }
 }
 
 
@@ -544,27 +547,28 @@ char *
 rremove(Fid *f)
 rremove(Fid *f)
 {
 {
 	VacFile *vf, *vfp;
 	VacFile *vf, *vfp;
+	char errbuf[80];
 	char *err = nil;
 	char *err = nil;
 
 
 	if(!f->busy)
 	if(!f->busy)
-		return Enotexist;
+		return vtstrdup(Enotexist);
 	vf = f->file;
 	vf = f->file;
-	vfp = vfGetParent(vf);
+	vfp = vacfilegetparent(vf);
 
 
 	if(!permf(vfp, f->user, Pwrite)) {
 	if(!permf(vfp, f->user, Pwrite)) {
 		err = Eperm;
 		err = Eperm;
 		goto Exit;
 		goto Exit;
 	}
 	}
 
 
-	if(!vfRemove(vf, "none")) {
-print("vfRemove failed\n");
-		err = vtGetError();
+	if(!vacfileremove(vf)) {
+		rerrstr(errbuf, sizeof errbuf);
+		err = errbuf;
 	}
 	}
 
 
 Exit:
 Exit:
-	vfDecRef(vfp);
+	vacfiledecref(vfp);
 	rclunk(f);
 	rclunk(f);
-	return err;
+	return vtstrdup(err);
 }
 }
 
 
 char *
 char *
@@ -572,13 +576,16 @@ rstat(Fid *f)
 {
 {
 	VacDir dir;
 	VacDir dir;
 	static uchar statbuf[1024];
 	static uchar statbuf[1024];
-
+	VacFile *parent;
+	
 	if(!f->busy)
 	if(!f->busy)
-		return Enotexist;
-	vfGetDir(f->file, &dir);
+		return vtstrdup(Enotexist);
+	parent = vacfilegetparent(f->file);
+	vacfilegetdir(f->file, &dir);
 	thdr.stat = statbuf;
 	thdr.stat = statbuf;
-	thdr.nstat = vdStat(&dir, thdr.stat, sizeof statbuf);
-	vdCleanup(&dir);
+	thdr.nstat = vacstat(parent, &dir, thdr.stat, sizeof statbuf);
+	vdcleanup(&dir);
+	vacfiledecref(parent);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -586,21 +593,21 @@ char *
 rwstat(Fid *f)
 rwstat(Fid *f)
 {
 {
 	if(!f->busy)
 	if(!f->busy)
-		return Enotexist;
-	return Erdonly;
+		return vtstrdup(Enotexist);
+	return vtstrdup(Erdonly);
 }
 }
 
 
 int
 int
-vdStat(VacDir *vd, uchar *p, int np)
+vacstat(VacFile *parent, VacDir *vd, uchar *p, int np)
 {
 {
+	int ret;
 	Dir dir;
 	Dir dir;
 
 
 	memset(&dir, 0, sizeof(dir));
 	memset(&dir, 0, sizeof(dir));
 
 
-	/*
-	 * Where do path and version come from
-	 */
-	dir.qid.path = vd->qid;
+	dir.qid.path = vd->qid + vacfilegetqidoffset(parent);
+	if(vd->qidspace)
+		dir.qid.path += vd->qidoffset;
 	dir.qid.vers = vd->mcount;
 	dir.qid.vers = vd->mcount;
 	dir.mode = vd->mode & 0777;
 	dir.mode = vd->mode & 0777;
 	if(vd->mode & ModeAppend){
 	if(vd->mode & ModeAppend){
@@ -615,7 +622,8 @@ vdStat(VacDir *vd, uchar *p, int np)
 		dir.qid.type |= QTDIR;
 		dir.qid.type |= QTDIR;
 		dir.mode |= DMDIR;
 		dir.mode |= DMDIR;
 	}
 	}
-
+	
+	
 	dir.atime = vd->atime;
 	dir.atime = vd->atime;
 	dir.mtime = vd->mtime;
 	dir.mtime = vd->mtime;
 	dir.length = vd->size;
 	dir.length = vd->size;
@@ -625,99 +633,43 @@ vdStat(VacDir *vd, uchar *p, int np)
 	dir.gid = vd->gid;
 	dir.gid = vd->gid;
 	dir.muid = vd->mid;
 	dir.muid = vd->mid;
 
 
-	return convD2M(&dir, p, np);
-}
-
-DirBuf*
-dirBufAlloc(VacFile *vf)
-{
-	DirBuf *db;
-
-	db = vtMemAllocZ(sizeof(DirBuf));
-	db->vde = vfDirEnum(vf);
-	return db;
-}
-
-VacDir *
-dirBufGet(DirBuf *db)
-{
-	VacDir *vd;
-	int n;
-
-	if(db->eof)
-		return nil;
-
-	if(db->i >= db->n) {
-		n = vdeRead(db->vde, db->buf, DirBufSize);
-		if(n < 0)
-			return nil;
-		db->i = 0;
-		db->n = n;
-		if(n == 0) {
-			db->eof = 1;
-			return nil;
-		}
-	}
-
-	vd = db->buf + db->i;
-	db->i++;
-
-	return vd;
-}
-
-int
-dirBufUnget(DirBuf *db)
-{
-	assert(db->i > 0);
-	db->i--;
-	return 1;
-}
-
-void
-dirBufFree(DirBuf *db)
-{
-	int i;
-
-	if(db == nil)
-		return;
-
-	for(i=db->i; i<db->n; i++)
-		vdCleanup(db->buf + i);
-	vdeFree(db->vde);
-	vtMemFree(db);
+	ret = convD2Mu(&dir, p, np, dotu);
+	return ret;
 }
 }
 
 
 int
 int
 vacdirread(Fid *f, char *p, long off, long cnt)
 vacdirread(Fid *f, char *p, long off, long cnt)
 {
 {
-	int n, nb;
-	VacDir *vd;
+	int i, n, nb;
+	VacDir vd;
 
 
 	/*
 	/*
 	 * special case of rewinding a directory
 	 * special case of rewinding a directory
 	 * otherwise ignore the offset
 	 * otherwise ignore the offset
 	 */
 	 */
-	if(off == 0 && f->db) {
-		dirBufFree(f->db);
-		f->db = nil;
+	if(off == 0 && f->vde){
+		vdeclose(f->vde);
+		f->vde = nil;
 	}
 	}
 
 
-	if(f->db == nil)
-		f->db = dirBufAlloc(f->file);
+	if(f->vde == nil){
+		f->vde = vdeopen(f->file);
+		if(f->vde == nil)
+			return -1;
+	}
 
 
 	for(nb = 0; nb < cnt; nb += n) {
 	for(nb = 0; nb < cnt; nb += n) {
-		vd = dirBufGet(f->db);
-		if(vd == nil) {
-			if(!f->db->eof)
-				return -1;
+		i = vderead(f->vde, &vd);
+		if(i < 0)
+			return -1;
+		if(i == 0)
 			break;
 			break;
-		}
-		n = vdStat(vd, (uchar*)p, cnt-nb);
+		n = vacstat(f->file, &vd, (uchar*)p, cnt-nb);
 		if(n <= BIT16SZ) {
 		if(n <= BIT16SZ) {
-			dirBufUnget(f->db);
+			vdeunread(f->vde);
 			break;
 			break;
 		}
 		}
-		vdCleanup(vd);
+		vdcleanup(&vd);
 		p += n;
 		p += n;
 	}
 	}
 	return nb;
 	return nb;
@@ -738,7 +690,7 @@ newfid(int fid)
 		ff->fid = fid;
 		ff->fid = fid;
 		return ff;
 		return ff;
 	}
 	}
-	f = vtMemAllocZ(sizeof *f);
+	f = vtmallocz(sizeof *f);
 	f->fid = fid;
 	f->fid = fid;
 	f->next = fids;
 	f->next = fids;
 	fids = f;
 	fids = f;
@@ -752,20 +704,10 @@ io(void)
 	int n;
 	int n;
 
 
 	for(;;){
 	for(;;){
-		/*
-		 * reading from a pipe or a network device
-		 * will give an error after a few eof reads
-		 * however, we cannot tell the difference
-		 * between a zero-length read and an interrupt
-		 * on the processes writing to us,
-		 * so we wait for the error
-		 */
 		n = read9pmsg(mfd[0], mdata, sizeof mdata);
 		n = read9pmsg(mfd[0], mdata, sizeof mdata);
-		if(n == 0)
-			continue;
-		if(n < 0)
+		if(n <= 0)
 			break;
 			break;
-		if(convM2S(mdata, n, &rhdr) != n)
+		if(convM2Su(mdata, n, &rhdr, dotu) != n)
 			sysfatal("convM2S conversion error");
 			sysfatal("convM2S conversion error");
 
 
 		if(dflag)
 		if(dflag)
@@ -786,7 +728,12 @@ io(void)
 		thdr.tag = rhdr.tag;
 		thdr.tag = rhdr.tag;
 		if(dflag)
 		if(dflag)
 			fprint(2, "vacfs:->%F\n", &thdr);
 			fprint(2, "vacfs:->%F\n", &thdr);
-		n = convS2M(&thdr, mdata, messagesize);
+		n = convS2Mu(&thdr, mdata, messagesize, dotu);
+		if(n <= BIT16SZ)
+			sysfatal("convS2Mu conversion error");
+		if(err)
+			vtfree(err);
+
 		if(write(mfd[1], mdata, n) != n)
 		if(write(mfd[1], mdata, n) != n)
 			sysfatal("mount write: %r");
 			sysfatal("mount write: %r");
 	}
 	}
@@ -795,13 +742,13 @@ io(void)
 int
 int
 permf(VacFile *vf, char *user, int p)
 permf(VacFile *vf, char *user, int p)
 {
 {
-	int ok = 1;
 	VacDir dir;
 	VacDir dir;
 	ulong perm;
 	ulong perm;
 
 
-	if(!vfGetDir(vf, &dir))
+	if(vacfilegetdir(vf, &dir))
 		return 0;
 		return 0;
 	perm = dir.mode & 0777;
 	perm = dir.mode & 0777;
+
 	if(noperm)
 	if(noperm)
 		goto Good;
 		goto Good;
 	if((p*Pother) & perm)
 	if((p*Pother) & perm)
@@ -810,10 +757,11 @@ permf(VacFile *vf, char *user, int p)
 		goto Good;
 		goto Good;
 	if(strcmp(user, dir.uid)==0 && ((p*Powner) & perm))
 	if(strcmp(user, dir.uid)==0 && ((p*Powner) & perm))
 		goto Good;
 		goto Good;
-	ok = 0;
+	vdcleanup(&dir);
+	return 0;
 Good:
 Good:
-	vdCleanup(&dir);
-	return ok;
+	vdcleanup(&dir);
+	return 1;
 }
 }
 
 
 int
 int
@@ -823,39 +771,17 @@ perm(Fid *f, int p)
 }
 }
 
 
 void
 void
-init(char *file, char *host, long ncache, int readOnly)
-{
-	notify(notifyf);
-	user = getuser();
-
-	fmtinstall('V', vtScoreFmt);
-	fmtinstall('R', vtErrFmt);
-
-	session = vtDial(host, 0);
-	if(session == nil)
-		vtFatal("could not connect to server: %s", vtGetError());
-
-	if(!vtConnect(session, 0))
-		vtFatal("vtConnect: %s", vtGetError());
-
-	fs = vfsOpen(session, file, readOnly, ncache);
-	if(fs == nil)
-		vtFatal("vfsOpen: %s", vtGetError());
-}
-
-void
-shutdown(void)
+vacshutdown(void)
 {
 {
 	Fid *f;
 	Fid *f;
 
 
 	for(f = fids; f; f = f->next) {
 	for(f = fids; f; f = f->next) {
 		if(!f->busy)
 		if(!f->busy)
 			continue;
 			continue;
-fprint(2, "open fid: %d\n", f->fid);
 		rclunk(f);
 		rclunk(f);
 	}
 	}
 
 
-	vfsClose(fs);
-	vtClose(session);
+	vacfsclose(fs);
+	vthangup(conn);
 }
 }
 
 

+ 0 - 182
sys/src/cmd/vac/vactest.c

@@ -1,182 +0,0 @@
-#include "stdinc.h"
-#include "vac.h"
-#include "dat.h"
-#include "fns.h"
-
-void usage(void);
-int unvac(VacFS *fs);
-int readScore(int fd, uchar score[VtScoreSize]);
-static void warn(char *fmt, ...);
-void dirlist(VacFS *fs, char *path);
-
-static	int	nwant;
-static	char	**want;
-static	int	dflag = 1;
-static	int	cflag;
-static	int	lower;
-static	int	verbose;
-static	int	settimes;
-
-void
-main(int argc, char *argv[])
-{
-	char *zfile;
-	int ok, table;
-	VtSession *z;
-	char *vsrv = nil;
-	char *host = nil;
-	char *p;
-	int ncache = 1000;
-	VacFS *fs;
-
-	table = 0;
-	zfile = nil;
-	ARGBEGIN{
-	case 'D':
-		dflag++;
-		break;
-	case 'c':
-		cflag++;
-		break;
-	case 'C':
-		p = ARGF();
-		if(p == nil)
-			usage();
-		ncache = atoi(p);
-		if(ncache < 10)
-			ncache = 10;
-		if(ncache > 1000000)
-			ncache = 1000000;
-		break;
-	case 'i':
-		lower++;
-		break;
-	case 'f':
-		zfile = ARGF();
-		if(zfile == nil)
-			usage();
-		break;
-	case 'h':
-		host = ARGF();
-		break;
-	case 't':
-		table++;
-		break;
-	case 'T':
-		settimes++;
-		break;
-	case 's':
-		vsrv = ARGF();
-		break;
-	case 'v':
-		verbose++;
-		break;
-	default:
-		usage();
-		break;
-	}ARGEND
-
-	nwant = argc;
-	want = argv;
-
-	vtAttach();
-
-	if(zfile == nil)
-		usage();
-
-	if(vsrv != nil)
-		z = vtStdioServer(vsrv);
-	else
-		z = vtDial(host);
-	if(z == nil)
-		vtFatal("could not connect to server: %s", vtGetError());
-	vtSetDebug(z, 0);
-	if(!vtConnect(z, 0))
-		vtFatal("vtConnect: %s", vtGetError());
-	fs = vfsOpen(z, zfile, 1, ncache);
-	if(fs == nil)
-		vtFatal("vfsOpen: %s", vtGetError());
-	ok = unvac(fs);
-	vtClose(z);
-	vtDetach();
-	
-	exits(ok? 0 : "error");
-}
-
-void
-usage(void)
-{
-	fprint(2, "usage: %s [-tTcDv] -f zipfile [-s ventid] [-h host] [file ...]\n", argv0);
-	exits("usage");
-}
-
-void
-suck(VacFile *f)
-{
-	USED(f);
-}
-
-
-void
-vacfile(VacFS *fs, char *path, VacDir *vd)
-{
-	char *path2;
-
-	path2 = vtMemAlloc(strlen(path) + 1 + strlen(vd->elem) + 1);
-	if(path[1] == 0)
-		sprintf(path2, "/%s", vd->elem);
-	else
-		sprintf(path2, "%s/%s", path, vd->elem);
-fprint(2, "vac file: %s\n", path2);
-	if(vd->mode & ModeDir)
-		dirlist(fs, path2);
-	vtMemFree(path2);
-}
-
-void
-dirlist(VacFS *fs, char *path)
-{
-	VacDir vd[50];
-	VacDirEnum *ds;
-	int i, n;
-
-	ds = vdeOpen(fs, path);
-	if(ds == nil) {
-		fprint(2, "could not open: %s: %s\n", path, vtGetError());
-		return;
-	}
-	for(;;) {
-		n = vdeRead(ds, vd, sizeof(vd)/sizeof(VacDir));
-		if(n < 0) {
-			warn("vdRead failed: %s: %s", path, vtGetError());
-			return;
-		}
-		if(n == 0)
-			break;
-		for(i=0; i<n; i++) {
-			vacfile(fs, path, &vd[i]);
-			vdCleanup(&vd[i]);
-		}
-	}
-	vdeFree(ds);
-}
-
-int
-unvac(VacFS *fs)
-{
-	dirlist(fs, "/");
-
-	return 1;
-}
-
-static void
-warn(char *fmt, ...)
-{
-	va_list arg;
-
-	va_start(arg, fmt);
-	fprint(2, "%s: ", argv0);
-	vfprint(2, fmt, arg);
-	fprint(2, "\n");
-	va_end(arg);
-}

+ 0 - 422
sys/src/cmd/vac/vtdump.c

@@ -1,422 +0,0 @@
-#include "stdinc.h"
-#include <bio.h>
-
-typedef struct Source Source;
-
-struct Source
-{
-	ulong gen;
-	int psize;
-	int dsize;
-	int dir;
-	int active;
-	int depth;
-	uvlong size;
-	uchar score[VtScoreSize];
-	int reserved;
-};
-
-int bsize;
-Biobuf *bout;
-VtRoot root;
-int ver;
-int cmp;
-int all;
-int find;
-uchar fscore[VtScoreSize];
-VtSession *z;
-
-int vtGetUint16(uchar *p);
-ulong vtGetUint32(uchar *p);
-uvlong vtGetUint48(uchar *p);
-void usage(void);
-int parseScore(uchar *score, char *buf, int n);
-void readRoot(VtRoot*, uchar *score, char *file);
-int dumpDir(Source*, int indent);
-
-void
-main(int argc, char *argv[])
-{
-	char *host = nil;
-	uchar score[VtScoreSize];
-	Source source;
-	uchar buf[VtMaxLumpSize];
-	char *p;
-	int n;
-
-	ARGBEGIN{
-	case 'h':
-		host = ARGF();
-		break;
-	case 'c':
-		cmp++;
-		break;
-	case 'f':
-		find++;
-		p = EARGF(usage());
-		if(!parseScore(fscore, p, strlen(p)))
-			usage();
-		break;
-	case 'a':
-		all = 1;
-		break;
-	default:
-		usage();
-	}ARGEND
-
-	vtAttach();
-
-	bout = vtMemAllocZ(sizeof(Biobuf));
-	Binit(bout, 1, OWRITE);
-
-	if(argc > 1)
-		usage();
-
-	vtAttach();
-
-	fmtinstall('V', vtScoreFmt);
-	fmtinstall('R', vtErrFmt);
-
-	z = vtDial(host, 0);
-	if(z == nil)
-		vtFatal("could not connect to server: %s", vtGetError());
-
-	if(!vtConnect(z, 0))
-		sysfatal("vtConnect: %r");
-
-	readRoot(&root, score, argv[0]);
-	ver = root.version;
-	bsize = root.blockSize;
-	if(!find) {
-		Bprint(bout, "score: %V\n", score);
-		Bprint(bout, "version: %d\n", ver);
-		Bprint(bout, "name: %s\n", root.name);
-		Bprint(bout, "type: %s\n", root.type);
-		Bprint(bout, "bsize: %d\n", bsize);
-		Bprint(bout, "prev: %V\n", root.prev);
-	}
-	if (bsize == 0)
-		sysfatal("zero bsize");
-
-	switch(ver) {
-	default:
-		sysfatal("unknown version");
-	case VtRootVersion:
-		break;
-	}
-
-	n = vtRead(z, root.score, VtDirType, buf, bsize);
-	if(n < 0)
-		sysfatal("could not read root dir");
-
-	/* fake up top level source */
-	memset(&source, 0, sizeof(source));
-	memmove(source.score, root.score, VtScoreSize);
-	source.psize = bsize;
-	source.dsize = bsize;
-	source.dir = 1;
-	source.active = 1;
-	source.depth = 0;
-	source.size = n;
-
-	dumpDir(&source, 0);
-
-	Bterm(bout);
-
-	vtClose(z);
-	vtDetach();
-	exits(0);
-}
-
-void
-sourcePrint(Source *s, int indent, int entry)
-{
-	int i;
-	uvlong size, dsize;
-	int ne;
-
-	for(i=0; i<indent; i++)
-		Bprint(bout, " ");
-	Bprint(bout, "%4d", entry);
-	if(s->active) {
-		/* dir size in directory entries */
-		if(s->dir) {
-			dsize = s->dsize;
-			if (dsize <= 0) {
-				fprint(2, "%s: non-positive dsize %d in dir %V\n",
-					argv0, s->dsize, s->score);
-				dsize = 1;	/* don't divide by zero */
-			}
-			ne = s->dsize/VtEntrySize;
-			size = ne*(s->size/dsize) +
-				(s->size%dsize)/VtEntrySize;
-		} else 
-			size = s->size;
-		if(cmp) {
-			Bprint(bout, ": gen: %lud size: %llud",
-				s->gen, size);
-			if(!s->dir)
-				Bprint(bout, ": %V", s->score);
-		} else {
-			Bprint(bout, ": gen: %lud psize: %d dsize: %d",
-				s->gen, s->psize, s->dsize);
-			Bprint(bout, " depth: %d size: %llud: %V",
-				s->depth, size, s->score);
-		}
-		
-		if(s->reserved)
-			Bprint(bout, ": reserved not emtpy");
-	}
-	Bprint(bout, "\n");
-}
-
-int
-parse(Source *s, uchar *p)
-{
-	VtEntry dir;
-
-	memset(s, 0, sizeof(*s));
-	if(!vtEntryUnpack(&dir, p, 0))
-		return 0;
-
-	if(!(dir.flags & VtEntryActive))
-		return 1;
-
-	s->active = 1;
-	s->gen = dir.gen;
-	s->psize = dir.psize;
-	s->dsize = dir.dsize;
-	s->size = dir.size;
-	memmove(s->score, dir.score, VtScoreSize);
-	if(dir.flags & VtEntryDir)
-		s->dir = 1;
-	s->depth = dir.depth;
-	return 1;
-}
-
-int
-sourceRead(Source *s, ulong block, uchar *p, int n)
-{
-	uchar buf[VtMaxLumpSize];
-	uchar score[VtScoreSize];
-	int i, nn, np, type;
-	int elem[VtPointerDepth];
-
-	memmove(score, s->score, VtScoreSize);
-
-	np = s->psize/VtScoreSize;
-	assert(np > 0);
-	for(i=0; i<s->depth; i++) {
-		elem[i] = block % np;
-		block /= np;
-	}
-	assert(block == 0);
-
-	for(i=s->depth-1; i>=0; i--) {
-		nn = vtRead(z, score, VtPointerType0+i, buf, s->psize);
-		if(nn < 0)
-			return -1;
-
-		if(!vtSha1Check(score, buf, nn)) {
-			vtSetError("vtSha1Check failed on root block");
-			return -1;
-		}
-
-		if((elem[i]+1)*VtScoreSize > nn)
-			return 0;
-		memmove(score, buf + elem[i]*VtScoreSize, VtScoreSize);
-	}
-
-	if(s->dir)
-		type = VtDirType;
-	else
-		type = VtDataType;
-
-	nn = vtRead(z, score, type, p, n);
-	if(nn < 0)
-		return -1;
-
-	if(!vtSha1Check(score, p, nn)) {
-		vtSetError("vtSha1Check failed on root block");
-		return -1;
-	}
-	
-	return nn;
-}
-
-void
-dumpFileContents(Source *s)
-{
-	int nb, lb, i, n;
-	uchar buf[VtMaxLumpSize];
-
-	nb = (s->size + s->dsize - 1)/s->dsize;
-	lb = s->size%s->dsize;
-	for(i=0; i<nb; i++) {
-		if (s->dsize > sizeof buf) {
-			fprint(2, "%s: implausibly large s->dsize %d for %V\n",
-				argv0, s->dsize, s->score);
-			continue;
-		}
-		memset(buf, 0, s->dsize);
-		n = sourceRead(s, i, buf, s->dsize);
-		if(n < 0) {	
-			fprint(2, "could not read block: %d: %s\n", i, vtGetError());
-			continue;
-		}
-		if(i < nb-1)
-			Bwrite(bout, buf, s->dsize);
-		else
-			Bwrite(bout, buf, lb);
-	}
-}
-
-void
-dumpFile(Source *s, int indent)
-{
-	int nb, i, j, n;
-	uchar buf[VtMaxLumpSize];
-	uchar score[VtScoreSize];
-
-	nb = (s->size + s->dsize - 1)/s->dsize;
-	for(i=0; i<nb; i++) {
-		if (s->dsize > sizeof buf) {
-			fprint(2, "%s: implausibly large s->dsize %d for %V\n",
-				argv0, s->dsize, s->score);
-			continue;
-		}
-		memset(buf, 0, s->dsize);
-		n = sourceRead(s, i, buf, s->dsize);
-		if(n < 0) {	
-			fprint(2, "could not read block: %d: %s\n", i, vtGetError());
-			continue;
-		}
-		for(j=0; j<indent; j++)
-			Bprint(bout, " ");
-		vtSha1(score, buf, n);		
-		Bprint(bout, "%4d: size: %ud: %V\n", i, n, score);
-	}
-}
-
-int
-dumpDir(Source *s, int indent)
-{
-	int pb, ne, nb, i, j, n, entry;
-	uchar buf[VtMaxLumpSize];
-	Source ss;
-
-	if (s->dsize <= 0) {
-		fprint(2, "%s: dumpDir %V: non-positive s->dsize %d\n",
-			argv0, s->score, s->dsize);
-		return 1;
-	}
-	pb = s->dsize/VtEntrySize;
-	ne = pb*(s->size/s->dsize) + (s->size%s->dsize)/VtEntrySize;
-	nb = (s->size + s->dsize - 1)/s->dsize;
-	for(i=0; i<nb; i++) {
-		if (s->dsize > sizeof buf) {
-			fprint(2, "%s: implausibly large s->dsize %d for %V\n",
-				argv0, s->dsize, s->score);
-			continue;
-		}
-		memset(buf, 0, s->dsize);
-		n = sourceRead(s, i, buf, s->dsize);
-		if(n < 0) {	
-			fprint(2, "could not read block: %d: %s\n", i, vtGetError());
-			continue;
-		}
-		for(j=0; j<pb; j++) {
-			entry = i*pb + j;
-			if(entry >= ne)
-				break;
-			parse(&ss, buf + j * VtEntrySize);
-
-			if(!find)
-				sourcePrint(&ss, indent, entry);
-			else if(memcmp(ss.score, fscore, VtScoreSize) == 0) {
-				dumpFileContents(&ss);
-				return 0;
-			}
-
-			if(ss.dir) {
-				if(!dumpDir(&ss, indent+1))
-					return 0;
-			} else if(all)
-				dumpFile(&ss, indent+1);
-		}
-	}
-	return 1;
-}
-
-void
-usage(void)
-{
-	fprint(2, "usage: %s [-ac] [-f findscore] [-h host] [file]\n", argv0);
-	exits("usage");
-}
-
-int
-parseScore(uchar *score, char *buf, int n)
-{
-	int i, c;
-
-	memset(score, 0, VtScoreSize);
-
-	if(n < VtScoreSize*2)
-		return 0;
-	for(i=0; i<VtScoreSize*2; i++) {
-		if(buf[i] >= '0' && buf[i] <= '9')
-			c = buf[i] - '0';
-		else if(buf[i] >= 'a' && buf[i] <= 'f')
-			c = buf[i] - 'a' + 10;
-		else if(buf[i] >= 'A' && buf[i] <= 'F')
-			c = buf[i] - 'A' + 10;
-		else {
-			return 0;
-		}
-
-		if((i & 1) == 0)
-			c <<= 4;
-	
-		score[i>>1] |= c;
-	}
-	return 1;
-}
-
-void
-readRoot(VtRoot *root, uchar *score, char *file)
-{
-	int fd;
-	uchar buf[VtRootSize];
-	int i, n, nn;
-
-	if(file == nil)
-		fd = 0;
-	else {
-		fd = open(file, OREAD);
-		if(fd < 0)
-			sysfatal("could not open file: %s: %r", file);
-	}
-	n = readn(fd, buf, sizeof(buf)-1);
-	if(n < 0)
-		sysfatal("read failed: %r");
-	buf[n] = 0;
-	close(fd);
-
-	for(i=0; i<n; i++) {
-		if(!parseScore(score, (char*)(buf+i), n-i))
-			continue;
-		nn = vtRead(z, score, VtRootType, buf, VtRootSize);
-		if(nn >= 0) {
-			if(nn != VtRootSize)
-				sysfatal("vtRead on root too short");
-			if(!vtSha1Check(score, buf, VtRootSize))
-				sysfatal("vtSha1Check failed on root block");
-			if(!vtRootUnpack(root, buf))
-				sysfatal("could not parse root: %r");
-			return;
-		}
-	}
-
-	sysfatal("could not find root");
-}

+ 0 - 127
sys/src/cmd/vac/vtread.c

@@ -1,127 +0,0 @@
-#include "stdinc.h"
-#include <bio.h>
-
-typedef struct Source Source;
-
-struct Source
-{
-	ulong gen;
-	int psize;
-	int dsize;
-	int dir;
-	int active;
-	int depth;
-	uvlong size;
-	uchar score[VtScoreSize];
-	int reserved;
-};
-
-int bsize;
-Biobuf *bout;
-int ver;
-int cmp;
-int all;
-int find;
-uchar fscore[VtScoreSize];
-int dirSize;
-void (*parse)(Source*, uchar*);
-VtSession *z;
-
-int vtGetUint16(uchar *p);
-ulong vtGetUint32(uchar *p);
-uvlong vtGetUint48(uchar *p);
-void usage(void);
-int parseScore(uchar *score, char *buf, int n);
-void parse1(Source*, uchar*);
-void parse2(Source*, uchar*);
-int dumpDir(Source*, int indent);
-
-void
-main(int argc, char *argv[])
-{
-	char *host = nil;
-	uchar score[VtScoreSize];
-	uchar buf[VtMaxLumpSize];
-	int type;
-	int n;
-	
-	type = VtDataType;
-
-	ARGBEGIN{
-	case 't':
-		type = atoi(ARGF());
-		break;
-	default:
-		usage();
-		break;
-	}ARGEND
-
-	vtAttach();
-
-	bout = vtMemAllocZ(sizeof(Biobuf));
-	Binit(bout, 1, OWRITE);
-
-	if(argc != 1)
-		usage();
-
-	vtAttach();
-
-	fmtinstall('V', vtScoreFmt);
-	fmtinstall('R', vtErrFmt);
-
-	z = vtDial(host, 0);
-	if(z == nil)
-		vtFatal("could not connect to server: %s", vtGetError());
-
-	if(!vtConnect(z, 0))
-		sysfatal("vtConnect: %r");
-
-	if(!parseScore(score, argv[0], strlen(argv[0])))
-		vtFatal("could not parse score: %s", vtGetError());
-
-	n = vtRead(z, score, type, buf, VtMaxLumpSize);
-	if(n < 0)
-		vtFatal("could not read block: %s", vtGetError());
-	Bwrite(bout, buf, n);
-
-	Bterm(bout);
-
-	vtClose(z);
-	vtDetach();
-	exits(0);
-}
-
-void
-usage(void)
-{
-	fprint(2, "%s: [-t type] score\n", argv0);
-	exits("usage");
-}
-
-int
-parseScore(uchar *score, char *buf, int n)
-{
-	int i, c;
-
-	memset(score, 0, VtScoreSize);
-
-	if(n < VtScoreSize*2)
-		return 0;
-	for(i=0; i<VtScoreSize*2; i++) {
-		if(buf[i] >= '0' && buf[i] <= '9')
-			c = buf[i] - '0';
-		else if(buf[i] >= 'a' && buf[i] <= 'f')
-			c = buf[i] - 'a' + 10;
-		else if(buf[i] >= 'A' && buf[i] <= 'F')
-			c = buf[i] - 'A' + 10;
-		else {
-			return 0;
-		}
-
-		if((i & 1) == 0)
-			c <<= 4;
-	
-		score[i>>1] |= c;
-	}
-	return 1;
-}

+ 0 - 47
sys/src/cmd/vac/wtest.c

@@ -1,47 +0,0 @@
-#include "stdinc.h"
-
-enum {
-	Nblock = 10000,
-	BlockSize = 8*1024,
-};
-
-uchar data[Nblock*BlockSize];
-
-void
-main(int argc, char *argv[])
-{
-	VtSession *z;
-	int i;
-	uchar score[VtScoreSize];
-	int start;
-
-	ARGBEGIN{
-	}ARGEND
-
-	for(i=0; i<Nblock; i++) {
-		if(readn(0, data+i*BlockSize, BlockSize) < BlockSize)
-			sysfatal("read failed: %r");
-	}
-
-	vtAttach();
-
-	z = vtDial("iolaire2");
-	if(z == nil)
-		sysfatal("cound not connect to venti");
-	if(!vtConnect(z, 0))
-		vtFatal("vtConnect: %s", vtGetError());
-
-	print("starting\n");
-
-	start = times(0);
-
-	for(i=0; i<Nblock; i++) {
-		if(!vtWrite(z, score, VtDataType, data+i*BlockSize, BlockSize))
-			vtFatal("vtWrite failed: %s", vtGetError());
-	}
-
-	print("time = %f\n", (times(0) - start)*0.001);
-
-	vtClose(z);
-	vtDetach();
-}

+ 3 - 4
sys/src/libventi/mem.c

@@ -54,8 +54,7 @@ vtbrk(int n)
 {
 {
 	static Lock lk;
 	static Lock lk;
 	static uchar *buf;
 	static uchar *buf;
-	static int nbuf;
-	static int nchunk;
+	static int nbuf, nchunk;
 	int align, pad;
 	int align, pad;
 	void *p;
 	void *p;
 
 
@@ -67,11 +66,11 @@ vtbrk(int n)
 		align = 4;
 		align = 4;
 
 
 	lock(&lk);
 	lock(&lk);
-	pad = (align - (ulong)buf) & (align-1);
+	pad = (align - (uintptr)buf) & (align-1);
 	if(n + pad > nbuf) {
 	if(n + pad > nbuf) {
 		buf = vtmallocz(ChunkSize);
 		buf = vtmallocz(ChunkSize);
 		nbuf = ChunkSize;
 		nbuf = ChunkSize;
-		pad = (align - (ulong)buf) & (align-1);
+		pad = (align - (uintptr)buf) & (align-1);
 		nchunk++;
 		nchunk++;
 	}
 	}
 
 

Some files were not shown because too many files changed in this diff