Commit Diff


commit - 518f0a1d31c58266a12ee76c90180d66fde57bb4
commit + 5f6612babbd9e6c0a4a204db0f9d2f286ec58261
blob - d7df56eba583637bd789aa3f1b6743f978973c40
blob + c7205e20adc135dde80dbaeb7d78ba8a486ca183
--- bin/9c
+++ bin/9c
@@ -56,7 +56,7 @@ case "$tag" in
 		v=`uname -r`
 		s=`echo $u$v | tr '. ' '__'`
 		cflags="$ngflags -g"
-		cflags="$cflags -D__${s}__"
+		cflags="$cflags -D__sun__ -D__${s}__"
 		;;
 *)
 	echo 9c does not know how to compile on "$tag" 1>&2
blob - 8f49245043b90a6fed49bd1f90336db5d1ac1b16
blob + 105a46dbb9e7f0402bf380695acd9f9f83b48db1
--- src/cmd/auth/factotum/confirm.c
+++ src/cmd/auth/factotum/confirm.c
@@ -30,11 +30,13 @@ confirmwrite(char *s)
 		return -1;
 	}
 	if((t = _strfindattr(a, "tag")) == nil){
+		flog("bad confirm write: no tag");
 		werrstr("no tag");
 		return -1;
 	}
 	tag = strtoul(t, 0, 0);
 	if((ans = _strfindattr(a, "answer")) == nil){
+		flog("bad confirm write: no answer");
 		werrstr("no answer");
 		return -1;
 	}
@@ -43,6 +45,7 @@ confirmwrite(char *s)
 	else if(strcmp(ans, "no") == 0)
 		allow = 0;
 	else{
+		flog("bad confirm write: bad answer");
 		werrstr("bad answer");
 		return -1;
 	}
@@ -62,12 +65,17 @@ confirmwrite(char *s)
 int
 confirmkey(Conv *c, Key *k)
 {
+	int ret;
+
 	if(*confirminuse == 0)
 		return -1;
 
 	lbappend(&confbuf, "confirm tag=%lud %A %N", c->tag, k->attr, k->privattr);
+	flog("confirm %A %N", k->attr, k->privattr);
 	c->state = "keyconfirm";
-	return recvul(c->keywait);
+	ret = recvul(c->keywait);
+	flog("confirm=%d %A %N", ret, k->attr, k->privattr);
+	return ret;
 }
 
 Logbuf needkeybuf;
@@ -124,6 +132,7 @@ needkey(Conv *c, Attr *a)
 		return -1;
 
 	lbappend(&needkeybuf, "needkey tag=%lud %A", c->tag, a);
+	flog("needkey %A", a);
 	return nbrecvul(c->keywait);
 }
 
@@ -135,5 +144,7 @@ badkey(Conv *c, Key *k, char *msg, Attr *a)
 
 	lbappend(&needkeybuf, "badkey tag=%lud %A %N\n%s\n%A",
 		c->tag, k->attr, k->privattr, msg, a);
+	flog("badkey %A / %N / %s / %A",
+		k->attr, k->privattr, msg, a);
 	return nbrecvul(c->keywait);
 }
