tmerge - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 5f6612babbd9e6c0a4a204db0f9d2f286ec58261
 (DIR) parent 518f0a1d31c58266a12ee76c90180d66fde57bb4
 (HTM) Author: Russ Cox <rsc@swtch.com>
       Date:   Sat, 31 May 2008 12:09:43 -0400
       
       merge
       
       Diffstat:
         M bin/9c                              |       2 +-
         M src/cmd/auth/factotum/confirm.c     |      13 ++++++++++++-
         M src/cmd/auth/factotum/conv.c        |      18 ++++++++++++++++++
         M src/cmd/auth/factotum/ctl.c         |       8 ++++++++
         M src/cmd/auth/factotum/fs.c          |       5 +++++
         M src/cmd/auth/factotum/key.c         |       2 ++
         M src/cmd/auth/factotum/log.c         |       2 +-
         M src/cmd/auth/factotum/p9sk1.c       |       6 ++++++
         M src/cmd/auth/factotum/secstore.c    |      18 ++++++++++++++++--
         M src/libbio/binit.c                  |       4 ++--
         M src/libbio/boffset.c                |       4 ++--
         M src/libbio/bseek.c                  |       6 +++---
         M src/libbio/lib9.std.h               |       8 +++++++-
         M src/libdiskfs/hfs.c                 |      78 ++++++++++++++++----------------
         M src/libdiskfs/hfs.h                 |       6 +++---
       
       15 files changed, 125 insertions(+), 55 deletions(-)
       ---
 (DIR) diff --git a/bin/9c b/bin/9c
       t@@ -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
 (DIR) diff --git a/src/cmd/auth/factotum/confirm.c b/src/cmd/auth/factotum/confirm.c
       t@@ -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;
                }
       t@@ -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;
                }
       t@@ -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;
       t@@ -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);
        }
        
       t@@ -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);
        }
 (DIR) diff --git a/src/cmd/auth/factotum/conv.c b/src/cmd/auth/factotum/conv.c
       t@@ -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;
                                }
       t@@ -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;
        }
        
       t@@ -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)
 (DIR) diff --git a/src/cmd/auth/factotum/ctl.c b/src/cmd/auth/factotum/ctl.c
       t@@ -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;
                                }
       t@@ -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;
                                        }
       t@@ -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);
                        }
       t@@ -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");
       t@@ -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]));
       t@@ -161,6 +168,7 @@ ctlwrite(char *a)
                        return 0;
                case 2:        /* debug */
                        debug ^= 1;
       +                flog("debug = %d", debug);
                        return 0;
                }
        }
 (DIR) diff --git a/src/cmd/auth/factotum/fs.c b/src/cmd/auth/factotum/fs.c
       t@@ -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:
       t@@ -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);
       t@@ -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);
 (DIR) diff --git a/src/cmd/auth/factotum/key.c b/src/cmd/auth/factotum/key.c
       t@@ -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++){
       t@@ -80,6 +81,7 @@ keyfetch(Conv *c, char *fmt, ...)
                                        continue;
                                }
                                freeattr(a);
       +                        flog("using key %A %N", k->attr, k->privattr);
                                return k;
                        }
                }
 (DIR) diff --git a/src/cmd/auth/factotum/log.c b/src/cmd/auth/factotum/log.c
       t@@ -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])
 (DIR) diff --git a/src/cmd/auth/factotum/p9sk1.c b/src/cmd/auth/factotum/p9sk1.c
       t@@ -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;
       t@@ -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;
 (DIR) diff --git a/src/cmd/auth/factotum/secstore.c b/src/cmd/auth/factotum/secstore.c
       t@@ -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;
       t@@ -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 */
       t@@ -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);
       t@@ -636,6 +648,8 @@ secstorefetch(void)
                rv = 0;
        
        Out:
       +        if(rv < 0)
       +                flog("secstorefetch: %r");
                if(conn)
                        conn->free(conn);
                if(pass)
 (DIR) diff --git a/src/libbio/binit.c b/src/libbio/binit.c
       t@@ -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;
                }
 (DIR) diff --git a/src/libbio/boffset.c b/src/libbio/boffset.c
       t@@ -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:
 (DIR) diff --git a/src/libbio/bseek.c b/src/libbio/bseek.c
       t@@ -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;
       t@@ -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;
 (DIR) diff --git a/src/libbio/lib9.std.h b/src/libbio/lib9.std.h
       t@@ -1,3 +1,6 @@
       +#define _FILE_OFFSET_BITS 64
       +#define _LARGEFILE64_SOURCE
       +
        #include <utf.h>
        #include <fmt.h>
        
       t@@ -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)
       +
 (DIR) diff --git a/src/libdiskfs/hfs.c b/src/libdiskfs/hfs.c
       t@@ -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)
       t@@ -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
       t@@ -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;
       t@@ -428,14 +428,14 @@ handle2ino(Hfs *fs, Nfs3Handle *h, Treeref *ref, Catalogkey *key, Inode *ino)
        
                /* 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)
       t@@ -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;
       t@@ -694,7 +694,7 @@ _hfslookup(Hfs *fs, u32int parent, char *name, Treeref *ref)
                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;
       t@@ -745,9 +745,9 @@ hfsreaddir(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count,
                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;
       t@@ -772,7 +772,7 @@ hfsreaddir(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count,
                */
                if(cnid == 0){
                        key.parent = ino.cnid;
       -                key.name.len = 0;
       +                key.u.name.len = 0;
                        if(hfscatsearch(fs, &key, &ref) < 0)
                                goto error;
                }
       t@@ -802,16 +802,16 @@ hfsreaddir(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count,
                                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;
       t@@ -830,7 +830,7 @@ hfsreaddir(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count,
        
        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;
       t@@ -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;
        }
        
       t@@ -883,7 +883,7 @@ hfsreadfile(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count,
                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;
       t@@ -895,7 +895,7 @@ hfsreadfile(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count,
                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;
       t@@ -905,10 +905,10 @@ hfsreadfile(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count,
                        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);
       t@@ -940,14 +940,14 @@ hfsreadlink(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char **link)
                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;
                }
       t@@ -1048,12 +1048,12 @@ _hfscatalogkeycmp(uchar *buf, int len, int *order, Key *key, int sensitive)
        
                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;
       t@@ -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;
        }
       t@@ -1464,8 +1464,8 @@ getcatalogkey(Catalogkey *k, uchar *b, int blen, int decode)
                }
                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;
        }
        
 (DIR) diff --git a/src/libdiskfs/hfs.h b/src/libdiskfs/hfs.h
       t@@ -135,8 +135,8 @@ struct Inode
                                /* in memory only */
                                int        nhdr;                /* 0 or Adlen */
                                Fork        *fork;                /* dfork or rfork */
       -                };
       -        };
       +                } f;
       +        } u;
        };
        
        struct Tree
       t@@ -200,7 +200,7 @@ struct Catalogkey
                union{
                        Name        name;
                        uchar        *b;                /* not yet decoded */
       -        };
       +        } u;
        };
        
        struct Hfs