blob - cd9d5045eb6e434dda7a2bfe0363c552d6ddd7a0
blob + 1c92c06c9ce1aa2415c5123054f408c90ea100ce
--- src/cmd/auth/factotum/conv.c
+++ src/cmd/auth/factotum/conv.c
@@ -89,12 +89,14 @@ convgetrpc(Conv *c, int want)
 {
 	for(;;){
 		if(c->hangup){
+			flog("convgetrpc: hangup");
 			werrstr("hangup");
 			return nil;
 		}
 		if(c->rpc.op == RpcUnknown){
 			recvp(c->rpcwait);
 			if(c->hangup){
+				flog("convgetrpc: hangup");
 				werrstr("hangup");
 				return nil;
 			}
@@ -227,12 +229,27 @@ convneedkey(Conv *c, Attr *a)
 	 * in response.  The keys get added out-of-band (via the
 	 * ctl file), so assume the key has been added when the
 	 * next request comes in.
+	 *
+	 * The convgetrpc seems dodgy, because we might be in
+	 * the middle of an rpc, and what about the one that comes
+	 * in later?  It's all actually okay: convgetrpc is idempotent
+	 * until rpcrespond is called, so if we're in the middle of an rpc,
+	 * the first convgetrpc is a no-op, the rpcrespond sends back
+	 * the needkey, and then the client repeats the rpc we're in
+	 * the middle of.  Otherwise, if we're not in the middle of an
+	 * rpc, the first convgetrpc waits for one, we respond needkey,
+	 * and then the second convgetrpc waits for another.  Because
+	 * there is no second response, eventually the caller will get
+	 * around to asking for an rpc itself, at which point the already
+	 * gotten rpc will be returned again.
 	 */
 	if(convgetrpc(c, -1) == nil)
 		return -1;
+	flog("convneedkey %A", a);
 	rpcrespond(c, "needkey %A", a);
 	if(convgetrpc(c, -1) == nil)
 		return -1;
+	flog("convneedkey returning");
 	return 0;
 }
 
@@ -242,6 +259,7 @@ convbadkey(Conv *c, Key *k, char *msg, Attr *a)
 {
 	if(convgetrpc(c, -1) == nil)
 		return -1;
+	flog("convbadkey %A %N / %s / %A", k->attr, k->privattr, msg, a);
 	rpcrespond(c, "badkey %A %N\n%s\n%A",
 		k->attr, k->privattr, msg, a);
 	if(convgetrpc(c, -1) == nil)
blob - 6195bb8401ddc524b0a090b4f2ffcf6be12740b3
blob + d12fbca7caa59c16d6ff9a9fbc2d7f3a3dd0ba93
--- src/cmd/auth/factotum/ctl.c
+++ src/cmd/auth/factotum/ctl.c
@@ -98,12 +98,14 @@ ctlwrite(char *a)
 				l = &(*l)->next;
 		}
 		*lpriv = nil;
+		flog("addkey %A %A %N", protos, attr, priv);
 
 		/* add keys */
 		ret = 0;
 		for(pa=protos; pa; pa=pa->next){
 			if((proto = protolookup(pa->val)) == nil){
 				werrstr("unknown proto %s", pa->val);
+				flog("addkey: %r");
 				ret = -1;
 				continue;
 			}
@@ -112,6 +114,7 @@ ctlwrite(char *a)
 				if(!matchattr(kpa, attr, priv)){
 					freeattr(kpa);
 					werrstr("missing attributes -- want %s", proto->keyprompt);
+					flog("addkey %s: %r", proto->name);
 					ret = -1;
 					continue;
 				}
@@ -123,10 +126,12 @@ ctlwrite(char *a)
 			k->ref = 1;
 			k->proto = proto;
 			if(proto->checkkey && (*proto->checkkey)(k) < 0){
+				flog("addkey %s: %r", proto->name);
 				ret = -1;
 				keyclose(k);
 				continue;
 			}
+			flog("adding key: %A %N", k->attr, k->privattr);
 			keyadd(k);
 			keyclose(k);
 		}
@@ -137,6 +142,7 @@ ctlwrite(char *a)
 	case 1:	/* delkey */
 		nmatch = 0;
 		attr = parseattr(p);
+		flog("delkey %A", attr);
 		for(pa=attr; pa; pa=pa->next){
 			if(pa->type != AttrQuery && pa->name[0]=='!'){
 				werrstr("only !private? patterns are allowed for private fields");
@@ -147,6 +153,7 @@ ctlwrite(char *a)
 		for(i=0; i<ring.nkey; ){
 			if(matchattr(attr, ring.key[i]->attr, ring.key[i]->privattr)){
 				nmatch++;
+				flog("deleting %A %N", ring.key[i]->attr, ring.key[i]->privattr);
 				keyclose(ring.key[i]);
 				ring.nkey--;
 				memmove(&ring.key[i], &ring.key[i+1], (ring.nkey-i)*sizeof(ring.key[0]));
@@ -161,6 +168,7 @@ ctlwrite(char *a)
 		return 0;
 	case 2:	/* debug */
 		debug ^= 1;
+		flog("debug = %d", debug);
 		return 0;
 	}
 }
blob - 08894ae6fd1219ab55b994825dda2d67efc99f05
blob + 2edbc7b1f957b4fef19829d0c4e606c1f082a93e
--- src/cmd/auth/factotum/fs.c
+++ src/cmd/auth/factotum/fs.c
@@ -372,6 +372,7 @@ fswrite(Req *r)
 	int ret;
 	char err[ERRMAX], *s;
 	int (*strfn)(char*);
+	char *name;
 
 	switch((int)r->fid->qid.path){
 	default:
@@ -387,12 +388,15 @@ fswrite(Req *r)
 		}
 		break;
 	case Qneedkey:
+		name = "needkey";
 		strfn = needkeywrite;
 		goto string;
 	case Qctl:
+		name = "ctl";
 		strfn = ctlwrite;
 		goto string;
 	case Qconfirm:
+		name = "confirm";
 		strfn = confirmwrite;
 	string:
 		s = emalloc(r->ifcall.count+1);
@@ -403,6 +407,7 @@ fswrite(Req *r)
 		if(ret < 0){
 			rerrstr(err, sizeof err);
 			respond(r, err);
+			flog("write %s: %s", name, err);
 		}else{
 			r->ofcall.count = r->ifcall.count;
 			respond(r, nil);
blob - e2299b846c0448c2efbe758f5898e95b23b32e2c
blob + 9df50eb31cd780ba51bc31d1bb33f58d826c6e09
--- src/cmd/auth/factotum/key.c
+++ src/cmd/auth/factotum/key.c
@@ -67,6 +67,7 @@ keyfetch(Conv *c, char *fmt, ...)
 	a = parseattrfmtv(fmt, arg);
 	va_end(arg);
 
+	flog("keyfetch %A", a);
 	tag = 0;
 
 	for(i=0; i<ring.nkey; i++){
@@ -80,6 +81,7 @@ keyfetch(Conv *c, char *fmt, ...)
 				continue;
 			}
 			freeattr(a);
+			flog("using key %A %N", k->attr, k->privattr);
 			return k;
 		}
 	}
blob - 239dca51a8a68d98999a24ab1a197d66b768c920
blob + 4d29536b06850619d7d248f5a81e8d97a35872ec
--- src/cmd/auth/factotum/log.c
+++ src/cmd/auth/factotum/log.c
@@ -84,7 +84,7 @@ lbvappend(Logbuf *lb, char *fmt, va_list arg)
 {
 	char *s;
 
-	s = smprint(fmt, arg);
+	s = vsmprint(fmt, arg);
 	if(s == nil)
 		sysfatal("out of memory");
 	if(lb->msg[lb->wp])
blob - 46156939ddad596549be8562df70ced658b163a0
blob + 0a79a361bede4c53d0a41afc1f9341652b6c84aa
--- src/cmd/auth/factotum/p9sk1.c
+++ src/cmd/auth/factotum/p9sk1.c
@@ -139,11 +139,14 @@ p9skclient(Conv *c)
 
 	/* success */
 	c->attr = addcap(c->attr, c->sysuser, &t);
+	flog("p9skclient success %A", c->attr);	/* before adding secret! */
 	des56to64((uchar*)t.key, secret);
 	c->attr = addattr(c->attr, "secret=%.8H", secret);
 	ret = 0;
 
 out:
+	if(ret < 0)
+		flog("p9skclient: %r");
 	freeattr(a);
 	keyclose(k);
 	return ret;
@@ -214,11 +217,14 @@ p9skserver(Conv *c)
 
 	/* success */
 	c->attr = addcap(c->attr, c->sysuser, &t);
+	flog("p9skserver success %A", c->attr);	/* before adding secret! */
 	des56to64((uchar*)t.key, secret);
 	c->attr = addattr(c->attr, "secret=%.8H", secret);
 	ret = 0;
 
 out:
+	if(ret < 0)
+		flog("p9skserver: %r");
 	freeattr(a);
 	keyclose(k);
 	return ret;
blob - 315de0eb696487ca624f2b181672b766c538831a
blob + c9009ee2809e54250d0cd55737d83ee11cfc9beb
--- src/cmd/auth/factotum/secstore.c
+++ src/cmd/auth/factotum/secstore.c
@@ -48,14 +48,17 @@ havesecstore(void)
 	if(fd < 0){
 		if(debug)
 			fprint(2, "secdial: %r\n");
+		flog("secdial: %r");
 		return 0;
 	}
 	if(write(fd, buf, n) != n || readn(fd, buf, 2) != 2){
+		flog("secstore: no count");
 		close(fd);
 		return 0;
 	}
 	n = ((buf[0]&0x7f)<<8) + buf[1];
 	if(n+1 > sizeof buf){
+		flog("secstore: bad count");
 		werrstr("implausibly large count %d", n);
 		close(fd);
 		return 0;
@@ -63,16 +66,23 @@ havesecstore(void)
 	m = readn(fd, buf, n);
 	close(fd);
 	if(m != n){
+		flog("secstore: unexpected eof");
 		if(m >= 0)
 			werrstr("short read from secstore");
 		return 0;
 	}
 	buf[n] = 0;
 	if(strcmp((char*)buf, "!account expired") == 0){
+		flog("secstore: account expired");
 		werrstr("account expired");
 		return 0;
 	}
-	return strcmp((char*)buf, "!account exists") == 0;
+	if(strcmp((char*)buf, "!account exists") == 0){
+		flog("secstore: account exists");
+		return 1;
+	}
+	flog("secstore: %s", buf);
+	return 0;
 }
 
 /* delimited, authenticated, encrypted connection */
@@ -384,8 +394,10 @@ getfile(SConn *conn, uchar *key, int nkey)
 		if(q = strchr(p, '\n'))
 			*q++ = '\0';
 		n++;
-		if(ctlwrite(p) < 0)
+		if(ctlwrite(p) < 0){
+			flog("secstore %s:%d: %r", gf, n);
 			fprint(2, "secstore(%s) line %d: %r\n", gf, n);
+		}
 		p = q;
 	}
 	free(buf);
@@ -636,6 +648,8 @@ secstorefetch(void)
 	rv = 0;
 
 Out:
+	if(rv < 0)
+		flog("secstorefetch: %r");
 	if(conn)
 		conn->free(conn);
 	if(pass)
blob - 1a8c252c6ca8b7a54174fff0326bd06f3d604952
blob + 8ec375ce6c0ac26cb46bc8ce4f0f264aa316381c
--- src/libbio/binit.c
+++ src/libbio/binit.c
@@ -122,13 +122,13 @@ Bopen(char *name, int mode)
 		return 0;
 
 	case OREAD:
-		f = open(name, OREAD);
+		f = open(name, mode);
 		if(f < 0)
 			return 0;
 		break;
 
 	case OWRITE:
-		f = creat(name, 0666);
+		f = create(name, mode, 0666);
 		if(f < 0)
 			return 0;
 	}
blob - df28aaf76ab1f27f47f6c9c2c39ef8bafde3cae7
blob + 88c4c3587829abc05bc30334811525b80c0fa51f
--- src/libbio/boffset.c
+++ src/libbio/boffset.c
@@ -1,10 +1,10 @@
 #include	"lib9.h"
 #include	<bio.h>
 
-off_t
+vlong
 Boffset(Biobuf *bp)
 {
-	off_t n;
+	vlong n;
 
 	switch(bp->state) {
 	default:
blob - 4e79affdf78b453823d1008793f09f3b65e75f9c
blob + b3f8191a625b48baa4ae9c9a87a4a198cd52553e
--- src/libbio/bseek.c
+++ src/libbio/bseek.c
@@ -1,8 +1,8 @@
 #include	"lib9.h"
 #include	<bio.h>
 
-off_t
-Bseek(Biobuf *bp, off_t offset, int base)
+long long
+Bseek(Biobuf *bp, long long offset, int base)
 {
 	vlong n, d;
 	int bufsz;
@@ -52,7 +52,7 @@ Bseek(Biobuf *bp, off_t offset, int base)
 
 	case Bwactive:
 		Bflush(bp);
-		n = lseek(bp->fid, offset, base);
+		n = seek(bp->fid, offset, base);
 		break;
 	}
 	bp->offset = n;
blob - 44218fd695cf727a8a4bbd9bf8f4d4d3ca7443ce
blob + 180471e16c78f0e1e559670b2be3083d2640958f
--- src/libbio/lib9.std.h
+++ src/libbio/lib9.std.h
@@ -1,3 +1,6 @@
+#define _FILE_OFFSET_BITS 64
+#define _LARGEFILE64_SOURCE
+
 #include <utf.h>
 #include <fmt.h>
 
@@ -13,8 +16,11 @@
 #define	ORCLOSE	0
 #define	OTRUNC	0
 
-
 #define nil ((void*)0)
 
 typedef long long vlong;
 typedef unsigned long long uvlong;
+
+#define seek(fd, offset, whence) lseek(fd, offset, whence)
+#define create(name, mode, perm) creat(name, perm)
+
blob - 40b38104991f9058063d83d50e5165193847b0df
blob + 6784dab4009c0225a1f63056587202ab9a60e5e6
--- src/libdiskfs/hfs.c
+++ src/libdiskfs/hfs.c
@@ -268,8 +268,8 @@ hfsmetadir(Hfs *fs)
 	Inode ino;
 
 	key.parent = RootId;
-	key.name.len = nelem(name);
-	memcpy(key.name.name, name, sizeof name);
+	key.u.name.len = nelem(name);
+	memcpy(key.u.name.name, name, sizeof name);
 	if(hfscatsearch(fs, &key, &ref) < 0)
 		goto notfound;
 	if(getcatalogrecord(&ino, ref.data, ref.dlen) < 0)
@@ -344,15 +344,15 @@ hfsblockread(Fsys *fsys, u64int vbno)
 static int
 hasresource(Inode *ino)
 {
-	return (ino->mode&IFMT)==IFREG && ino->rfork.size>0;
+	return (ino->mode&IFMT)==IFREG && ino->u.f.rfork.size>0;
 }
 
 static void
 useresource(Inode *ino)
 {
 	ino->fileid = ((u64int)1)<<32 | ino->cnid;
-	ino->nhdr = Adlen;
-	ino->fork = &ino->rfork;
+	ino->u.f.nhdr = Adlen;
+	ino->u.f.fork = &ino->u.f.rfork;
 }
 
 static int
@@ -367,12 +367,12 @@ ref2ino(Hfs *fs, Treeref *ref, Inode *ino)
 		return -1;
 
 	if((ino->mode&IFMT) == IFREG
-	&& memcmp(ino->info, magic, nelem(magic)) == 0){
+	&& memcmp(ino->u.f.info, magic, nelem(magic)) == 0){
 		if(debug) print("iNode%ud...", ino->special);
 		if(fs->hlinkparent == 0)
 			return -1;
 		key.parent = fs->hlinkparent;
-		key.name.len = runesnprint(key.name.name, sizeof key.name.name,
+		key.u.name.len = runesnprint(key.u.name.name, sizeof key.u.name.name,
 			"iNode%ud", ino->special);
 		if(hfscatsearch(fs, &key, &hlink) < 0)
 			goto error;
@@ -428,14 +428,14 @@ handle2ino(Hfs *fs, Nfs3Handle *h, Treeref *ref, Catal
 
 	/* map cnid to full catalog key */
 	key->parent = cnid;
-	key->name.len = 0;
+	key->u.name.len = 0;
 	if(hfscatsearch(fs, key, ref) < 0)
 		goto error;
 	if(getcatalogthread(key, ref->data, ref->dlen) < 0)
 		goto error;
 	hfsrefput(ref);
 
-	if(debug) print("{%ud,%.*S}...", key->parent, key->name.len, key->name.name);
+	if(debug) print("{%ud,%.*S}...", key->parent, key->u.name.len, key->u.name.name);
 
 	/* map full key to catalog info */
 	if(hfscatsearch(fs, key, ref) < 0)
@@ -499,8 +499,8 @@ ino2attr(Hfs *fs, Inode *ino, Nfs3Attr *attr)
 	attr->uid = ino->uid;
 	attr->gid = ino->gid;
 	if(attr->type==Nfs3FileReg || attr->type==Nfs3FileSymlink){
-		attr->size = ino->nhdr+ino->fork->size;
-		attr->used = (u64int)ino->fork->nblocks*fs->blocksize;
+		attr->size = ino->u.f.nhdr+ino->u.f.fork->size;
+		attr->used = (u64int)ino->u.f.fork->nblocks*fs->blocksize;
 	}
 	else{
 		attr->size = 0;
@@ -694,7 +694,7 @@ _hfslookup(Hfs *fs, u32int parent, char *name, Treeref
 	Nfs3Status ok;
 
 	key.parent = parent;
-	if((ok = utf2name(&key.name, name)) != Nfs3Ok)
+	if((ok = utf2name(&key.u.name, name)) != Nfs3Ok)
 		return ok;
 	if(hfscatsearch(fs, &key, ref) < 0)
 		return Nfs3ErrNoEnt;
@@ -745,9 +745,9 @@ hfsreaddir(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h,
 	if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok)
 		return ok;
 
-	if(ino.nentries>>31)
+	if(ino.u.nentries>>31)
 		return Nfs3ErrIo;
-	nentries = ino.nentries*2;	/* even data, odd resource */
+	nentries = ino.u.nentries*2;	/* even data, odd resource */
 	
 	i = cookie>>32;
 	cnid = cookie&0xFFFFFFFF;
@@ -772,7 +772,7 @@ hfsreaddir(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h,
 	*/
 	if(cnid == 0){
 		key.parent = ino.cnid;
-		key.name.len = 0;
+		key.u.name.len = 0;
 		if(hfscatsearch(fs, &key, &ref) < 0)
 			goto error;
 	}
@@ -802,16 +802,16 @@ hfsreaddir(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h,
 			continue;
 		else
 			useresource(&child);
-		if(hfshidename(&key.name))
+		if(hfshidename(&key.u.name))
 			continue;
 		e.fileid = child.fileid;
 		e.name = name;
 		if(rsrc){
 			memcpy(name, Rprefix, Rplen);
-			e.namelen = Rplen+name2utf(name+Rplen, &key.name);
+			e.namelen = Rplen+name2utf(name+Rplen, &key.u.name);
 		}
 		else
-			e.namelen = name2utf(name, &key.name);
+			e.namelen = name2utf(name, &key.u.name);
 		e.cookie = ((u64int)i)<<32 | child.cnid;
 		e.haveAttr = (ino2attr(fs, &child, &e.attr) == Nfs3Ok);
 		e.haveHandle = 1;
@@ -830,7 +830,7 @@ hfsreaddir(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h,
 
 badparent:
 	if(debug) fprint(2, "%.*S: bad parent %ud != %ud\n",
-		key.name.len, key.name.name, key.parent, ino.cnid);
+		key.u.name.len, key.u.name.name, key.parent, ino.cnid);
 error:
 	hfsrefput(&ref);
 	return Nfs3ErrIo;
@@ -852,13 +852,13 @@ appledouble(Inode *ino, uchar *ad)
 			0,0,0,Adlen,		/* offset */
 	};
 
-	if(ino->rfork.size>>32){
+	if(ino->u.f.rfork.size>>32){
 		if(debug) fprint(2, "resource fork %ud too large\n", ino->cnid);
 		return -1;
 	}
 	memcpy(ad, Adhdr, nelem(Adhdr));
-	put32(ad+nelem(Adhdr), ino->rfork.size);
-	memcpy(ad+Fioff, ino->info, Filen);
+	put32(ad+nelem(Adhdr), ino->u.f.rfork.size);
+	memcpy(ad+Fioff, ino->u.f.info, Filen);
 	return 0;
 }
 
@@ -883,7 +883,7 @@ hfsreadfile(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h
 	if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok)
 		return ok;
 
-	size = ino.nhdr+ino.fork->size;
+	size = ino.u.f.nhdr+ino.u.f.fork->size;
 	if(offset >= size){
 		*pdata = 0;
 		*pcount = 0;
@@ -895,7 +895,7 @@ hfsreadfile(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h
 	data = mallocz(count, 1);
 	if(data == nil)
 		return Nfs3ErrNoMem;
-	if(offset < ino.nhdr){
+	if(offset < ino.u.f.nhdr){
 		if(appledouble(&ino, prefix) < 0)
 			goto error;
 		skip = Adlen-offset;
@@ -905,10 +905,10 @@ hfsreadfile(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h
 		offset = 0;
 	}
 	else{
-		offset -= ino.nhdr;
+		offset -= ino.u.f.nhdr;
 		skip = 0;
 	}
-	if(hfsforkread(fs, ino.fork, data+skip, count-skip, offset) < 0)
+	if(hfsforkread(fs, ino.u.f.fork, data+skip, count-skip, offset) < 0)
 		goto error;
 
 	*peof = (offset+count == size);
@@ -940,14 +940,14 @@ hfsreadlink(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h
 	if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok)
 		return ok;
 
-	len = ino.dfork.size;
+	len = ino.u.f.dfork.size;
 	if(len > 10240)	/* arbitrary limit */
 		return Nfs3ErrIo;
 
 	data = mallocz(len+1, 1);
 	if(data == nil)
 		return Nfs3ErrNoMem;
-	if(hfsforkread(fs, &ino.dfork, data, len, 0) < 0){
+	if(hfsforkread(fs, &ino.u.f.dfork, data, len, 0) < 0){
 		free(data);
 		return Nfs3ErrIo;
 	}
@@ -1048,12 +1048,12 @@ _hfscatalogkeycmp(uchar *buf, int len, int *order, Key
 
 	diff = a.parent - b->parent;
 	if(diff == 0){
-		if(getname(&a.name, a.b) < 0)
+		if(getname(&a.u.name, a.u.b) < 0)
 			return -1;
 		if(sensitive)
-			diff = hfsnamecmp(&a.name, &b->name);
+			diff = hfsnamecmp(&a.u.name, &b->u.name);
 		else
-			diff = hfsinamecmp(&a.name, &b->name);
+			diff = hfsinamecmp(&a.u.name, &b->u.name);
 	}
 	*order = diff;
 	return 0;
@@ -1427,13 +1427,13 @@ getcatalogrecord(Inode *ino, uchar *b, int blen)
 	ino->mode = get16(p+10);
 	ino->special = get32(p+12);
 	if(t == Folder)
-		ino->nentries = get32(b+4);
+		ino->u.nentries = get32(b+4);
 	else{
-		getfork(&ino->dfork, ino->cnid, Dfork, b+88);
-		getfork(&ino->rfork, ino->cnid, Rfork, b+168);
-		memcpy(ino->info, b+48, Filen);
-		ino->nhdr = 0;
-		ino->fork = &ino->dfork;
+		getfork(&ino->u.f.dfork, ino->cnid, Dfork, b+88);
+		getfork(&ino->u.f.rfork, ino->cnid, Rfork, b+168);
+		memcpy(ino->u.f.info, b+48, Filen);
+		ino->u.f.nhdr = 0;
+		ino->u.f.fork = &ino->u.f.dfork;
 	}
 	return 0;
 }
@@ -1464,8 +1464,8 @@ getcatalogkey(Catalogkey *k, uchar *b, int blen, int d
 	}
 	k->parent = get32(b+2);
 	if(decode)
-		return getname(&k->name, b+6);
-	k->b = b+6;
+		return getname(&k->u.name, b+6);
+	k->u.b = b+6;
 	return 0;
 }
 
blob - a8a7943e4d240a564273d3c7f2ccf17d10801a52
blob + 662c33895eda4c70f41827bb7112f9f2fb829832
--- src/libdiskfs/hfs.h
+++ src/libdiskfs/hfs.h
@@ -135,8 +135,8 @@ struct Inode
 			/* in memory only */
 			int	nhdr;		/* 0 or Adlen */
 			Fork	*fork;		/* dfork or rfork */
-		};
-	};
+		} f;
+	} u;
 };
 
 struct Tree
@@ -200,7 +200,7 @@ struct Catalogkey
 	union{
 		Name	name;
 		uchar	*b;		/* not yet decoded */
-	};
+	} u;
 };
 
 struct Hfs