from Mike Hibler
authorKirk McKusick <mckusick@ucbvax.Berkeley.EDU>
Sat, 22 Jan 1994 10:29:00 +0000 (02:29 -0800)
committerKirk McKusick <mckusick@ucbvax.Berkeley.EDU>
Sat, 22 Jan 1994 10:29:00 +0000 (02:29 -0800)
SCCS-vsn: sys/isofs/cd9660/iso.h 8.1
SCCS-vsn: sys/isofs/cd9660/iso_rrip.h 8.1
SCCS-vsn: sys/isofs/cd9660/cd9660_bmap.c 8.1
SCCS-vsn: sys/isofs/cd9660/cd9660_lookup.c 8.1
SCCS-vsn: sys/isofs/cd9660/cd9660_node.c 8.1
SCCS-vsn: sys/isofs/cd9660/cd9660_node.h 8.1
SCCS-vsn: sys/isofs/cd9660/cd9660_rrip.c 8.1
SCCS-vsn: sys/isofs/cd9660/cd9660_rrip.h 8.1
SCCS-vsn: sys/isofs/cd9660/cd9660_util.c 8.1
SCCS-vsn: sys/isofs/cd9660/cd9660_vfsops.c 8.1
SCCS-vsn: sys/isofs/cd9660/cd9660_vnops.c 8.1

usr/src/sys/isofs/cd9660/cd9660_bmap.c [new file with mode: 0644]
usr/src/sys/isofs/cd9660/cd9660_lookup.c [new file with mode: 0644]
usr/src/sys/isofs/cd9660/cd9660_node.c [new file with mode: 0644]
usr/src/sys/isofs/cd9660/cd9660_node.h [new file with mode: 0644]
usr/src/sys/isofs/cd9660/cd9660_rrip.c [new file with mode: 0644]
usr/src/sys/isofs/cd9660/cd9660_rrip.h [new file with mode: 0644]
usr/src/sys/isofs/cd9660/cd9660_util.c [new file with mode: 0644]
usr/src/sys/isofs/cd9660/cd9660_vfsops.c [new file with mode: 0644]
usr/src/sys/isofs/cd9660/cd9660_vnops.c [new file with mode: 0644]
usr/src/sys/isofs/cd9660/iso.h [new file with mode: 0644]
usr/src/sys/isofs/cd9660/iso_rrip.h [new file with mode: 0644]

diff --git a/usr/src/sys/isofs/cd9660/cd9660_bmap.c b/usr/src/sys/isofs/cd9660/cd9660_bmap.c
new file mode 100644 (file)
index 0000000..db77d88
--- /dev/null
@@ -0,0 +1,82 @@
+/*-
+ * Copyright (c) 1994
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley
+ * by Pace Willisson (pace@blitz.com).  The Rock Ridge Extension
+ * Support code is derived from software contributed to Berkeley
+ * by Atsushi Murai (amurai@spec.co.jp).
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)cd9660_bmap.c       8.1 (Berkeley) %G%
+ */
+
+#include <sys/param.h>
+#include <sys/namei.h>
+#include <sys/buf.h>
+#include <sys/file.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+
+#include <isofs/cd9660/iso.h>
+#include <isofs/cd9660/isofs_node.h>
+
+/*
+ * Bmap converts a the logical block number of a file to its physical block
+ * number on the disk. The conversion is done by using the logical block
+ * number to index into the data block (extent) for the file.
+ */
+int
+isofs_bmap(ap)
+       struct vop_bmap_args /* {
+               struct vnode *a_vp;
+               daddr_t  a_bn;
+               struct vnode **a_vpp;
+               daddr_t *a_bnp;
+               int *a_runp;
+       } */ *ap;
+{
+       struct iso_node *ip = VTOI(ap->a_vp);
+       daddr_t lblkno = ap->a_bn;
+       long bsize;
+
+       /*
+        * Check for underlying vnode requests and ensure that logical
+        * to physical mapping is requested.
+        */
+       if (ap->a_vpp != NULL)
+               *ap->a_vpp = ip->i_devvp;
+       if (ap->a_bnp == NULL)
+               return (0);
+
+       /*
+        * Compute the requested block number
+        */
+       bsize = ip->i_mnt->logical_block_size;
+       *ap->a_bnp = (ip->iso_start + lblkno) * btodb(bsize);
+
+       /*
+        * Determine maximum number of readahead blocks following the
+        * requested block.
+        */
+       if (ap->a_runp) {
+               int nblk;
+
+               nblk = (ip->i_size - (lblkno + 1) * bsize) / bsize;
+               if (nblk <= 0)
+                       *ap->a_runp = 0;
+               else if (nblk >= MAXBSIZE/bsize)
+                       *ap->a_runp = MAXBSIZE/bsize - 1;
+               else
+                       *ap->a_runp = nblk;
+{
+extern int doclusterread;
+if (doclusterread)
+printf("ip=%x, size=%x, lblkno=%x, runp=%x\n",
+ip, ip->i_size, lblkno, *ap->a_runp);
+}
+       }
+
+       return 0;
+}
diff --git a/usr/src/sys/isofs/cd9660/cd9660_lookup.c b/usr/src/sys/isofs/cd9660/cd9660_lookup.c
new file mode 100644 (file)
index 0000000..8e84ae7
--- /dev/null
@@ -0,0 +1,439 @@
+/*-
+ * Copyright (c) 1989, 1993, 1994
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley
+ * by Pace Willisson (pace@blitz.com).  The Rock Ridge Extension
+ * Support code is derived from software contributed to Berkeley
+ * by Atsushi Murai (amurai@spec.co.jp).
+ *
+ * %sccs.include.redist.c%
+ *
+ *     from: @(#)ufs_lookup.c  7.33 (Berkeley) 5/19/91
+ *
+ *     @(#)cd9660_lookup.c     8.1 (Berkeley) %G%
+ */
+
+#include <sys/param.h>
+#include <sys/namei.h>
+#include <sys/buf.h>
+#include <sys/file.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+
+#include <isofs/cd9660/iso.h>
+#include <isofs/cd9660/isofs_node.h>
+#include <isofs/cd9660/iso_rrip.h>
+#include <isofs/cd9660/isofs_rrip.h>
+
+struct nchstats iso_nchstats;
+
+/*
+ * Convert a component of a pathname into a pointer to a locked inode.
+ * This is a very central and rather complicated routine.
+ * If the file system is not maintained in a strict tree hierarchy,
+ * this can result in a deadlock situation (see comments in code below).
+ *
+ * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
+ * whether the name is to be looked up, created, renamed, or deleted.
+ * When CREATE, RENAME, or DELETE is specified, information usable in
+ * creating, renaming, or deleting a directory entry may be calculated.
+ * If flag has LOCKPARENT or'ed into it and the target of the pathname
+ * exists, lookup returns both the target and its parent directory locked.
+ * When creating or renaming and LOCKPARENT is specified, the target may
+ * not be ".".  When deleting and LOCKPARENT is specified, the target may
+ * be "."., but the caller must check to ensure it does an vrele and iput
+ * instead of two iputs.
+ *
+ * Overall outline of ufs_lookup:
+ *
+ *     check accessibility of directory
+ *     look for name in cache, if found, then if at end of path
+ *       and deleting or creating, drop it, else return name
+ *     search for name in directory, to found or notfound
+ * notfound:
+ *     if creating, return locked directory, leaving info on available slots
+ *     else return error
+ * found:
+ *     if at end of path and deleting, return information to allow delete
+ *     if at end of path and rewriting (RENAME and LOCKPARENT), lock target
+ *       inode and return info to allow rewrite
+ *     if not at end, add name to cache; if at end and neither creating
+ *       nor deleting, add name to cache
+ *
+ * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent inode unlocked.
+ */
+isofs_lookup(ap)
+       struct vop_lookup_args /* {
+               struct vnode *a_dvp;
+               struct vnode **a_vpp;
+               struct componentname *a_cnp;
+       } */ *ap;
+{
+       register struct vnode *vdp;     /* vnode for directory being searched */
+       register struct iso_node *dp;   /* inode for directory being searched */
+       register struct iso_mnt *imp;   /* file system that directory is in */
+       struct buf *bp;                 /* a buffer of directory entries */
+       struct iso_directory_record *ep;/* the current directory entry */
+       int entryoffsetinblock;         /* offset of ep in bp's buffer */
+       int saveoffset;                 /* offset of last directory entry in dir */
+       int numdirpasses;               /* strategy for directory search */
+       doff_t endsearch;               /* offset to end directory search */
+       struct iso_node *pdp;           /* saved dp during symlink work */
+       struct iso_node *tdp;           /* returned by iget */
+       int lockparent;                 /* 1 => lockparent flag is set */
+       int wantparent;                 /* 1 => wantparent or lockparent flag */
+       int error;
+       ino_t ino = 0;
+       int reclen;
+       u_short namelen;
+       char altname[NAME_MAX];
+       int res;
+       int assoc, len;
+       char *name;
+       struct vnode **vpp = ap->a_vpp;
+       struct componentname *cnp = ap->a_cnp;
+       struct ucred *cred = cnp->cn_cred;
+       int flags = cnp->cn_flags;
+       int nameiop = cnp->cn_nameiop;
+       
+       bp = NULL;
+       *vpp = NULL;
+       vdp = ap->a_dvp;
+       dp = VTOI(vdp);
+       imp = dp->i_mnt;
+       lockparent = flags & LOCKPARENT;
+       wantparent = flags & (LOCKPARENT|WANTPARENT);
+       
+       /*
+        * Check accessiblity of directory.
+        */
+       if (vdp->v_type != VDIR)
+           return (ENOTDIR);
+       if (error = VOP_ACCESS(vdp, VEXEC, cred, cnp->cn_proc))
+               return (error);
+       
+       /*
+        * We now have a segment name to search for, and a directory to search.
+        *
+        * Before tediously performing a linear scan of the directory,
+        * check the name cache to see if the directory/name pair
+        * we are looking for is known already.
+        */
+       if (error = cache_lookup(vdp, vpp, cnp)) {
+               int vpid;       /* capability number of vnode */
+
+               if (error == ENOENT)
+                       return (error);
+#ifdef PARANOID
+               if ((vdp->v_flag & VROOT) && (flags & ISDOTDOT))
+                       panic("ufs_lookup: .. through root");
+#endif
+               /*
+                * Get the next vnode in the path.
+                * See comment below starting `Step through' for
+                * an explaination of the locking protocol.
+                */
+               pdp = dp;
+               dp = VTOI(*vpp);
+               vdp = *vpp;
+               vpid = vdp->v_id;
+               if (pdp == dp) {
+                       VREF(vdp);
+                       error = 0;
+               } else if (flags & ISDOTDOT) {
+                       ISO_IUNLOCK(pdp);
+                       error = vget(vdp, 1);
+                       if (!error && lockparent && (flags & ISLASTCN))
+                               ISO_ILOCK(pdp);
+               } else {
+                       error = vget(vdp, 1);
+                       if (!lockparent || error || !(flags & ISLASTCN))
+                               ISO_IUNLOCK(pdp);
+               }
+               /*
+                * Check that the capability number did not change
+                * while we were waiting for the lock.
+                */
+               if (!error) {
+                       if (vpid == vdp->v_id)
+                               return (0);
+                       iso_iput(dp);
+                       if (lockparent && pdp != dp && (flags & ISLASTCN))
+                               ISO_IUNLOCK(pdp);
+               }
+               ISO_ILOCK(pdp);
+               dp = pdp;
+               vdp = ITOV(dp);
+               *vpp = NULL;
+       }
+       
+       len = cnp->cn_namelen;
+       name = cnp->cn_nameptr;
+       /*
+        * A leading `=' means, we are looking for an associated file
+        */
+       if (assoc = (imp->iso_ftype != ISO_FTYPE_RRIP && *name == ASSOCCHAR)) {
+               len--;
+               name++;
+       }
+       
+       /*
+        * If there is cached information on a previous search of
+        * this directory, pick up where we last left off.
+        * We cache only lookups as these are the most common
+        * and have the greatest payoff. Caching CREATE has little
+        * benefit as it usually must search the entire directory
+        * to determine that the entry does not exist. Caching the
+        * location of the last DELETE or RENAME has not reduced
+        * profiling time and hence has been removed in the interest
+        * of simplicity.
+        */
+       if (nameiop != LOOKUP || dp->i_diroff == 0 ||
+           dp->i_diroff > dp->i_size) {
+               entryoffsetinblock = 0;
+               dp->i_offset = 0;
+               numdirpasses = 1;
+       } else {
+               dp->i_offset = dp->i_diroff;
+               entryoffsetinblock = iso_blkoff(imp, dp->i_offset);
+               if (entryoffsetinblock != 0) {
+                       if (error = iso_blkatoff(dp, dp->i_offset, &bp))
+                               return (error);
+               }
+               numdirpasses = 2;
+               iso_nchstats.ncs_2passes++;
+       }
+       endsearch = roundup(dp->i_size, imp->logical_block_size);
+       
+searchloop:
+       while (dp->i_offset < endsearch) {
+               /*
+                * If offset is on a block boundary,
+                * read the next directory block.
+                * Release previous if it exists.
+                */
+               if (iso_blkoff(imp, dp->i_offset) == 0) {
+                       if (bp != NULL)
+                               brelse(bp);
+                       if (error = iso_blkatoff(dp, dp->i_offset, &bp))
+                               return (error);
+                       entryoffsetinblock = 0;
+               }
+               /*
+                * Get pointer to next entry.
+                */
+               ep = (struct iso_directory_record *)
+                       (bp->b_un.b_addr + entryoffsetinblock);
+               
+               reclen = isonum_711 (ep->length);
+               if (reclen == 0) {
+                       /* skip to next block, if any */
+                       dp->i_offset =
+                               roundup(dp->i_offset, imp->logical_block_size);
+                       continue;
+               }
+               
+               if (reclen < ISO_DIRECTORY_RECORD_SIZE)
+                       /* illegal entry, stop */
+                       break;
+               
+               if (entryoffsetinblock + reclen > imp->logical_block_size)
+                       /* entries are not allowed to cross boundaries */
+                       break;
+               
+               /*
+                * Check for a name match.
+                */
+               namelen = isonum_711(ep->name_len);
+               
+               if (reclen < ISO_DIRECTORY_RECORD_SIZE + namelen)
+                       /* illegal entry, stop */
+                       break;
+               
+               switch (imp->iso_ftype) {
+               default:
+                       if ((!(isonum_711(ep->flags)&4)) == !assoc) {
+                               if ((len == 1
+                                    && *name == '.')
+                                   || (flags & ISDOTDOT)) {
+                                       if (namelen == 1
+                                           && ep->name[0] == ((flags & ISDOTDOT) ? 1 : 0)) {
+                                               /*
+                                                * Save directory entry's inode number and
+                                                * reclen in ndp->ni_ufs area, and release
+                                                * directory buffer.
+                                                */
+                                               isodirino(&dp->i_ino,ep,imp);
+                                               goto found;
+                                       }
+                                       if (namelen != 1
+                                           || ep->name[0] != 0)
+                                               goto notfound;
+                               } else if (!(res = isofncmp(name,len,
+                                                           ep->name,namelen))) {
+                                       if (isonum_711(ep->flags)&2)
+                                               isodirino(&ino,ep,imp);
+                                       else
+                                               ino = dbtob(bp->b_blkno)
+                                                       + entryoffsetinblock;
+                                       saveoffset = dp->i_offset;
+                               } else if (ino)
+                                       goto foundino;
+#ifdef NOSORTBUG       /* On some CDs directory entries are not sorted correctly */
+                               else if (res < 0)
+                                       goto notfound;
+                               else if (res > 0 && numdirpasses == 2)
+                                       numdirpasses++;
+#endif
+                       }
+                       break;
+               case ISO_FTYPE_RRIP:
+                       if (isonum_711(ep->flags)&2)
+                               isodirino(&ino,ep,imp);
+                       else
+                               ino = dbtob(bp->b_blkno) + entryoffsetinblock;
+                       dp->i_ino = ino;
+                       isofs_rrip_getname(ep,altname,&namelen,&dp->i_ino,imp);
+                       if (namelen == cnp->cn_namelen
+                           && !bcmp(name,altname,namelen))
+                               goto found;
+                       ino = 0;
+                       break;
+               }
+               dp->i_offset += reclen;
+               entryoffsetinblock += reclen;
+       }
+       if (ino) {
+foundino:
+               dp->i_ino = ino;
+               if (saveoffset != dp->i_offset) {
+                       if (iso_lblkno(imp,dp->i_offset)
+                           != iso_lblkno(imp,saveoffset)) {
+                               if (bp != NULL)
+                                       brelse(bp);
+                               if (error = iso_blkatoff(dp, saveoffset, &bp))
+                                       return (error);
+                       }
+                       ep = (struct iso_directory_record *)(bp->b_un.b_addr
+                                                            + iso_blkoff(imp,saveoffset));
+                       dp->i_offset = saveoffset;
+               }
+               goto found;
+       }
+notfound:
+       /*
+        * If we started in the middle of the directory and failed
+        * to find our target, we must check the beginning as well.
+        */
+       if (numdirpasses == 2) {
+               numdirpasses--;
+               dp->i_offset = 0;
+               endsearch = dp->i_diroff;
+               goto searchloop;
+       }
+       if (bp != NULL)
+               brelse(bp);
+       /*
+        * Insert name into cache (as non-existent) if appropriate.
+        */
+       if (cnp->cn_flags & MAKEENTRY)
+               cache_enter(vdp, *vpp, cnp);
+       if (nameiop == CREATE || nameiop == RENAME)
+               return (EJUSTRETURN);
+       return (ENOENT);
+       
+found:
+       if (numdirpasses == 2)
+               iso_nchstats.ncs_pass2++;
+       if (bp != NULL)
+               brelse(bp);
+       
+       /*
+        * Found component in pathname.
+        * If the final component of path name, save information
+        * in the cache as to where the entry was found.
+        */
+       if ((flags & ISLASTCN) && nameiop == LOOKUP)
+               dp->i_diroff = dp->i_offset;
+       
+       /*
+        * Step through the translation in the name.  We do not `iput' the
+        * directory because we may need it again if a symbolic link
+        * is relative to the current directory.  Instead we save it
+        * unlocked as "pdp".  We must get the target inode before unlocking
+        * the directory to insure that the inode will not be removed
+        * before we get it.  We prevent deadlock by always fetching
+        * inodes from the root, moving down the directory tree. Thus
+        * when following backward pointers ".." we must unlock the
+        * parent directory before getting the requested directory.
+        * There is a potential race condition here if both the current
+        * and parent directories are removed before the `iget' for the
+        * inode associated with ".." returns.  We hope that this occurs
+        * infrequently since we cannot avoid this race condition without
+        * implementing a sophisticated deadlock detection algorithm.
+        * Note also that this simple deadlock detection scheme will not
+        * work if the file system has any hard links other than ".."
+        * that point backwards in the directory structure.
+        */
+       pdp = dp;
+       /*
+        * If ino is different from dp->i_ino,
+        * it's a relocated directory.
+        */
+       if (flags & ISDOTDOT) {
+               ISO_IUNLOCK(pdp);       /* race to get the inode */
+               if (error = iso_iget(dp,dp->i_ino,
+                                    dp->i_ino != ino,
+                                    &tdp,ep)) {
+                       ISO_ILOCK(pdp);
+                       return (error);
+               }
+               if (lockparent && (flags & ISLASTCN))
+                       ISO_ILOCK(pdp);
+               *vpp = ITOV(tdp);
+       } else if (dp->i_number == dp->i_ino) {
+               VREF(vdp);      /* we want ourself, ie "." */
+               *vpp = vdp;
+       } else {
+               if (error = iso_iget(dp,dp->i_ino,dp->i_ino!=ino,&tdp,ep))
+                       return (error);
+               if (!lockparent || !(flags & ISLASTCN))
+                       ISO_IUNLOCK(pdp);
+               *vpp = ITOV(tdp);
+       }
+       
+       /*
+        * Insert name into cache if appropriate.
+        */
+       if (cnp->cn_flags & MAKEENTRY)
+               cache_enter(vdp, *vpp, cnp);
+       return (0);
+}
+
+/*
+ * Return buffer with contents of block "offset"
+ * from the beginning of directory "ip".  If "res"
+ * is non-zero, fill it in with a pointer to the
+ * remaining space in the directory.
+ */
+iso_blkatoff(ip, offset, bpp)
+       struct iso_node *ip;
+       doff_t offset;
+       struct buf **bpp;
+{
+       register struct iso_mnt *imp = ip->i_mnt;
+       daddr_t lbn = iso_lblkno(imp,offset);
+       int bsize = iso_blksize(imp,ip,lbn);
+       struct buf *bp;
+       int error;
+       
+       if (error = bread(ITOV(ip),lbn,bsize,NOCRED,&bp)) {
+               brelse(bp);
+               *bpp = 0;
+               return (error);
+       }
+       *bpp = bp;
+       
+       return (0);
+}
diff --git a/usr/src/sys/isofs/cd9660/cd9660_node.c b/usr/src/sys/isofs/cd9660/cd9660_node.c
new file mode 100644 (file)
index 0000000..66d8119
--- /dev/null
@@ -0,0 +1,622 @@
+/*-
+ * Copyright (c) 1982, 1986, 1989, 1994
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley
+ * by Pace Willisson (pace@blitz.com).  The Rock Ridge Extension
+ * Support code is derived from software contributed to Berkeley
+ * by Atsushi Murai (amurai@spec.co.jp).
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)cd9660_node.c       8.1 (Berkeley) %G%
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mount.h>
+#include <sys/proc.h>
+#include <sys/file.h>
+#include <sys/buf.h>
+#include <sys/vnode.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/stat.h>
+
+#include <isofs/cd9660/iso.h>
+#include <isofs/cd9660/isofs_node.h>
+#include <isofs/cd9660/iso_rrip.h>
+
+#define        INOHSZ  512
+#if    ((INOHSZ&(INOHSZ-1)) == 0)
+#define        INOHASH(dev,ino)        (((dev)+((ino)>>12))&(INOHSZ-1))
+#else
+#define        INOHASH(dev,ino)        (((unsigned)((dev)+((ino)>>12)))%INOHSZ)
+#endif
+
+union iso_ihead {
+       union  iso_ihead *ih_head[2];
+       struct iso_node *ih_chain[2];
+} iso_ihead[INOHSZ];
+
+#ifdef ISODEVMAP
+#define        DNOHSZ  64
+#if    ((DNOHSZ&(DNOHSZ-1)) == 0)
+#define        DNOHASH(dev,ino)        (((dev)+((ino)>>12))&(DNOHSZ-1))
+#else
+#define        DNOHASH(dev,ino)        (((unsigned)((dev)+((ino)>>12)))%DNOHSZ)
+#endif
+
+union iso_dhead {
+       union  iso_dhead  *dh_head[2];
+       struct iso_dnode *dh_chain[2];
+} iso_dhead[DNOHSZ];
+#endif
+
+int prtactive; /* 1 => print out reclaim of active vnodes */
+
+/*
+ * Initialize hash links for inodes and dnodes.
+ */
+isofs_init()
+{
+       register int i;
+       register union iso_ihead *ih = iso_ihead;
+#ifdef ISODEVMAP
+       register union iso_dhead *dh = iso_dhead;
+#endif
+
+       for (i = INOHSZ; --i >= 0; ih++) {
+               ih->ih_head[0] = ih;
+               ih->ih_head[1] = ih;
+       }
+#ifdef ISODEVMAP
+       for (i = DNOHSZ; --i >= 0; dh++) {
+               dh->dh_head[0] = dh;
+               dh->dh_head[1] = dh;
+       }
+#endif
+}
+
+#ifdef ISODEVMAP
+/*
+ * Enter a new node into the device hash list
+ */
+struct iso_dnode *
+iso_dmap(dev,ino,create)
+       dev_t   dev;
+       ino_t   ino;
+       int     create;
+{
+       struct iso_dnode *dp;
+       union iso_dhead *dh;
+       
+       dh = &iso_dhead[DNOHASH(dev, ino)];
+       for (dp = dh->dh_chain[0];
+            dp != (struct iso_dnode *)dh;
+            dp = dp->d_forw)
+               if (ino == dp->i_number && dev == dp->i_dev)
+                       return dp;
+
+       if (!create)
+               return (struct iso_dnode *)0;
+
+       MALLOC(dp,struct iso_dnode *,sizeof(struct iso_dnode),M_CACHE,M_WAITOK);
+       dp->i_dev = dev;
+       dp->i_number = ino;
+       insque(dp,dh);
+       
+       return dp;
+}
+
+void
+iso_dunmap(dev)
+       dev_t   dev;
+{
+       struct iso_dnode *dp, *dq;
+       union iso_dhead *dh;
+       
+       for (dh = iso_dhead; dh < iso_dhead + DNOHSZ; dh++) {
+               for (dp = dh->dh_chain[0];
+                    dp != (struct iso_dnode *)dh;
+                    dp = dq) {
+                       dq = dp->d_forw;
+                       if (dev == dp->i_dev) {
+                               remque(dp);
+                               FREE(dp,M_CACHE);
+                       }
+               }
+       }
+}
+#endif
+
+/*
+ * Look up a ISOFS dinode number to find its incore vnode.
+ * If it is not in core, read it in from the specified device.
+ * If it is in core, wait for the lock bit to clear, then
+ * return the inode locked. Detection and handling of mount
+ * points must be done by the calling routine.
+ */
+iso_iget(xp, ino, relocated, ipp, isodir)
+       struct iso_node *xp;
+       ino_t ino;
+       struct iso_node **ipp;
+       struct iso_directory_record *isodir;
+{
+       dev_t dev = xp->i_dev;
+       struct mount *mntp = ITOV(xp)->v_mount;
+       register struct iso_node *ip, *iq;
+       register struct vnode *vp;
+       register struct iso_dnode *dp;
+       struct vnode *nvp;
+       struct buf *bp = NULL, *bp2 = NULL;
+       union iso_ihead *ih;
+       union iso_dhead *dh;
+       int i, error, result;
+       struct iso_mnt *imp;
+       ino_t defino;
+       
+       ih = &iso_ihead[INOHASH(dev, ino)];
+loop:
+       for (ip = ih->ih_chain[0];
+            ip != (struct iso_node *)ih;
+            ip = ip->i_forw) {
+               if (ino != ip->i_number || dev != ip->i_dev)
+                       continue;
+               if ((ip->i_flag&ILOCKED) != 0) {
+                       ip->i_flag |= IWANT;
+                       sleep((caddr_t)ip, PINOD);
+                       goto loop;
+               }
+               if (vget(ITOV(ip), 1))
+                       goto loop;
+               *ipp = ip;
+               return 0;
+       }
+       /*
+        * Allocate a new vnode/iso_node.
+        */
+       if (error = getnewvnode(VT_ISOFS, mntp, isofs_vnodeop_p, &nvp)) {
+               *ipp = 0;
+               return error;
+       }
+       MALLOC(ip, struct iso_node *, sizeof(struct iso_node),
+              M_ISOFSNODE, M_WAITOK);
+       bzero((caddr_t)ip, sizeof(struct iso_node));
+       nvp->v_data = ip;
+       ip->i_vnode = nvp;
+       ip->i_flag = 0;
+       ip->i_devvp = 0;
+       ip->i_diroff = 0;
+       ip->i_lockf = 0;
+       
+       /*
+        * Put it onto its hash chain and lock it so that other requests for
+        * this inode will block if they arrive while we are sleeping waiting
+        * for old data structures to be purged or for the contents of the
+        * disk portion of this inode to be read.
+        */
+       ip->i_dev = dev;
+       ip->i_number = ino;
+       insque(ip, ih);
+       ISO_ILOCK(ip);
+
+       imp = VFSTOISOFS (mntp);
+       ip->i_mnt = imp;
+       ip->i_devvp = imp->im_devvp;
+       VREF(ip->i_devvp);
+       
+       if (relocated) {
+               /*
+                * On relocated directories we must
+                * read the `.' entry out of a dir.
+                */
+               ip->iso_start = ino >> imp->im_bshift;
+               if (error = iso_blkatoff(ip,0,&bp)) {
+                       vrele(ip->i_devvp);
+                       remque(ip);
+                       ip->i_forw = ip;
+                       ip->i_back = ip;
+                       iso_iput(ip);
+                       *ipp = 0;
+                       return error;
+               }
+               isodir = (struct iso_directory_record *)bp->b_un.b_addr;
+       }
+       
+       ip->iso_extent = isonum_733(isodir->extent);
+       ip->i_size = isonum_733(isodir->size);
+       ip->iso_start = isonum_711(isodir->ext_attr_length) + ip->iso_extent;
+       
+       vp = ITOV(ip);
+       
+       /*
+        * Setup time stamp, attribute
+        */
+       vp->v_type = VNON;
+       switch (imp->iso_ftype) {
+       default:        /* ISO_FTYPE_9660 */
+               if ((imp->im_flags&ISOFSMNT_EXTATT)
+                   && isonum_711(isodir->ext_attr_length))
+                       iso_blkatoff(ip,-isonum_711(isodir->ext_attr_length),
+                                    &bp2);
+               isofs_defattr(isodir,ip,bp2 );
+               isofs_deftstamp(isodir,ip,bp2 );
+               break;
+       case ISO_FTYPE_RRIP:
+               result = isofs_rrip_analyze(isodir,ip,imp);
+               break;
+       }
+       if (bp2)
+               brelse(bp2);
+       if (bp)
+               brelse(bp);
+       
+       /*
+        * Initialize the associated vnode
+        */
+       vp->v_type = IFTOVT(ip->inode.iso_mode);
+       
+       if ( vp->v_type == VFIFO ) {
+#ifdef FIFO
+               extern int (**isofs_fifoop_p)();
+               vp->v_op = isofs_fifoop_p;
+#else
+               iso_iput(ip);
+               *ipp = 0;
+               return EOPNOTSUPP;
+#endif /* FIFO */
+       } else if ( vp->v_type == VCHR || vp->v_type == VBLK ) {
+               extern int (**isofs_specop_p)();
+
+               /*
+                * if device, look at device number table for translation
+                */
+#ifdef ISODEVMAP
+               if (dp = iso_dmap(dev,ino,0))
+                       ip->inode.iso_rdev = dp->d_dev;
+#endif
+               vp->v_op = isofs_specop_p;
+               if (nvp = checkalias(vp, ip->inode.iso_rdev, mntp)) {
+                       /*
+                        * Reinitialize aliased inode.
+                        */
+                       vp = nvp;
+                       iq = VTOI(vp);
+                       iq->i_vnode = vp;
+                       iq->i_flag = 0;
+                       ISO_ILOCK(iq);
+                       iq->i_dev = dev;
+                       iq->i_number = ino;
+                       iq->i_mnt = ip->i_mnt;
+                       bcopy(&ip->iso_extent,&iq->iso_extent,
+                             (char *)(ip + 1) - (char *)&ip->iso_extent);
+                       insque(iq, ih);
+                       /*
+                        * Discard unneeded vnode
+                        * (This introduces the need of INACTIVE modification)
+                        */
+                       ip->inode.iso_mode = 0;
+                       iso_iput(ip);
+                       ip = iq;
+               }
+       }
+       
+       if (ip->iso_extent == imp->root_extent)
+               vp->v_flag |= VROOT;
+       
+       *ipp = ip;
+       return 0;
+}
+
+/*
+ * Unlock and decrement the reference count of an inode structure.
+ */
+iso_iput(ip)
+       register struct iso_node *ip;
+{
+       
+       if ((ip->i_flag & ILOCKED) == 0)
+               panic("iso_iput");
+       ISO_IUNLOCK(ip);
+       vrele(ITOV(ip));
+}
+
+/*
+ * Last reference to an inode, write the inode out and if necessary,
+ * truncate and deallocate the file.
+ */
+int
+isofs_inactive(ap)
+       struct vop_inactive_args /* {
+               struct vnode *a_vp;
+       } */ *ap;
+{
+       struct vnode *vp = ap->a_vp;
+       register struct iso_node *ip = VTOI(vp);
+       int mode, error = 0;
+       
+       if (prtactive && vp->v_usecount != 0)
+               vprint("isofs_inactive: pushing active", vp);
+       
+       ip->i_flag = 0;
+       /*
+        * If we are done with the inode, reclaim it
+        * so that it can be reused immediately.
+        */
+       if (vp->v_usecount == 0 && ip->inode.iso_mode == 0)
+               vgone(vp);
+       return error;
+}
+
+/*
+ * Reclaim an inode so that it can be used for other purposes.
+ */
+int
+isofs_reclaim(ap)
+       struct vop_reclaim_args /* {
+               struct vnode *a_vp;
+       } */ *ap;
+{
+       register struct vnode *vp = ap->a_vp;
+       register struct iso_node *ip = VTOI(vp);
+       int i;
+       
+       if (prtactive && vp->v_usecount != 0)
+               vprint("isofs_reclaim: pushing active", vp);
+       /*
+        * Remove the inode from its hash chain.
+        */
+       remque(ip);
+       ip->i_forw = ip;
+       ip->i_back = ip;
+       /*
+        * Purge old data structures associated with the inode.
+        */
+       cache_purge(vp);
+       if (ip->i_devvp) {
+               vrele(ip->i_devvp);
+               ip->i_devvp = 0;
+       }
+       FREE(vp->v_data, M_ISOFSNODE);
+       vp->v_data = NULL;
+       return 0;
+}
+
+/*
+ * Lock an inode. If its already locked, set the WANT bit and sleep.
+ */
+iso_ilock(ip)
+       register struct iso_node *ip;
+{
+       
+       while (ip->i_flag & ILOCKED) {
+               ip->i_flag |= IWANT;
+               if (ip->i_spare0 == curproc->p_pid)
+                       panic("locking against myself");
+               ip->i_spare1 = curproc->p_pid;
+               (void) sleep((caddr_t)ip, PINOD);
+       }
+       ip->i_spare1 = 0;
+       ip->i_spare0 = curproc->p_pid;
+       ip->i_flag |= ILOCKED;
+}
+
+/*
+ * Unlock an inode.  If WANT bit is on, wakeup.
+ */
+iso_iunlock(ip)
+       register struct iso_node *ip;
+{
+
+       if ((ip->i_flag & ILOCKED) == 0)
+               vprint("iso_iunlock: unlocked inode", ITOV(ip));
+       ip->i_spare0 = 0;
+       ip->i_flag &= ~ILOCKED;
+       if (ip->i_flag&IWANT) {
+               ip->i_flag &= ~IWANT;
+               wakeup((caddr_t)ip);
+       }
+}
+
+/*
+ * File attributes
+ */
+void
+isofs_defattr(isodir,inop,bp)
+       struct iso_directory_record *isodir;
+       struct iso_node *inop;
+       struct buf *bp;
+{
+       struct buf *bp2 = NULL;
+       struct iso_mnt *imp;
+       struct iso_extended_attributes *ap = NULL;
+       int off;
+       
+       if (isonum_711(isodir->flags)&2) {
+               inop->inode.iso_mode = S_IFDIR;
+               /*
+                * If we return 2, fts() will assume there are no subdirectories
+                * (just links for the path and .), so instead we return 1.
+                */
+               inop->inode.iso_links = 1;
+       } else {
+               inop->inode.iso_mode = S_IFREG;
+               inop->inode.iso_links = 1;
+       }
+       if (!bp
+           && ((imp = inop->i_mnt)->im_flags&ISOFSMNT_EXTATT)
+           && (off = isonum_711(isodir->ext_attr_length))) {
+               iso_blkatoff(inop,-off * imp->logical_block_size,&bp2);
+               bp = bp2;
+       }
+       if (bp) {
+               ap = (struct iso_extended_attributes *)bp->b_un.b_addr;
+               
+               if (isonum_711(ap->version) == 1) {
+                       if (!(ap->perm[0]&0x40))
+                               inop->inode.iso_mode |= VEXEC >> 6;
+                       if (!(ap->perm[0]&0x10))
+                               inop->inode.iso_mode |= VREAD >> 6;
+                       if (!(ap->perm[0]&4))
+                               inop->inode.iso_mode |= VEXEC >> 3;
+                       if (!(ap->perm[0]&1))
+                               inop->inode.iso_mode |= VREAD >> 3;
+                       if (!(ap->perm[1]&0x40))
+                               inop->inode.iso_mode |= VEXEC;
+                       if (!(ap->perm[1]&0x10))
+                               inop->inode.iso_mode |= VREAD;
+                       inop->inode.iso_uid = isonum_723(ap->owner); /* what about 0? */
+                       inop->inode.iso_gid = isonum_723(ap->group); /* what about 0? */
+               } else
+                       ap = NULL;
+       }
+       if (!ap) {
+               inop->inode.iso_mode |= VREAD|VEXEC|(VREAD|VEXEC)>>3|(VREAD|VEXEC)>>6;
+               inop->inode.iso_uid = (uid_t)0;
+               inop->inode.iso_gid = (gid_t)0;
+       }
+       if (bp2)
+               brelse(bp2);
+}
+
+/*
+ * Time stamps
+ */
+void
+isofs_deftstamp(isodir,inop,bp)
+       struct iso_directory_record *isodir;
+       struct iso_node *inop;
+       struct buf *bp;
+{
+       struct buf *bp2 = NULL;
+       struct iso_mnt *imp;
+       struct iso_extended_attributes *ap = NULL;
+       int off;
+       
+       if (!bp
+           && ((imp = inop->i_mnt)->im_flags&ISOFSMNT_EXTATT)
+           && (off = isonum_711(isodir->ext_attr_length))) {
+               iso_blkatoff(inop,-off * imp->logical_block_size,&bp2);
+               bp = bp2;
+       }
+       if (bp) {
+               ap = (struct iso_extended_attributes *)bp->b_un.b_addr;
+               
+               if (isonum_711(ap->version) == 1) {
+                       if (!isofs_tstamp_conv17(ap->ftime,&inop->inode.iso_atime))
+                               isofs_tstamp_conv17(ap->ctime,&inop->inode.iso_atime);
+                       if (!isofs_tstamp_conv17(ap->ctime,&inop->inode.iso_ctime))
+                               inop->inode.iso_ctime = inop->inode.iso_atime;
+                       if (!isofs_tstamp_conv17(ap->mtime,&inop->inode.iso_mtime))
+                               inop->inode.iso_mtime = inop->inode.iso_ctime;
+               } else
+                       ap = NULL;
+       }
+       if (!ap) {
+               isofs_tstamp_conv7(isodir->date,&inop->inode.iso_ctime);
+               inop->inode.iso_atime = inop->inode.iso_ctime;
+               inop->inode.iso_mtime = inop->inode.iso_ctime;
+       }
+       if (bp2)
+               brelse(bp2);
+}
+
+int
+isofs_tstamp_conv7(pi,pu)
+char *pi;
+struct timeval *pu;
+{
+       int i;
+       int crtime, days;
+       int y, m, d, hour, minute, second, tz;
+       
+       y = pi[0] + 1900;
+       m = pi[1];
+       d = pi[2];
+       hour = pi[3];
+       minute = pi[4];
+       second = pi[5];
+       tz = pi[6];
+       
+       if (y < 1970) {
+               pu->tv_sec  = 0;
+               pu->tv_usec = 0;
+               return 0;
+       } else {
+#ifdef ORIGINAL
+               /* computes day number relative to Sept. 19th,1989 */
+               /* don't even *THINK* about changing formula. It works! */
+               days = 367*(y-1980)-7*(y+(m+9)/12)/4-3*((y+(m-9)/7)/100+1)/4+275*m/9+d-100;
+#else
+               /*
+                * Changed :-) to make it relative to Jan. 1st, 1970
+                * and to disambiguate negative division
+                */
+               days = 367*(y-1960)-7*(y+(m+9)/12)/4-3*((y+(m+9)/12-1)/100+1)/4+275*m/9+d-239;
+#endif
+               crtime = ((((days * 24) + hour) * 60 + minute) * 60) + second;
+               
+               /* timezone offset is unreliable on some disks */
+               if (-48 <= tz && tz <= 52)
+                       crtime += tz * 15 * 60;
+       }
+       pu->tv_sec  = crtime;
+       pu->tv_usec = 0;
+       return 1;
+}
+
+static unsigned
+isofs_chars2ui(begin,len)
+       unsigned char *begin;
+       int len;
+{
+       unsigned rc;
+       
+       for (rc = 0; --len >= 0;) {
+               rc *= 10;
+               rc += *begin++ - '0';
+       }
+       return rc;
+}
+
+int
+isofs_tstamp_conv17(pi,pu)
+       unsigned char *pi;
+       struct timeval *pu;
+{
+       unsigned char buf[7];
+       
+       /* year:"0001"-"9999" -> -1900  */
+       buf[0] = isofs_chars2ui(pi,4) - 1900;
+       
+       /* month: " 1"-"12"      -> 1 - 12 */
+       buf[1] = isofs_chars2ui(pi + 4,2);
+       
+       /* day:   " 1"-"31"      -> 1 - 31 */
+       buf[2] = isofs_chars2ui(pi + 6,2);
+       
+       /* hour:  " 0"-"23"      -> 0 - 23 */
+       buf[3] = isofs_chars2ui(pi + 8,2);
+       
+       /* minute:" 0"-"59"      -> 0 - 59 */
+       buf[4] = isofs_chars2ui(pi + 10,2);
+       
+       /* second:" 0"-"59"      -> 0 - 59 */
+       buf[5] = isofs_chars2ui(pi + 12,2);
+       
+       /* difference of GMT */
+       buf[6] = pi[16];
+       
+       return isofs_tstamp_conv7(buf,pu);
+}
+
+void
+isodirino(inump,isodir,imp)
+       ino_t *inump;
+       struct iso_directory_record *isodir;
+       struct iso_mnt *imp;
+{
+       *inump = (isonum_733(isodir->extent) + isonum_711(isodir->ext_attr_length))
+                * imp->logical_block_size;
+}
diff --git a/usr/src/sys/isofs/cd9660/cd9660_node.h b/usr/src/sys/isofs/cd9660/cd9660_node.h
new file mode 100644 (file)
index 0000000..6cfdfb5
--- /dev/null
@@ -0,0 +1,117 @@
+/*-
+ * Copyright (c) 1994
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley
+ * by Pace Willisson (pace@blitz.com).  The Rock Ridge Extension
+ * Support code is derived from software contributed to Berkeley
+ * by Atsushi Murai (amurai@spec.co.jp).
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)cd9660_node.h       8.1 (Berkeley) %G%
+ */
+
+/*
+ * Theoretically, directories can be more than 2Gb in length,
+ * however, in practice this seems unlikely. So, we define
+ * the type doff_t as a long to keep down the cost of doing
+ * lookup on a 32-bit machine. If you are porting to a 64-bit
+ * architecture, you should make doff_t the same as off_t.
+ */
+#define doff_t long
+
+typedef        struct  {
+       struct timespec iso_atime;      /* time of last access */
+       struct timespec iso_mtime;      /* time of last modification */
+       struct timespec iso_ctime;      /* time file changed */
+       u_short         iso_mode;       /* files access mode and type */
+       uid_t           iso_uid;        /* owner user id */
+       gid_t           iso_gid;        /* owner group id */
+       short           iso_links;      /* links of file */
+       dev_t           iso_rdev;       /* Major/Minor number for special */
+} ISO_RRIP_INODE;
+
+#ifdef ISODEVMAP
+/*
+ * FOr device# (major,minor) translation table
+ */
+struct iso_dnode {
+       struct iso_dnode *d_chain[2];   /* hash chain, MUST be first */
+       dev_t           i_dev;          /* device where dnode resides */
+       ino_t           i_number;       /* the identity of the inode */
+       dev_t           d_dev;          /* device # for translation */
+};
+#define        d_forw          d_chain[0]
+#define        d_back          d_chain[1]
+#endif
+
+struct iso_node {
+       struct  iso_node *i_chain[2]; /* hash chain, MUST be first */
+       struct  vnode *i_vnode; /* vnode associated with this inode */
+       struct  vnode *i_devvp; /* vnode for block I/O */
+       u_long  i_flag;         /* see below */
+       dev_t   i_dev;          /* device where inode resides */
+       ino_t   i_number;       /* the identity of the inode */
+                               /* we use the actual starting block of the file */
+       struct  iso_mnt *i_mnt; /* filesystem associated with this inode */
+       struct  lockf *i_lockf; /* head of byte-level lock list */
+       doff_t  i_endoff;       /* end of useful stuff in directory */
+       doff_t  i_diroff;       /* offset in dir, where we found last entry */
+       doff_t  i_offset;       /* offset of free space in directory */
+       ino_t   i_ino;          /* inode number of found directory */
+       long    i_spare0;
+       long    i_spare1;
+
+       long iso_extent;        /* extent of file */
+       long i_size;
+       long iso_start;         /* actual start of data of file (may be different */
+                               /* from iso_extent, if file has extended attributes) */
+       ISO_RRIP_INODE  inode;
+};
+
+#define        i_forw          i_chain[0]
+#define        i_back          i_chain[1]
+
+/* flags */
+#define        ILOCKED         0x0001          /* inode is locked */
+#define        IWANT           0x0002          /* some process waiting on lock */
+#define        IACC            0x0020          /* inode access time to be updated */
+
+#define VTOI(vp) ((struct iso_node *)(vp)->v_data)
+#define ITOV(ip) ((ip)->i_vnode)
+
+#define ISO_ILOCK(ip)  iso_ilock(ip)
+#define ISO_IUNLOCK(ip)        iso_iunlock(ip)
+
+/*
+ * Prototypes for ISOFS vnode operations
+ */
+int isofs_lookup __P((struct vop_lookup_args *));
+int isofs_open __P((struct vop_open_args *));
+int isofs_close __P((struct vop_close_args *));
+int isofs_access __P((struct vop_access_args *));
+int isofs_getattr __P((struct vop_getattr_args *));
+int isofs_read __P((struct vop_read_args *));
+int isofs_ioctl __P((struct vop_ioctl_args *));
+int isofs_select __P((struct vop_select_args *));
+int isofs_mmap __P((struct vop_mmap_args *));
+int isofs_seek __P((struct vop_seek_args *));
+int isofs_readdir __P((struct vop_readdir_args *));
+int isofs_abortop __P((struct vop_abortop_args *));
+int isofs_inactive __P((struct vop_inactive_args *));
+int isofs_reclaim __P((struct vop_reclaim_args *));
+int isofs_bmap __P((struct vop_bmap_args *));
+int isofs_lock __P((struct vop_lock_args *));
+int isofs_unlock __P((struct vop_unlock_args *));
+int isofs_strategy __P((struct vop_strategy_args *));
+int isofs_print __P((struct vop_print_args *));
+int isofs_islocked __P((struct vop_islocked_args *));
+void isofs_defattr __P((struct iso_directory_record *,
+                       struct iso_node *, struct buf *));
+void isofs_deftstamp __P((struct iso_directory_record *,
+                       struct iso_node *, struct buf *));
+#ifdef ISODEVMAP
+struct iso_dnode *iso_dmap __P((dev_t, ino_t, int));
+void iso_dunmap __P((dev_t));
+#endif
diff --git a/usr/src/sys/isofs/cd9660/cd9660_rrip.c b/usr/src/sys/isofs/cd9660/cd9660_rrip.c
new file mode 100644 (file)
index 0000000..388b797
--- /dev/null
@@ -0,0 +1,659 @@
+/*-
+ * Copyright (c) 1993, 1994
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley
+ * by Pace Willisson (pace@blitz.com).  The Rock Ridge Extension
+ * Support code is derived from software contributed to Berkeley
+ * by Atsushi Murai (amurai@spec.co.jp).
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)cd9660_rrip.c       8.1 (Berkeley) %G%
+ */
+
+#include <sys/param.h>
+#include <sys/namei.h>
+#include <sys/buf.h>
+#include <sys/file.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+#include <sys/kernel.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <sys/time.h>
+
+#include <isofs/cd9660/iso.h>
+#include <isofs/cd9660/isofs_node.h>
+#include <isofs/cd9660/isofs_rrip.h>
+#include <isofs/cd9660/iso_rrip.h>
+
+/*
+ * POSIX file attribute
+ */
+static int
+isofs_rrip_attr(p,ana)
+       ISO_RRIP_ATTR *p;
+       ISO_RRIP_ANALYZE *ana;
+{
+       ana->inop->inode.iso_mode = isonum_731(p->mode_l);
+       ana->inop->inode.iso_uid = (uid_t)isonum_731(p->uid_l);
+       ana->inop->inode.iso_gid = (gid_t)isonum_731(p->gid_l);
+       ana->inop->inode.iso_links = isonum_731(p->links_l);
+       ana->fields &= ~ISO_SUSP_ATTR;
+       return ISO_SUSP_ATTR;
+}
+
+static void
+isofs_rrip_defattr(isodir,ana)
+       struct iso_directory_record *isodir;
+       ISO_RRIP_ANALYZE *ana;
+{
+       /* But this is a required field! */
+       printf("RRIP without PX field?\n");
+       isofs_defattr(isodir,ana->inop,NULL);
+}
+
+/*
+ * Symbolic Links
+ */
+static int
+isofs_rrip_slink(p,ana)
+       ISO_RRIP_SLINK  *p;
+       ISO_RRIP_ANALYZE *ana;
+{
+       register ISO_RRIP_SLINK_COMPONENT *pcomp;
+       register ISO_RRIP_SLINK_COMPONENT *pcompe;
+       int len, wlen, cont;
+       char *outbuf, *inbuf;
+       
+       pcomp = (ISO_RRIP_SLINK_COMPONENT *)p->component;
+       pcompe = (ISO_RRIP_SLINK_COMPONENT *)((char *)p + isonum_711(p->h.length));
+       len = *ana->outlen;
+       outbuf = ana->outbuf;
+       cont = ana->cont;
+       
+       /*
+        * Gathering a Symbolic name from each component with path
+        */
+       for (;
+            pcomp < pcompe;
+            pcomp = (ISO_RRIP_SLINK_COMPONENT *)((char *)pcomp + ISO_RRIP_SLSIZ
+                                                 + isonum_711(pcomp->clen))) {
+               
+               if (!cont) {
+                       if (len < ana->maxlen) {
+                               len++;
+                               *outbuf++ = '/';
+                       }
+               }
+               cont = 0;
+               
+               inbuf = "..";
+               wlen = 0;
+               
+               switch (*pcomp->cflag) {
+                       
+               case ISO_SUSP_CFLAG_CURRENT:
+                       /* Inserting Current */
+                       wlen = 1;
+                       break;
+                       
+               case ISO_SUSP_CFLAG_PARENT:
+                       /* Inserting Parent */
+                       wlen = 2;
+                       break;
+                       
+               case ISO_SUSP_CFLAG_ROOT:
+                       /* Inserting slash for ROOT */
+                       /* start over from beginning(?) */
+                       outbuf -= len;
+                       len = 0;
+                       break;
+                       
+               case ISO_SUSP_CFLAG_VOLROOT:
+                       /* Inserting a mount point i.e. "/cdrom" */
+                       /* same as above */
+                       outbuf -= len;
+                       len = 0;
+                       inbuf = ana->imp->im_mountp->mnt_stat.f_mntonname;
+                       wlen = strlen(inbuf);
+                       break;
+                       
+               case ISO_SUSP_CFLAG_HOST:
+                       /* Inserting hostname i.e. "kurt.tools.de" */
+                       inbuf = hostname;
+                       wlen = hostnamelen;
+                       break;
+                       
+               case ISO_SUSP_CFLAG_CONTINUE:
+                       cont = 1;
+                       /* fall thru */
+               case 0:
+                       /* Inserting component */
+                       wlen = isonum_711(pcomp->clen);
+                       inbuf = pcomp->name;
+                       break;
+               default:
+                       printf("RRIP with incorrect flags?");
+                       wlen = ana->maxlen + 1;
+                       break;
+               }
+               
+               if (len + wlen > ana->maxlen) {
+                       /* indicate error to caller */
+                       ana->cont = 1;
+                       ana->fields = 0;
+                       ana->outbuf -= *ana->outlen;
+                       *ana->outlen = 0;
+                       return 0;
+               }
+               
+               bcopy(inbuf,outbuf,wlen);
+               outbuf += wlen;
+               len += wlen;
+               
+       }
+       ana->outbuf = outbuf;
+       *ana->outlen = len;
+       ana->cont = cont;
+       
+       if (!isonum_711(p->flags)) {
+               ana->fields &= ~ISO_SUSP_SLINK;
+               return ISO_SUSP_SLINK;
+       }
+       return 0;
+}
+
+/*
+ * Alternate name
+ */
+static int
+isofs_rrip_altname(p,ana)
+       ISO_RRIP_ALTNAME *p;
+       ISO_RRIP_ANALYZE *ana;
+{
+       char *inbuf;
+       int wlen;
+       int cont;
+       
+       inbuf = "..";
+       wlen = 0;
+       cont = 0;
+       
+       switch (*p->flags) {
+       case ISO_SUSP_CFLAG_CURRENT:
+               /* Inserting Current */
+               wlen = 1;
+               break;
+               
+       case ISO_SUSP_CFLAG_PARENT:
+               /* Inserting Parent */
+               wlen = 2;
+               break;
+               
+       case ISO_SUSP_CFLAG_HOST:
+               /* Inserting hostname i.e. "kurt.tools.de" */
+               inbuf = hostname;
+               wlen = hostnamelen;
+               break;
+               
+       case ISO_SUSP_CFLAG_CONTINUE:
+               cont = 1;
+               /* fall thru */
+       case 0:
+               /* Inserting component */
+               wlen = isonum_711(p->h.length) - 5;
+               inbuf = (char *)p + 5;
+               break;
+               
+       default:
+               printf("RRIP with incorrect NM flags?\n");
+               wlen = ana->maxlen + 1;
+               break;
+       }
+       
+       if ((*ana->outlen += wlen) > ana->maxlen) {
+               /* treat as no name field */
+               ana->fields &= ~ISO_SUSP_ALTNAME;
+               ana->outbuf -= *ana->outlen - wlen;
+               *ana->outlen = 0;
+               return 0;
+       }
+       
+       bcopy(inbuf,ana->outbuf,wlen);
+       ana->outbuf += wlen;
+       
+       if (!cont) {
+               ana->fields &= ~ISO_SUSP_ALTNAME;
+               return ISO_SUSP_ALTNAME;
+       }
+       return 0;
+}
+
+static void
+isofs_rrip_defname(isodir,ana)
+       struct iso_directory_record *isodir;
+       ISO_RRIP_ANALYZE *ana;
+{
+       strcpy(ana->outbuf,"..");
+       switch (*isodir->name) {
+       default:
+               isofntrans(isodir->name,isonum_711(isodir->name_len),
+                          ana->outbuf,ana->outlen,
+                          1,isonum_711(isodir->flags)&4);
+               break;
+       case 0:
+               *ana->outlen = 1;
+               break;
+       case 1:
+               *ana->outlen = 2;
+               break;
+       }
+}
+
+/*
+ * Parent or Child Link
+ */
+static int
+isofs_rrip_pclink(p,ana)
+       ISO_RRIP_CLINK  *p;
+       ISO_RRIP_ANALYZE *ana;
+{
+       *ana->inump = isonum_733(p->dir_loc) << ana->imp->im_bshift;
+       ana->fields &= ~(ISO_SUSP_CLINK|ISO_SUSP_PLINK);
+       return *p->h.type == 'C' ? ISO_SUSP_CLINK : ISO_SUSP_PLINK;
+}
+
+/*
+ * Relocated directory
+ */
+static int
+isofs_rrip_reldir(p,ana)
+       ISO_RRIP_RELDIR  *p;
+       ISO_RRIP_ANALYZE *ana;
+{
+       /* special hack to make caller aware of RE field */
+       *ana->outlen = 0;
+       ana->fields = 0;
+       return ISO_SUSP_RELDIR|ISO_SUSP_ALTNAME|ISO_SUSP_CLINK|ISO_SUSP_PLINK;
+}
+
+static int
+isofs_rrip_tstamp(p,ana)
+       ISO_RRIP_TSTAMP *p;
+       ISO_RRIP_ANALYZE *ana;
+{
+       unsigned char *ptime;
+       
+       ptime = p->time;
+       
+       /* Check a format of time stamp (7bytes/17bytes) */
+       if (!(*p->flags&ISO_SUSP_TSTAMP_FORM17)) {
+               if (*p->flags&ISO_SUSP_TSTAMP_CREAT)
+                       ptime += 7;
+               
+               if (*p->flags&ISO_SUSP_TSTAMP_MODIFY) {
+                       isofs_tstamp_conv7(ptime,&ana->inop->inode.iso_mtime);
+                       ptime += 7;
+               } else
+                       bzero(&ana->inop->inode.iso_mtime,sizeof(struct timeval));
+               
+               if (*p->flags&ISO_SUSP_TSTAMP_ACCESS) {
+                       isofs_tstamp_conv7(ptime,&ana->inop->inode.iso_atime);
+                       ptime += 7;
+               } else
+                       ana->inop->inode.iso_atime = ana->inop->inode.iso_mtime;
+               
+               if (*p->flags&ISO_SUSP_TSTAMP_ATTR)
+                       isofs_tstamp_conv7(ptime,&ana->inop->inode.iso_ctime);
+               else
+                       ana->inop->inode.iso_ctime = ana->inop->inode.iso_mtime;
+               
+       } else {
+               if (*p->flags&ISO_SUSP_TSTAMP_CREAT)
+                       ptime += 17;
+               
+               if (*p->flags&ISO_SUSP_TSTAMP_MODIFY) {
+                       isofs_tstamp_conv17(ptime,&ana->inop->inode.iso_mtime);
+                       ptime += 17;
+               } else
+                       bzero(&ana->inop->inode.iso_mtime,sizeof(struct timeval));
+               
+               if (*p->flags&ISO_SUSP_TSTAMP_ACCESS) {
+                       isofs_tstamp_conv17(ptime,&ana->inop->inode.iso_atime);
+                       ptime += 17;
+               } else
+                       ana->inop->inode.iso_atime = ana->inop->inode.iso_mtime;
+               
+               if (*p->flags&ISO_SUSP_TSTAMP_ATTR)
+                       isofs_tstamp_conv17(ptime,&ana->inop->inode.iso_ctime);
+               else
+                       ana->inop->inode.iso_ctime = ana->inop->inode.iso_mtime;
+               
+       }
+       ana->fields &= ~ISO_SUSP_TSTAMP;
+       return ISO_SUSP_TSTAMP;
+}
+
+static void
+isofs_rrip_deftstamp(isodir,ana)
+       struct iso_directory_record  *isodir;
+       ISO_RRIP_ANALYZE *ana;
+{
+       isofs_deftstamp(isodir,ana->inop,NULL);
+}
+
+/*
+ * POSIX device modes
+ */
+static int
+isofs_rrip_device(p,ana)
+       ISO_RRIP_DEVICE *p;
+       ISO_RRIP_ANALYZE *ana;
+{
+       unsigned high, low;
+       
+       high = isonum_733(p->dev_t_high_l);
+       low  = isonum_733(p->dev_t_low_l);
+       
+       if ( high == 0 ) {
+               ana->inop->inode.iso_rdev = makedev( major(low), minor(low) );
+       } else {
+               ana->inop->inode.iso_rdev = makedev( high, minor(low) );
+       }
+       ana->fields &= ~ISO_SUSP_DEVICE;
+       return ISO_SUSP_DEVICE;
+}
+
+/*
+ * Flag indicating
+ */
+static int
+isofs_rrip_idflag(p,ana)
+       ISO_RRIP_IDFLAG *p;
+       ISO_RRIP_ANALYZE *ana;
+{
+       ana->fields &= isonum_711(p->flags)|~0xff; /* don't touch high bits */
+       /* special handling of RE field */
+       if (ana->fields&ISO_SUSP_RELDIR)
+               return isofs_rrip_reldir(p,ana);
+       
+       return ISO_SUSP_IDFLAG;
+}
+
+/*
+ * Continuation pointer
+ */
+static int
+isofs_rrip_cont(p,ana)
+       ISO_RRIP_CONT *p;
+       ISO_RRIP_ANALYZE *ana;
+{
+       ana->iso_ce_blk = isonum_733(p->location);
+       ana->iso_ce_off = isonum_733(p->offset);
+       ana->iso_ce_len = isonum_733(p->length);
+       return ISO_SUSP_CONT;
+}
+
+/*
+ * System Use end
+ */
+static int
+isofs_rrip_stop(p,ana)
+       ISO_SUSP_HEADER *p;
+       ISO_RRIP_ANALYZE *ana;
+{
+       /* stop analyzing */
+       ana->fields = 0;
+       return ISO_SUSP_STOP;
+}
+
+/*
+ * Extension reference
+ */
+static int
+isofs_rrip_extref(p,ana)
+       ISO_RRIP_EXTREF *p;
+       ISO_RRIP_ANALYZE *ana;
+{
+       if (isonum_711(p->len_id) != 10
+           || bcmp((char *)p + 8,"RRIP_1991A",10)
+           || isonum_711(p->version) != 1)
+               return 0;
+       ana->fields &= ~ISO_SUSP_EXTREF;
+       return ISO_SUSP_EXTREF;
+}
+
+typedef struct {
+       char type[2];
+       int (*func)();
+       void (*func2)();
+       int result;
+} RRIP_TABLE;
+
+static int
+isofs_rrip_loop(isodir,ana,table)
+       struct iso_directory_record *isodir;
+       ISO_RRIP_ANALYZE *ana;
+       RRIP_TABLE *table;
+{
+       register RRIP_TABLE *ptable;
+       register ISO_SUSP_HEADER *phead;
+       register ISO_SUSP_HEADER *pend;
+       struct buf *bp = NULL;
+       int i;
+       char *pwhead;
+       int result;
+       
+       /*
+        * Note: If name length is odd,
+        *       it will be padding 1 byte  after the name
+        */
+       pwhead = isodir->name + isonum_711(isodir->name_len);
+       if (!(isonum_711(isodir->name_len)&1))
+               pwhead++;
+       
+       /* If it's not the '.' entry of the root dir obey SP field */
+       if (*isodir->name != 0
+           || isonum_733(isodir->extent) != ana->imp->root_extent)
+               pwhead += ana->imp->rr_skip;
+       else
+               pwhead += ana->imp->rr_skip0;
+       
+       phead = (ISO_SUSP_HEADER *)pwhead;
+       pend = (ISO_SUSP_HEADER *)((char *)isodir + isonum_711(isodir->length));
+       
+       result = 0;
+       while (1) {
+               ana->iso_ce_len = 0;
+               /*
+                * Note: "pend" should be more than one SUSP header
+                */ 
+               while (pend >= phead + 1) {
+                       if (isonum_711(phead->version) == 1) {
+                               for (ptable = table; ptable->func; ptable++) {
+                                       if (*phead->type == *ptable->type
+                                           && phead->type[1] == ptable->type[1]) {
+                                               result |= ptable->func(phead,ana);
+                                               break;
+                                       }
+                               }
+                               if (!ana->fields)
+                                       break;
+                       }
+                       /*
+                        * move to next SUSP
+                        * Hopefully this works with newer versions, too
+                        */
+                       phead = (ISO_SUSP_HEADER *)((char *)phead + isonum_711(phead->length));
+               }
+               
+               if ( ana->fields && ana->iso_ce_len ) {
+                       if (ana->iso_ce_blk >= ana->imp->volume_space_size
+                           || ana->iso_ce_off + ana->iso_ce_len > ana->imp->logical_block_size
+                           || bread(ana->imp->im_devvp,
+                                    ana->iso_ce_blk * ana->imp->logical_block_size / DEV_BSIZE,
+                                    ana->imp->logical_block_size,NOCRED,&bp))
+                               /* what to do now? */
+                               break;
+                       phead = (ISO_SUSP_HEADER *)(bp->b_un.b_addr + ana->iso_ce_off);
+                       pend = (ISO_SUSP_HEADER *) ((char *)phead + ana->iso_ce_len);
+               } else
+                       break;
+       }
+       if (bp)
+               brelse(bp);
+       /*
+        * If we don't find the Basic SUSP stuffs, just set default value
+        *   ( attribute/time stamp )
+        */
+       for (ptable = table; ptable->func2; ptable++)
+               if (!(ptable->result&result))
+                       ptable->func2(isodir,ana);
+       
+       return result;
+}
+
+static RRIP_TABLE rrip_table_analyze[] = {
+       { "PX", isofs_rrip_attr,        isofs_rrip_defattr,     ISO_SUSP_ATTR },
+       { "TF", isofs_rrip_tstamp,      isofs_rrip_deftstamp,   ISO_SUSP_TSTAMP },
+       { "PN", isofs_rrip_device,      0,                      ISO_SUSP_DEVICE },
+       { "RR", isofs_rrip_idflag,      0,                      ISO_SUSP_IDFLAG },
+       { "CE", isofs_rrip_cont,        0,                      ISO_SUSP_CONT },
+       { "ST", isofs_rrip_stop,        0,                      ISO_SUSP_STOP },
+       { "",   0,                      0,                      0 }
+};
+
+int
+isofs_rrip_analyze(isodir,inop,imp)
+       struct iso_directory_record *isodir;
+       struct iso_node *inop;
+       struct iso_mnt *imp;
+{
+       ISO_RRIP_ANALYZE analyze;
+       
+       analyze.inop = inop;
+       analyze.imp = imp;
+       analyze.fields = ISO_SUSP_ATTR|ISO_SUSP_TSTAMP|ISO_SUSP_DEVICE;
+       
+       return isofs_rrip_loop(isodir,&analyze,rrip_table_analyze);
+}
+
+/* 
+ * Get Alternate Name from 'AL' record 
+ * If either no AL record or 0 length, 
+ *    it will be return the translated ISO9660 name,
+ */
+static RRIP_TABLE rrip_table_getname[] = {
+       { "NM", isofs_rrip_altname,     isofs_rrip_defname,     ISO_SUSP_ALTNAME },
+       { "CL", isofs_rrip_pclink,      0,                      ISO_SUSP_CLINK|ISO_SUSP_PLINK },
+       { "PL", isofs_rrip_pclink,      0,                      ISO_SUSP_CLINK|ISO_SUSP_PLINK },
+       { "RE", isofs_rrip_reldir,      0,                      ISO_SUSP_RELDIR },
+       { "RR", isofs_rrip_idflag,      0,                      ISO_SUSP_IDFLAG },
+       { "CE", isofs_rrip_cont,        0,                      ISO_SUSP_CONT },
+       { "ST", isofs_rrip_stop,        0,                      ISO_SUSP_STOP },
+       { "",   0,                      0,                      0 }
+};
+
+int
+isofs_rrip_getname(isodir,outbuf,outlen,inump,imp)
+       struct iso_directory_record *isodir;
+       char *outbuf;
+       u_short *outlen;
+       ino_t *inump;
+       struct iso_mnt *imp;
+{
+       ISO_RRIP_ANALYZE analyze;
+       RRIP_TABLE *tab;
+       
+       analyze.outbuf = outbuf;
+       analyze.outlen = outlen;
+       analyze.maxlen = NAME_MAX;
+       analyze.inump = inump;
+       analyze.imp = imp;
+       analyze.fields = ISO_SUSP_ALTNAME|ISO_SUSP_RELDIR|ISO_SUSP_CLINK|ISO_SUSP_PLINK;
+       *outlen = 0;
+       
+       tab = rrip_table_getname;
+       if (*isodir->name == 0
+           || *isodir->name == 1) {
+               isofs_rrip_defname(isodir,&analyze);
+               
+               analyze.fields &= ~ISO_SUSP_ALTNAME;
+               tab++;
+       }
+       
+       return isofs_rrip_loop(isodir,&analyze,tab);
+}
+
+/* 
+ * Get Symbolic Name from 'SL' record 
+ *
+ * Note: isodir should contains SL record!
+ */
+static RRIP_TABLE rrip_table_getsymname[] = {
+       { "SL", isofs_rrip_slink,       0,                      ISO_SUSP_SLINK },
+       { "RR", isofs_rrip_idflag,      0,                      ISO_SUSP_IDFLAG },
+       { "CE", isofs_rrip_cont,        0,                      ISO_SUSP_CONT },
+       { "ST", isofs_rrip_stop,        0,                      ISO_SUSP_STOP },
+       { "",   0,                      0,                      0 }
+};
+
+int
+isofs_rrip_getsymname(isodir,outbuf,outlen,imp)
+       struct iso_directory_record *isodir;
+       char *outbuf;
+       u_short *outlen;
+       struct iso_mnt *imp;
+{
+       ISO_RRIP_ANALYZE analyze;
+       
+       analyze.outbuf = outbuf;
+       analyze.outlen = outlen;
+       *outlen = 0;
+       analyze.maxlen = MAXPATHLEN;
+       analyze.cont = 1;               /* don't start with a slash */
+       analyze.imp = imp;
+       analyze.fields = ISO_SUSP_SLINK;
+       
+       return (isofs_rrip_loop(isodir,&analyze,rrip_table_getsymname)&ISO_SUSP_SLINK);
+}
+
+static RRIP_TABLE rrip_table_extref[] = {
+       { "ER", isofs_rrip_extref,      0,                      ISO_SUSP_EXTREF },
+       { "CE", isofs_rrip_cont,        0,                      ISO_SUSP_CONT },
+       { "ST", isofs_rrip_stop,        0,                      ISO_SUSP_STOP },
+       { "",   0,                      0,                      0 }
+};
+
+/*
+ * Check for Rock Ridge Extension and return offset of its fields.
+ * Note: We require the ER field.
+ */
+int
+isofs_rrip_offset(isodir,imp)
+       struct iso_directory_record *isodir;
+       struct iso_mnt *imp;
+{
+       ISO_RRIP_OFFSET *p;
+       ISO_RRIP_ANALYZE analyze;
+       
+       imp->rr_skip0 = 0;
+       p = (ISO_RRIP_OFFSET *)(isodir->name + 1);
+       if (bcmp(p,"SP\7\1\276\357",6)) {
+               /* Maybe, it's a CDROM XA disc? */
+               imp->rr_skip0 = 15;
+               p = (ISO_RRIP_OFFSET *)((char *)p + 15);
+               if (bcmp(p,"SP\7\1\276\357",6))
+                       return -1;
+       }
+       
+       analyze.imp = imp;
+       analyze.fields = ISO_SUSP_EXTREF;
+       if (!(isofs_rrip_loop(isodir,&analyze,rrip_table_extref)&ISO_SUSP_EXTREF))
+               return -1;
+       
+       return isonum_711(p->skip);
+}
diff --git a/usr/src/sys/isofs/cd9660/cd9660_rrip.h b/usr/src/sys/isofs/cd9660/cd9660_rrip.h
new file mode 100644 (file)
index 0000000..68e1829
--- /dev/null
@@ -0,0 +1,120 @@
+/*-
+ * Copyright (c) 1993, 1994
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley
+ * by Pace Willisson (pace@blitz.com).  The Rock Ridge Extension
+ * Support code is derived from software contributed to Berkeley
+ * by Atsushi Murai (amurai@spec.co.jp).
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)cd9660_rrip.h       8.1 (Berkeley) %G%
+ */
+
+typedef struct {
+       char          type              [ISODCL (  0,    1)];
+       unsigned char length            [ISODCL (  2,    2)]; /* 711 */
+       unsigned char version           [ISODCL (  3,    3)];
+} ISO_SUSP_HEADER;
+
+typedef struct {
+       ISO_SUSP_HEADER                 h;
+       char mode_l                     [ISODCL (  4,    7)]; /* 731 */
+       char mode_m                     [ISODCL (  8,   11)]; /* 732 */
+       char links_l                    [ISODCL ( 12,   15)]; /* 731 */
+       char links_m                    [ISODCL ( 16,   19)]; /* 732 */
+       char uid_l                      [ISODCL ( 20,   23)]; /* 731 */
+       char uid_m                      [ISODCL ( 24,   27)]; /* 732 */
+       char gid_l                      [ISODCL ( 28,   31)]; /* 731 */
+       char gid_m                      [ISODCL ( 32,   35)]; /* 732 */
+} ISO_RRIP_ATTR;
+
+typedef struct {
+       ISO_SUSP_HEADER                 h;
+       char dev_t_high_l               [ISODCL (  4,    7)]; /* 731 */
+       char dev_t_high_m               [ISODCL (  8,   11)]; /* 732 */
+       char dev_t_low_l                [ISODCL ( 12,   15)]; /* 731 */
+       char dev_t_low_m                [ISODCL ( 16,   19)]; /* 732 */
+} ISO_RRIP_DEVICE;
+
+#define        ISO_SUSP_CFLAG_CONTINUE 0x01
+#define        ISO_SUSP_CFLAG_CURRENT  0x02
+#define        ISO_SUSP_CFLAG_PARENT   0x04
+#define        ISO_SUSP_CFLAG_ROOT     0x08
+#define        ISO_SUSP_CFLAG_VOLROOT  0x10
+#define        ISO_SUSP_CFLAG_HOST     0x20
+
+typedef struct {
+       u_char cflag                    [ISODCL (  1,    1)];
+       u_char clen                     [ISODCL (  2,    2)];
+       u_char name                     [0];
+} ISO_RRIP_SLINK_COMPONENT;
+#define        ISO_RRIP_SLSIZ  2
+
+typedef struct {
+       ISO_SUSP_HEADER                 h;
+       u_char flags                    [ISODCL (  4,    4)];
+       u_char component                [ISODCL (  5,    5)];
+} ISO_RRIP_SLINK;
+
+typedef struct {
+       ISO_SUSP_HEADER                 h;
+       char flags                      [ISODCL (  4,    4)];
+} ISO_RRIP_ALTNAME;
+
+typedef struct {
+       ISO_SUSP_HEADER                 h;
+       char dir_loc                    [ISODCL (  4,    11)]; /* 733 */
+} ISO_RRIP_CLINK;
+
+typedef struct {
+       ISO_SUSP_HEADER                 h;
+       char dir_loc                    [ISODCL (  4,    11)]; /* 733 */
+} ISO_RRIP_PLINK;
+
+typedef struct {
+       ISO_SUSP_HEADER                 h;
+} ISO_RRIP_RELDIR;
+
+#define        ISO_SUSP_TSTAMP_FORM17  0x80
+#define        ISO_SUSP_TSTAMP_FORM7   0x00
+#define        ISO_SUSP_TSTAMP_CREAT   0x01
+#define        ISO_SUSP_TSTAMP_MODIFY  0x02
+#define        ISO_SUSP_TSTAMP_ACCESS  0x04
+#define        ISO_SUSP_TSTAMP_ATTR    0x08
+#define        ISO_SUSP_TSTAMP_BACKUP  0x10
+#define        ISO_SUSP_TSTAMP_EXPIRE  0x20
+#define        ISO_SUSP_TSTAMP_EFFECT  0x40
+
+typedef struct {
+       ISO_SUSP_HEADER                 h;
+       unsigned char flags             [ISODCL (  4,    4)];
+       unsigned char time              [ISODCL (  5,    5)];
+} ISO_RRIP_TSTAMP;
+
+typedef struct {
+       ISO_SUSP_HEADER                 h;
+       unsigned char flags             [ISODCL (  4,    4)];
+} ISO_RRIP_IDFLAG;
+
+typedef struct {
+       ISO_SUSP_HEADER                 h;
+       char len_id                     [ISODCL (  4,    4)];
+       char len_des                    [ISODCL (  5,    5)];
+       char len_src                    [ISODCL (  6,    6)];
+       char version                    [ISODCL (  7,    7)];
+} ISO_RRIP_EXTREF;
+
+typedef struct {
+       ISO_SUSP_HEADER                 h;
+       char check                      [ISODCL (  4,    5)];
+       char skip                       [ISODCL (  6,    6)];
+} ISO_RRIP_OFFSET;
+
+typedef struct {
+       ISO_SUSP_HEADER                 h;
+       char location                   [ISODCL (  4,   11)];
+       char offset                     [ISODCL ( 12,   19)];
+       char length                     [ISODCL ( 20,   27)];
+} ISO_RRIP_CONT;
diff --git a/usr/src/sys/isofs/cd9660/cd9660_util.c b/usr/src/sys/isofs/cd9660/cd9660_util.c
new file mode 100644 (file)
index 0000000..c66bde0
--- /dev/null
@@ -0,0 +1,210 @@
+/*-
+ * Copyright (c) 1994
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley
+ * by Pace Willisson (pace@blitz.com).  The Rock Ridge Extension
+ * Support code is derived from software contributed to Berkeley
+ * by Atsushi Murai (amurai@spec.co.jp).
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)cd9660_util.c       8.1 (Berkeley) %G%
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/namei.h>
+#include <sys/resourcevar.h>
+#include <sys/kernel.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <sys/conf.h>
+#include <sys/mount.h>
+#include <sys/vnode.h>
+#include <miscfs/specfs/specdev.h> /* XXX */
+#include <miscfs/fifofs/fifo.h> /* XXX */
+#include <sys/malloc.h>
+#include <sys/dir.h>
+
+#include <isofs/cd9660/iso.h>
+
+#ifdef __notanymore__
+int
+isonum_711 (p)
+unsigned char *p;
+{
+       return (*p);
+}
+
+int
+isonum_712 (p)
+signed char *p;
+{
+       return (*p);
+}
+
+int
+isonum_721 (p)
+unsigned char *p;
+{
+       /* little endian short */
+#if BYTE_ORDER != LITTLE_ENDIAN
+       printf ("isonum_721 called on non little-endian machine!\n");
+#endif
+
+       return *(short *)p;
+}
+
+int
+isonum_722 (p)
+unsigned char *p;
+{
+        /* big endian short */
+#if BYTE_ORDER != BIG_ENDIAN
+        printf ("isonum_722 called on non big-endian machine!\n");
+#endif
+
+       return *(short *)p;
+}
+
+int
+isonum_723 (p)
+unsigned char *p;
+{
+#if BYTE_ORDER == BIG_ENDIAN
+        return isonum_722 (p + 2);
+#elif BYTE_ORDER == LITTLE_ENDIAN
+       return isonum_721 (p);
+#else
+       printf ("isonum_723 unsupported byte order!\n");
+       return 0;
+#endif
+}
+
+int
+isonum_731 (p)
+unsigned char *p;
+{
+        /* little endian long */
+#if BYTE_ORDER != LITTLE_ENDIAN
+        printf ("isonum_731 called on non little-endian machine!\n");
+#endif
+
+       return *(long *)p;
+}
+
+int
+isonum_732 (p)
+unsigned char *p;
+{
+        /* big endian long */
+#if BYTE_ORDER != BIG_ENDIAN
+        printf ("isonum_732 called on non big-endian machine!\n");
+#endif
+
+       return *(long *)p;
+}
+
+int
+isonum_733 (p)
+unsigned char *p;
+{
+#if BYTE_ORDER == BIG_ENDIAN
+        return isonum_732 (p + 4);
+#elif BYTE_ORDER == LITTLE_ENDIAN
+       return isonum_731 (p);
+#else
+       printf ("isonum_733 unsupported byte order!\n");
+       return 0;
+#endif
+}
+#endif /* __notanymore__ */
+
+/*
+ * translate and compare a filename
+ * Note: Version number plus ';' may be omitted.
+ */
+int
+isofncmp(unsigned char *fn,int fnlen,unsigned char *isofn,int isolen)
+{
+       int i, j;
+       char c;
+       
+       while (--fnlen >= 0) {
+               if (--isolen < 0)
+                       return *fn;
+               if ((c = *isofn++) == ';') {
+                       switch (*fn++) {
+                       default:
+                               return *--fn;
+                       case 0:
+                               return 0;
+                       case ';':
+                               break;
+                       }
+                       for (i = 0; --fnlen >= 0; i = i * 10 + *fn++ - '0') {
+                               if (*fn < '0' || *fn > '9') {
+                                       return -1;
+                               }
+                       }
+                       for (j = 0; --isolen >= 0; j = j * 10 + *isofn++ - '0');
+                       return i - j;
+               }
+               if (c != *fn) {
+                       if (c >= 'A' && c <= 'Z') {
+                               if (c + ('a' - 'A') != *fn) {
+                                       if (*fn >= 'a' && *fn <= 'z')
+                                               return *fn - ('a' - 'A') - c;
+                                       else
+                                               return *fn - c;
+                               }
+                       } else
+                               return *fn - c;
+               }
+               fn++;
+       }
+       if (isolen > 0) {
+               switch (*isofn) {
+               default:
+                       return -1;
+               case '.':
+                       if (isofn[1] != ';')
+                               return -1;
+               case ';':
+                       return 0;
+               }
+       }
+       return 0;
+}
+
+/*
+ * translate a filename
+ */
+void
+isofntrans(unsigned char *infn,int infnlen,
+          unsigned char *outfn,unsigned short *outfnlen,
+          int original,int assoc)
+{
+       int fnidx = 0;
+       
+       if (assoc) {
+               *outfn++ = ASSOCCHAR;
+               fnidx++;
+       }
+       for (; fnidx < infnlen; fnidx++) {
+               char c = *infn++;
+               
+               if (!original && c >= 'A' && c <= 'Z')
+                       *outfn++ = c + ('a' - 'A');
+               else if (!original && c == '.' && *infn == ';')
+                       break;
+               else if (!original && c == ';')
+                       break;
+               else
+                       *outfn++ = c;
+       }
+       *outfnlen = fnidx;
+}
diff --git a/usr/src/sys/isofs/cd9660/cd9660_vfsops.c b/usr/src/sys/isofs/cd9660/cd9660_vfsops.c
new file mode 100644 (file)
index 0000000..17f69be
--- /dev/null
@@ -0,0 +1,654 @@
+/*-
+ * Copyright (c) 1994
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley
+ * by Pace Willisson (pace@blitz.com).  The Rock Ridge Extension
+ * Support code is derived from software contributed to Berkeley
+ * by Atsushi Murai (amurai@spec.co.jp).
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)cd9660_vfsops.c     8.1 (Berkeley) %G%
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/namei.h>
+#include <sys/proc.h>
+#include <sys/kernel.h>
+#include <sys/vnode.h>
+#include <miscfs/specfs/specdev.h>
+#include <sys/mount.h>
+#include <sys/buf.h>
+#include <sys/file.h>
+#include <sys/dkbad.h>
+#include <sys/disklabel.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/malloc.h>
+
+#include <isofs/cd9660/iso.h>
+#include <isofs/cd9660/isofs_node.h>
+
+extern int enodev ();
+
+struct vfsops isofs_vfsops = {
+       isofs_mount,
+       isofs_start,
+       isofs_unmount,
+       isofs_root,
+       isofs_quotactl,
+       isofs_statfs,
+       isofs_sync,
+       isofs_vget,
+       isofs_fhtovp,
+       isofs_vptofh,
+       isofs_init,
+};
+
+/*
+ * Called by vfs_mountroot when iso is going to be mounted as root.
+ *
+ * Name is updated by mount(8) after booting.
+ */
+#define ROOTNAME       "root_device"
+
+static iso_mountfs();
+
+isofs_mountroot()
+{
+       register struct mount *mp;
+       extern struct vnode *rootvp;
+       struct proc *p = curproc;       /* XXX */
+       struct iso_mnt *imp;
+       register struct fs *fs;
+       u_int size;
+       int error;
+       struct iso_args args;
+       
+       /*
+        * Get vnodes for swapdev and rootdev.
+        */
+       if (bdevvp(swapdev, &swapdev_vp) || bdevvp(rootdev, &rootvp))
+               panic("isofs_mountroot: can't setup bdevvp's");
+
+       mp = malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK);
+       bzero((char *)mp, (u_long)sizeof(struct mount));
+       mp->mnt_op = &isofs_vfsops;
+       mp->mnt_flag = MNT_RDONLY;
+       args.flags = ISOFSMNT_ROOT;
+       if (error = iso_mountfs(rootvp, mp, p, &args)) {
+               free(mp, M_MOUNT);
+               return (error);
+       }
+       if (error = vfs_lock(mp)) {
+               (void)isofs_unmount(mp, 0, p);
+               free(mp, M_MOUNT);
+               return (error);
+       }
+       TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
+       mp->mnt_flag |= MNT_ROOTFS;
+       mp->mnt_vnodecovered = NULLVP;
+       imp = VFSTOISOFS(mp);
+       bzero(imp->im_fsmnt, sizeof(imp->im_fsmnt));
+       imp->im_fsmnt[0] = '/';
+       bcopy((caddr_t)imp->im_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
+           MNAMELEN);
+       (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
+           &size);
+       bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
+       (void) isofs_statfs(mp, &mp->mnt_stat, p);
+       vfs_unlock(mp);
+       return (0);
+}
+
+/*
+ * Flag to allow forcible unmounting.
+ */
+int iso_doforce = 1;
+
+/*
+ * VFS Operations.
+ *
+ * mount system call
+ */
+isofs_mount(mp, path, data, ndp, p)
+       register struct mount *mp;
+       char *path;
+       caddr_t data;
+       struct nameidata *ndp;
+       struct proc *p;
+{
+       struct vnode *devvp;
+       struct iso_args args;
+       u_int size;
+       int error;
+       struct iso_mnt *imp;
+       
+       if (error = copyin(data, (caddr_t)&args, sizeof (struct iso_args)))
+               return (error);
+       
+       if ((mp->mnt_flag & MNT_RDONLY) == 0)
+               return (EROFS);
+       
+       /*
+        * If updating, check whether changing from read-only to
+        * read/write; if there is no device name, that's all we do.
+        */
+       if (mp->mnt_flag & MNT_UPDATE) {
+               imp = VFSTOISOFS(mp);
+               if (args.fspec == 0)
+                       return (vfs_export(mp, &imp->im_export, &args.export));
+       }
+       /*
+        * Not an update, or updating the name: look up the name
+        * and verify that it refers to a sensible block device.
+        */
+       NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
+       if (error = namei(ndp))
+               return (error);
+       devvp = ndp->ni_vp;
+
+       if (devvp->v_type != VBLK) {
+               vrele(devvp);
+               return ENOTBLK;
+       }
+       if (major(devvp->v_rdev) >= nblkdev) {
+               vrele(devvp);
+               return ENXIO;
+       }
+       if ((mp->mnt_flag & MNT_UPDATE) == 0)
+               error = iso_mountfs(devvp, mp, p, &args);
+       else {
+               if (devvp != imp->im_devvp)
+                       error = EINVAL; /* needs translation */
+               else
+                       vrele(devvp);
+       }
+       if (error) {
+               vrele(devvp);
+               return error;
+       }
+       imp = VFSTOISOFS(mp);
+       (void) copyinstr(path, imp->im_fsmnt, sizeof(imp->im_fsmnt)-1, &size);
+       bzero(imp->im_fsmnt + size, sizeof(imp->im_fsmnt) - size);
+       bcopy((caddr_t)imp->im_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
+           MNAMELEN);
+       (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
+           &size);
+       bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
+       (void) isofs_statfs(mp, &mp->mnt_stat, p);
+       return 0;
+}
+
+/*
+ * Common code for mount and mountroot
+ */
+static iso_mountfs(devvp, mp, p, argp)
+       register struct vnode *devvp;
+       struct mount *mp;
+       struct proc *p;
+       struct iso_args *argp;
+{
+       register struct iso_mnt *isomp = (struct iso_mnt *)0;
+       struct buf *bp = NULL;
+       dev_t dev = devvp->v_rdev;
+       caddr_t base, space;
+       int havepart = 0, blks;
+       int error = EINVAL, i, size;
+       int needclose = 0;
+       int ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
+       extern struct vnode *rootvp;
+       int j;
+       int iso_bsize;
+       int iso_blknum;
+       struct iso_volume_descriptor *vdp;
+       struct iso_primary_descriptor *pri;
+       struct iso_directory_record *rootp;
+       int logical_block_size;
+       
+       if (!ronly)
+               return EROFS;
+       
+       /*
+        * Disallow multiple mounts of the same device.
+        * Disallow mounting of a device that is currently in use
+        * (except for root, which might share swap device for miniroot).
+        * Flush out any old buffers remaining from a previous use.
+        */
+       if (error = vfs_mountedon(devvp))
+               return error;
+       if (vcount(devvp) > 1 && devvp != rootvp)
+               return EBUSY;
+       if (error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0))
+               return (error);
+
+       if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p))
+               return error;
+       needclose = 1;
+       
+       /* This is the "logical sector size".  The standard says this
+        * should be 2048 or the physical sector size on the device,
+        * whichever is greater.  For now, we'll just use a constant.
+        */
+       iso_bsize = ISO_DEFAULT_BLOCK_SIZE;
+       
+       for (iso_blknum = 16; iso_blknum < 100; iso_blknum++) {
+               if (error = bread (devvp, btodb(iso_blknum * iso_bsize),
+                                  iso_bsize, NOCRED, &bp))
+                       goto out;
+               
+               vdp = (struct iso_volume_descriptor *)bp->b_un.b_addr;
+               if (bcmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) != 0) {
+                       error = EINVAL;
+                       goto out;
+               }
+               
+               if (isonum_711 (vdp->type) == ISO_VD_END) {
+                       error = EINVAL;
+                       goto out;
+               }
+               
+               if (isonum_711 (vdp->type) == ISO_VD_PRIMARY)
+                       break;
+               brelse(bp);
+       }
+       
+       if (isonum_711 (vdp->type) != ISO_VD_PRIMARY) {
+               error = EINVAL;
+               goto out;
+       }
+       
+       pri = (struct iso_primary_descriptor *)vdp;
+       
+       logical_block_size = isonum_723 (pri->logical_block_size);
+       
+       if (logical_block_size < DEV_BSIZE || logical_block_size > MAXBSIZE
+           || (logical_block_size & (logical_block_size - 1)) != 0) {
+               error = EINVAL;
+               goto out;
+       }
+       
+       rootp = (struct iso_directory_record *)pri->root_directory_record;
+       
+       isomp = (struct iso_mnt *)malloc(sizeof *isomp,M_ISOFSMNT,M_WAITOK);
+       isomp->logical_block_size = logical_block_size;
+       isomp->volume_space_size = isonum_733 (pri->volume_space_size);
+       bcopy (rootp, isomp->root, sizeof isomp->root);
+       isomp->root_extent = isonum_733 (rootp->extent);
+       isomp->root_size = isonum_733 (rootp->size);
+       
+       isomp->im_bmask = logical_block_size - 1;
+       isomp->im_bshift = 0;
+       while ((1 << isomp->im_bshift) < isomp->logical_block_size)
+               isomp->im_bshift++;
+       
+       bp->b_flags |= B_AGE;
+       brelse(bp);
+       bp = NULL;
+       
+       mp->mnt_data = (qaddr_t)isomp;
+       mp->mnt_stat.f_fsid.val[0] = (long)dev;
+       mp->mnt_stat.f_fsid.val[1] = MOUNT_ISOFS;
+       mp->mnt_maxsymlinklen = 0;
+       mp->mnt_flag |= MNT_LOCAL;
+       isomp->im_mountp = mp;
+       isomp->im_dev = dev;
+       isomp->im_devvp = devvp;
+       
+       devvp->v_specflags |= SI_MOUNTEDON;
+       
+       /* Check the Rock Ridge Extention support */
+       if (!(argp->flags & ISOFSMNT_NORRIP)) {
+               if (error = bread (isomp->im_devvp,
+                                  (isomp->root_extent + isonum_711(rootp->ext_attr_length))
+                                  * isomp->logical_block_size / DEV_BSIZE,
+                                  isomp->logical_block_size,NOCRED,&bp))
+                   goto out;
+               
+               rootp = (struct iso_directory_record *)bp->b_un.b_addr;
+               
+               if ((isomp->rr_skip = isofs_rrip_offset(rootp,isomp)) < 0) {
+                   argp->flags  |= ISOFSMNT_NORRIP;
+               } else {
+                   argp->flags  &= ~ISOFSMNT_GENS;
+               }
+               
+               /*
+                * The contents are valid,
+                * but they will get reread as part of another vnode, so...
+                */
+               bp->b_flags |= B_AGE;
+               brelse(bp);
+               bp = NULL;
+       }
+       isomp->im_flags = argp->flags&(ISOFSMNT_NORRIP|ISOFSMNT_GENS|ISOFSMNT_EXTATT);
+       switch (isomp->im_flags&(ISOFSMNT_NORRIP|ISOFSMNT_GENS)) {
+       default:
+           isomp->iso_ftype = ISO_FTYPE_DEFAULT;
+           break;
+       case ISOFSMNT_GENS|ISOFSMNT_NORRIP:
+           isomp->iso_ftype = ISO_FTYPE_9660;
+           break;
+       case 0:
+           isomp->iso_ftype = ISO_FTYPE_RRIP;
+           break;
+       }
+       
+       return 0;
+out:
+       if (bp)
+               brelse(bp);
+       if (needclose)
+               (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p);
+       if (isomp) {
+               free((caddr_t)isomp, M_ISOFSMNT);
+               mp->mnt_data = (qaddr_t)0;
+       }
+       return error;
+}
+
+/*
+ * Make a filesystem operational.
+ * Nothing to do at the moment.
+ */
+/* ARGSUSED */
+isofs_start(mp, flags, p)
+       struct mount *mp;
+       int flags;
+       struct proc *p;
+{
+       return 0;
+}
+
+/*
+ * unmount system call
+ */
+int
+isofs_unmount(mp, mntflags, p)
+       struct mount *mp;
+       int mntflags;
+       struct proc *p;
+{
+       register struct iso_mnt *isomp;
+       int i, error, ronly, flags = 0;
+       
+       if (mntflags & MNT_FORCE) {
+               if (!iso_doforce || (mp->mnt_flag & MNT_ROOTFS))
+                       return (EINVAL);
+               flags |= FORCECLOSE;
+       }
+#if 0
+       mntflushbuf(mp, 0);
+       if (mntinvalbuf(mp))
+               return EBUSY;
+#endif
+       if (error = vflush(mp, NULLVP, flags))
+               return (error);
+
+       isomp = VFSTOISOFS(mp);
+
+#ifdef ISODEVMAP
+       if (isomp->iso_ftype == ISO_FTYPE_RRIP)
+               iso_dunmap(isomp->im_dev);
+#endif
+       
+       isomp->im_devvp->v_specflags &= ~SI_MOUNTEDON;
+       error = VOP_CLOSE(isomp->im_devvp, FREAD, NOCRED, p);
+       vrele(isomp->im_devvp);
+       free((caddr_t)isomp, M_ISOFSMNT);
+       mp->mnt_data = (qaddr_t)0;
+       mp->mnt_flag &= ~MNT_LOCAL;
+       return (error);
+}
+
+/*
+ * Return root of a filesystem
+ */
+isofs_root(mp, vpp)
+       struct mount *mp;
+       struct vnode **vpp;
+{
+       register struct iso_node *ip;
+       struct iso_node tip, *nip;
+       struct vnode tvp;
+       int error;
+       struct iso_mnt *imp = VFSTOISOFS (mp);
+       struct iso_directory_record *dp;
+       
+       tvp.v_mount = mp;
+       tvp.v_data = &tip;
+       ip = VTOI(&tvp);
+       ip->i_vnode = &tvp;
+       ip->i_dev = imp->im_dev;
+       ip->i_diroff = 0;
+       dp = (struct iso_directory_record *)imp->root;
+       isodirino(&ip->i_number,dp,imp);
+       
+       /*
+        * With RRIP we must use the `.' entry of the root directory.
+        * Simply tell iget, that it's a relocated directory.
+        */
+       error = iso_iget(ip,ip->i_number,
+                        imp->iso_ftype == ISO_FTYPE_RRIP,
+                        &nip,dp);
+       if (error)
+               return error;
+       *vpp = ITOV(nip);
+       return 0;
+}
+
+/*
+ * Do operations associated with quotas, not supported
+ */
+/* ARGSUSED */
+int
+isofs_quotactl(mp, cmd, uid, arg, p)
+       struct mount *mp;
+       int cmd;
+       uid_t uid;
+       caddr_t arg;
+       struct proc *p;
+{
+
+       return (EOPNOTSUPP);
+}
+
+/*
+ * Get file system statistics.
+ */
+isofs_statfs(mp, sbp, p)
+       struct mount *mp;
+       register struct statfs *sbp;
+       struct proc *p;
+{
+       register struct iso_mnt *isomp;
+       register struct fs *fs;
+       
+       isomp = VFSTOISOFS(mp);
+       
+       sbp->f_type = MOUNT_ISOFS;
+       sbp->f_bsize = isomp->logical_block_size;
+       sbp->f_iosize = sbp->f_bsize;   /* XXX */
+       sbp->f_blocks = isomp->volume_space_size;
+       sbp->f_bfree = 0; /* total free blocks */
+       sbp->f_bavail = 0; /* blocks free for non superuser */
+       sbp->f_files =  0; /* total files */
+       sbp->f_ffree = 0; /* free file nodes */
+       if (sbp != &mp->mnt_stat) {
+               bcopy((caddr_t)mp->mnt_stat.f_mntonname,
+                       (caddr_t)&sbp->f_mntonname[0], MNAMELEN);
+               bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
+                       (caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
+       }
+       /* Use the first spare for flags: */
+       sbp->f_spare[0] = isomp->im_flags;
+       return 0;
+}
+
+/* ARGSUSED */
+int
+isofs_sync(mp, waitfor, cred, p)
+       struct mount *mp;
+       int waitfor;
+       struct ucred *cred;
+       struct proc *p;
+{
+       return (0);
+}
+
+/*
+ * Flat namespace lookup.
+ * Currently unsupported.
+ */
+/* ARGSUSED */
+int
+isofs_vget(mp, ino, vpp)
+       struct mount *mp;
+       ino_t ino;
+       struct vnode **vpp;
+{
+
+       return (EOPNOTSUPP);
+}
+
+/*
+ * File handle to vnode
+ *
+ * Have to be really careful about stale file handles:
+ * - check that the inode number is in range
+ * - call iget() to get the locked inode
+ * - check for an unallocated inode (i_mode == 0)
+ * - check that the generation number matches
+ */
+
+struct ifid {
+       ushort  ifid_len;
+       ushort  ifid_pad;
+       int     ifid_ino;
+       long    ifid_start;
+};
+
+/* ARGSUSED */
+int
+isofs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
+       register struct mount *mp;
+       struct fid *fhp;
+       struct mbuf *nam;
+       struct vnode **vpp;
+       int *exflagsp;
+       struct ucred **credanonp;
+{
+       struct vnode                    tvp;
+       int                             error;
+       int                             lbn, off;
+       struct ifid                     *ifhp;
+       struct iso_mnt                  *imp;
+       struct buf                      *bp;
+       struct iso_directory_record     *dirp;
+       struct iso_node                 tip, *ip, *nip;
+       struct netcred                  *np;
+       
+       imp = VFSTOISOFS (mp);
+       ifhp = (struct ifid *)fhp;
+       
+#ifdef ISOFS_DBG
+       printf("fhtovp: ino %d, start %ld\n",
+              ifhp->ifid_ino, ifhp->ifid_start);
+#endif
+       
+       np = vfs_export_lookup(mp, &imp->im_export, nam);
+       if (np == NULL)
+               return (EACCES);
+
+       lbn = iso_lblkno(imp, ifhp->ifid_ino);
+       if (lbn >= imp->volume_space_size) {
+               printf("fhtovp: lbn exceed volume space %d\n", lbn);
+               return (ESTALE);
+       }
+       
+       off = iso_blkoff(imp, ifhp->ifid_ino);
+       if (off + ISO_DIRECTORY_RECORD_SIZE > imp->logical_block_size) {
+               printf("fhtovp: crosses block boundary %d\n",
+                      off + ISO_DIRECTORY_RECORD_SIZE);
+               return (ESTALE);
+       }
+       
+       error = bread(imp->im_devvp, btodb(lbn * imp->logical_block_size),
+                     imp->logical_block_size, NOCRED, &bp);
+       if (error) {
+               printf("fhtovp: bread error %d\n",error);
+               brelse(bp);
+               return (error);
+       }
+       
+       dirp = (struct iso_directory_record *)(bp->b_un.b_addr + off);
+       if (off + isonum_711(dirp->length) > imp->logical_block_size) {
+               brelse(bp);
+               printf("fhtovp: directory crosses block boundary %d[off=%d/len=%d]\n",
+                      off+isonum_711(dirp->length), off,
+                      isonum_711(dirp->length));
+               return (ESTALE);
+       }
+       
+       if (isonum_733(dirp->extent) + isonum_711(dirp->ext_attr_length) !=
+           ifhp->ifid_start) {
+               brelse(bp);
+               printf("fhtovp: file start miss %d vs %d\n",
+                      isonum_733(dirp->extent)+isonum_711(dirp->ext_attr_length),
+                      ifhp->ifid_start);
+               return (ESTALE);
+       }
+       brelse(bp);
+       
+       ip = &tip;
+       tvp.v_mount = mp;
+       tvp.v_data = ip;
+       ip->i_vnode = &tvp;
+       ip->i_dev = imp->im_dev;
+       if (error = iso_iget(ip, ifhp->ifid_ino, 0, &nip, dirp)) {
+               *vpp = NULLVP;
+               printf("fhtovp: failed to get inode\n");
+               return (error);
+       }
+       ip = nip;
+       /*
+        * XXX need generation number?
+        */
+       if (ip->inode.iso_mode == 0) {
+               iso_iput(ip);
+               *vpp = NULLVP;
+               printf("fhtovp: inode mode == 0\n");
+               return (ESTALE);
+       }
+       *vpp = ITOV(ip);
+       *exflagsp = np->netc_exflags;
+       *credanonp = &np->netc_anon;
+       return 0;
+}
+
+/*
+ * Vnode pointer to File handle
+ */
+/* ARGSUSED */
+isofs_vptofh(vp, fhp)
+       struct vnode *vp;
+       struct fid *fhp;
+{
+       register struct iso_node *ip = VTOI(vp);
+       register struct ifid *ifhp;
+       register struct iso_mnt *mp = ip->i_mnt;
+       
+       ifhp = (struct ifid *)fhp;
+       ifhp->ifid_len = sizeof(struct ifid);
+       
+       ifhp->ifid_ino = ip->i_number;
+       ifhp->ifid_start = ip->iso_start;
+       
+#ifdef ISOFS_DBG
+       printf("vptofh: ino %d, start %ld\n",
+              ifhp->ifid_ino,ifhp->ifid_start);
+#endif
+       return 0;
+}
diff --git a/usr/src/sys/isofs/cd9660/cd9660_vnops.c b/usr/src/sys/isofs/cd9660/cd9660_vnops.c
new file mode 100644 (file)
index 0000000..7227906
--- /dev/null
@@ -0,0 +1,1009 @@
+/*-
+ * Copyright (c) 1994
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley
+ * by Pace Willisson (pace@blitz.com).  The Rock Ridge Extension
+ * Support code is derived from software contributed to Berkeley
+ * by Atsushi Murai (amurai@spec.co.jp).
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)cd9660_vnops.c      8.1 (Berkeley) %G%
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/namei.h>
+#include <sys/resourcevar.h>
+#include <sys/kernel.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <sys/conf.h>
+#include <sys/mount.h>
+#include <sys/vnode.h>
+#include <miscfs/specfs/specdev.h>
+#include <miscfs/fifofs/fifo.h>
+#include <sys/malloc.h>
+#include <sys/dir.h>
+
+#include <isofs/cd9660/iso.h>
+#include <isofs/cd9660/isofs_node.h>
+#include <isofs/cd9660/iso_rrip.h>
+
+#if 0
+/*
+ * Mknod vnode call
+ *  Actually remap the device number
+ */
+isofs_mknod(ndp, vap, cred, p)
+       struct nameidata *ndp;
+       struct ucred *cred;
+       struct vattr *vap;
+       struct proc *p;
+{
+#ifndef        ISODEVMAP
+       free(ndp->ni_pnbuf, M_NAMEI);
+       vput(ndp->ni_dvp);
+       vput(ndp->ni_vp);
+       return EINVAL;
+#else
+       register struct vnode *vp;
+       struct iso_node *ip;
+       struct iso_dnode *dp;
+       int error;
+       
+       vp = ndp->ni_vp;
+       ip = VTOI(vp);
+       
+       if (ip->i_mnt->iso_ftype != ISO_FTYPE_RRIP
+           || vap->va_type != vp->v_type
+           || (vap->va_type != VCHR && vap->va_type != VBLK)) {
+               free(ndp->ni_pnbuf, M_NAMEI);
+               vput(ndp->ni_dvp);
+               vput(ndp->ni_vp);
+               return EINVAL;
+       }
+       
+       dp = iso_dmap(ip->i_dev,ip->i_number,1);
+       if (ip->inode.iso_rdev == vap->va_rdev || vap->va_rdev == VNOVAL) {
+               /* same as the unmapped one, delete the mapping */
+               remque(dp);
+               FREE(dp,M_CACHE);
+       } else
+               /* enter new mapping */
+               dp->d_dev = vap->va_rdev;
+       
+       /*
+        * Remove inode so that it will be reloaded by iget and
+        * checked to see if it is an alias of an existing entry
+        * in the inode cache.
+        */
+       vput(vp);
+       vp->v_type = VNON;
+       vgone(vp);
+       return (0);
+#endif
+}
+#endif
+
+/*
+ * Open called.
+ *
+ * Nothing to do.
+ */
+/* ARGSUSED */
+int
+isofs_open(ap)
+       struct vop_open_args /* {
+               struct vnode *a_vp;
+               int  a_mode;
+               struct ucred *a_cred;
+               struct proc *a_p;
+       } */ *ap;
+{
+       return (0);
+}
+
+/*
+ * Close called
+ *
+ * Update the times on the inode on writeable file systems.
+ */
+/* ARGSUSED */
+int
+isofs_close(ap)
+       struct vop_close_args /* {
+               struct vnode *a_vp;
+               int  a_fflag;
+               struct ucred *a_cred;
+               struct proc *a_p;
+       } */ *ap;
+{
+       return (0);
+}
+
+/*
+ * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC.
+ * The mode is shifted to select the owner/group/other fields. The
+ * super user is granted all permissions.
+ */
+/* ARGSUSED */
+isofs_access(ap)
+       struct vop_access_args /* {
+               struct vnode *a_vp;
+               int  a_mode;
+               struct ucred *a_cred;
+               struct proc *a_p;
+       } */ *ap;
+{
+       return (0);
+}
+
+isofs_getattr(ap)
+       struct vop_getattr_args /* {
+               struct vnode *a_vp;
+               struct vattr *a_vap;
+               struct ucred *a_cred;
+               struct proc *a_p;
+       } */ *ap;
+
+{
+       struct vnode *vp = ap->a_vp;
+       register struct vattr *vap = ap->a_vap;
+       register struct iso_node *ip = VTOI(vp);
+       int i;
+
+       vap->va_fsid    = ip->i_dev;
+       vap->va_fileid  = ip->i_number;
+
+       vap->va_mode    = ip->inode.iso_mode;
+       vap->va_nlink   = ip->inode.iso_links;
+       vap->va_uid     = ip->inode.iso_uid;
+       vap->va_gid     = ip->inode.iso_gid;
+       vap->va_atime   = ip->inode.iso_atime;
+       vap->va_mtime   = ip->inode.iso_mtime;
+       vap->va_ctime   = ip->inode.iso_ctime;
+       vap->va_rdev    = ip->inode.iso_rdev;
+
+       vap->va_size    = (u_quad_t) ip->i_size;
+       vap->va_flags   = 0;
+       vap->va_gen = 1;
+       vap->va_blocksize = ip->i_mnt->logical_block_size;
+       vap->va_bytes   = (u_quad_t) ip->i_size;
+       vap->va_type    = vp->v_type;
+       return (0);
+}
+
+#if ISO_DEFAULT_BLOCK_SIZE >= NBPG
+#ifdef DEBUG
+extern int doclusterread;
+#else
+#define doclusterread 1
+#endif
+#else
+/* XXX until cluster routines can handle block sizes less than one page */
+#define doclusterread 0
+#endif
+
+/*
+ * Vnode op for reading.
+ */
+isofs_read(ap)
+       struct vop_read_args /* {
+               struct vnode *a_vp;
+               struct uio *a_uio;
+               int a_ioflag;
+               struct ucred *a_cred;
+       } */ *ap;
+{
+       struct vnode *vp = ap->a_vp;
+       register struct uio *uio = ap->a_uio;
+       register struct iso_node *ip = VTOI(vp);
+       register struct iso_mnt *imp;
+       struct buf *bp;
+       daddr_t lbn, bn, rablock;
+       off_t diff;
+       int rasize, error = 0;
+       long size, n, on;
+       
+       if (uio->uio_resid == 0)
+               return (0);
+       if (uio->uio_offset < 0)
+               return (EINVAL);
+       ip->i_flag |= IACC;
+       imp = ip->i_mnt;
+       do {
+               lbn = iso_lblkno(imp, uio->uio_offset);
+               on = iso_blkoff(imp, uio->uio_offset);
+               n = min((unsigned)(imp->logical_block_size - on),
+                       uio->uio_resid);
+               diff = (off_t)ip->i_size - uio->uio_offset;
+               if (diff <= 0)
+                       return (0);
+               if (diff < n)
+                       n = diff;
+               size = iso_blksize(imp, ip, lbn);
+               rablock = lbn + 1;
+#if 1
+               if (doclusterread) {
+                       if (iso_lblktosize(imp, rablock) <= ip->i_size)
+                               error = cluster_read(vp, (off_t)ip->i_size,
+                                                    lbn, size, NOCRED, &bp);
+                       else 
+                               error = bread(vp, lbn, size, NOCRED, &bp);
+               } else {
+                       if (vp->v_lastr + 1 == lbn &&
+                           iso_lblktosize(imp, rablock) < ip->i_size) {
+                               rasize = iso_blksize(imp, ip, rablock);
+                               error = breadn(vp, lbn, size, &rablock,
+                                              &rasize, 1, NOCRED, &bp);
+                       } else
+                               error = bread(vp, lbn, size, NOCRED, &bp);
+               }
+#endif
+               vp->v_lastr = lbn;
+               n = min(n, size - bp->b_resid);
+               if (error) {
+                       brelse(bp);
+                       return (error);
+               }
+
+               error = uiomove(bp->b_un.b_addr + on, (int)n, uio);
+               if (n + on == imp->logical_block_size ||
+                   uio->uio_offset == (off_t)ip->i_size)
+                       bp->b_flags |= B_AGE;
+               brelse(bp);
+       } while (error == 0 && uio->uio_resid > 0 && n != 0);
+       return (error);
+}
+
+/* ARGSUSED */
+int
+isofs_ioctl(ap)
+       struct vop_ioctl_args /* {
+               struct vnode *a_vp;
+               int  a_command;
+               caddr_t  a_data;
+               int  a_fflag;
+               struct ucred *a_cred;
+               struct proc *a_p;
+       } */ *ap;
+{
+       printf("You did ioctl for isofs !!\n");
+       return (ENOTTY);
+}
+
+/* ARGSUSED */
+int
+isofs_select(ap)
+       struct vop_select_args /* {
+               struct vnode *a_vp;
+               int  a_which;
+               int  a_fflags;
+               struct ucred *a_cred;
+               struct proc *a_p;
+       } */ *ap;
+{
+
+       /*
+        * We should really check to see if I/O is possible.
+        */
+       return (1);
+}
+
+/*
+ * Mmap a file
+ *
+ * NB Currently unsupported.
+ */
+/* ARGSUSED */
+int
+isofs_mmap(ap)
+       struct vop_mmap_args /* {
+               struct vnode *a_vp;
+               int  a_fflags;
+               struct ucred *a_cred;
+               struct proc *a_p;
+       } */ *ap;
+{
+
+       return (EINVAL);
+}
+
+/*
+ * Seek on a file
+ *
+ * Nothing to do, so just return.
+ */
+/* ARGSUSED */
+int
+isofs_seek(ap)
+       struct vop_seek_args /* {
+               struct vnode *a_vp;
+               off_t  a_oldoff;
+               off_t  a_newoff;
+               struct ucred *a_cred;
+       } */ *ap;
+{
+
+       return (0);
+}
+
+/*
+ * Structure for reading directories
+ */
+struct isoreaddir {
+       struct dirent saveent;
+       struct dirent assocent;
+       struct dirent current;
+       off_t saveoff;
+       off_t assocoff;
+       off_t curroff;
+       struct uio *uio;
+       off_t uio_off;
+       u_int *cookiep;
+       int ncookies;
+       int eof;
+};
+
+static int
+iso_uiodir(idp,dp,off)
+       struct isoreaddir *idp;
+       struct dirent *dp;
+       off_t off;
+{
+       int error;
+       
+       dp->d_name[dp->d_namlen] = 0;
+       dp->d_reclen = DIRSIZ(dp);
+       
+       if (idp->uio->uio_resid < dp->d_reclen) {
+               idp->eof = 0;
+               return -1;
+       }
+       
+       if (idp->cookiep) {
+               if (idp->ncookies <= 0) {
+                       idp->eof = 0;
+                       return -1;
+               }
+               
+               *idp->cookiep++ = off;
+               --idp->ncookies;
+       }
+       
+       if (error = uiomove(dp,dp->d_reclen,idp->uio))
+               return error;
+       idp->uio_off = off;
+       return 0;
+}
+
+static int
+iso_shipdir(idp)
+       struct isoreaddir *idp;
+{
+       struct dirent *dp;
+       int cl, sl, assoc;
+       int error;
+       char *cname, *sname;
+       
+       cl = idp->current.d_namlen;
+       cname = idp->current.d_name;
+       if (assoc = cl > 1 && *cname == ASSOCCHAR) {
+               cl--;
+               cname++;
+       }
+       
+       dp = &idp->saveent;
+       sname = dp->d_name;
+       if (!(sl = dp->d_namlen)) {
+               dp = &idp->assocent;
+               sname = dp->d_name + 1;
+               sl = dp->d_namlen - 1;
+       }
+       if (sl > 0) {
+               if (sl != cl
+                   || bcmp(sname,cname,sl)) {
+                       if (idp->assocent.d_namlen) {
+                               if (error = iso_uiodir(idp,&idp->assocent,idp->assocoff))
+                                       return error;
+                               idp->assocent.d_namlen = 0;
+                       }
+                       if (idp->saveent.d_namlen) {
+                               if (error = iso_uiodir(idp,&idp->saveent,idp->saveoff))
+                                       return error;
+                               idp->saveent.d_namlen = 0;
+                       }
+               }
+       }
+       idp->current.d_reclen = DIRSIZ(&idp->current);
+       if (assoc) {
+               idp->assocoff = idp->curroff;
+               bcopy(&idp->current,&idp->assocent,idp->current.d_reclen);
+       } else {
+               idp->saveoff = idp->curroff;
+               bcopy(&idp->current,&idp->saveent,idp->current.d_reclen);
+       }
+       return 0;
+}
+
+/*
+ * Vnode op for readdir
+ * XXX make sure everything still works now that eofflagp and cookiep
+ * are no longer args.
+ */
+int
+isofs_readdir(ap)
+       struct vop_readdir_args /* {
+               struct vnode *a_vp;
+               struct uio *a_uio;
+               struct ucred *a_cred;
+       } */ *ap;
+{
+       register struct uio *uio = ap->a_uio;
+       struct isoreaddir *idp;
+       int entryoffsetinblock;
+       int error = 0;
+       int endsearch;
+       struct iso_directory_record *ep;
+       u_short elen;
+       int reclen;
+       struct iso_mnt *imp;
+       struct iso_node *ip;
+       struct buf *bp = NULL;
+       
+       ip = VTOI(ap->a_vp);
+       imp = ip->i_mnt;
+       
+       MALLOC(idp,struct isoreaddir *,sizeof(*idp),M_TEMP,M_WAITOK);
+       idp->saveent.d_namlen = 0;
+       idp->assocent.d_namlen = 0;
+       idp->uio = uio;
+#if 0
+       idp->cookiep = cookies;
+       idp->ncookies = ncookies;
+       idp->eof = 1;
+#else
+       idp->cookiep = 0;
+#endif
+       idp->curroff = uio->uio_offset;
+       
+       entryoffsetinblock = iso_blkoff(imp, idp->curroff);
+       if (entryoffsetinblock != 0) {
+               if (error = iso_blkatoff(ip, idp->curroff, &bp)) {
+                       FREE(idp,M_TEMP);
+                       return (error);
+               }
+       }
+       
+       endsearch = ip->i_size;
+       
+       while (idp->curroff < endsearch) {
+               /*
+                * If offset is on a block boundary,
+                * read the next directory block.
+                * Release previous if it exists.
+                */
+               
+               if (iso_blkoff(imp, idp->curroff) == 0) {
+                       if (bp != NULL)
+                               brelse(bp);
+                       if (error = iso_blkatoff(ip, idp->curroff, &bp))
+                               break;
+                       entryoffsetinblock = 0;
+               }
+               /*
+                * Get pointer to next entry.
+                */
+               
+               ep = (struct iso_directory_record *)
+                       (bp->b_un.b_addr + entryoffsetinblock);
+               
+               reclen = isonum_711 (ep->length);
+               if (reclen == 0) {
+                       /* skip to next block, if any */
+                       idp->curroff = roundup (idp->curroff,
+                                               imp->logical_block_size);
+                       continue;
+               }
+               
+               if (reclen < ISO_DIRECTORY_RECORD_SIZE) {
+                       error = EINVAL;
+                       /* illegal entry, stop */
+                       break;
+               }
+               
+               if (entryoffsetinblock + reclen > imp->logical_block_size) {
+                       error = EINVAL;
+                       /* illegal directory, so stop looking */
+                       break;
+               }
+               
+               idp->current.d_namlen = isonum_711 (ep->name_len);
+               if (isonum_711(ep->flags)&2)
+                       isodirino(&idp->current.d_fileno,ep,imp);
+               else
+                       idp->current.d_fileno = dbtob(bp->b_blkno) +
+                               idp->curroff;
+               
+               if (reclen < ISO_DIRECTORY_RECORD_SIZE + idp->current.d_namlen) {
+                       error = EINVAL;
+                       /* illegal entry, stop */
+                       break;
+               }
+               
+               idp->curroff += reclen;
+               /*
+                *
+                */
+               switch (imp->iso_ftype) {
+               case ISO_FTYPE_RRIP:
+                       isofs_rrip_getname(ep,idp->current.d_name,
+                                          (u_short *)&idp->current.d_namlen,
+                                          &idp->current.d_fileno,imp);
+                       if (idp->current.d_namlen)
+                               error = iso_uiodir(idp,&idp->current,idp->curroff);
+                       break;
+               default:        /* ISO_FTYPE_DEFAULT || ISO_FTYPE_9660 */
+                       strcpy(idp->current.d_name,"..");
+                       switch (ep->name[0]) {
+                       case 0:
+                               idp->current.d_namlen = 1;
+                               error = iso_uiodir(idp,&idp->current,idp->curroff);
+                               break;
+                       case 1:
+                               idp->current.d_namlen = 2;
+                               error = iso_uiodir(idp,&idp->current,idp->curroff);
+                               break;
+                       default:
+                               isofntrans(ep->name,idp->current.d_namlen,
+                                          idp->current.d_name, &elen,
+                                          imp->iso_ftype == ISO_FTYPE_9660,
+                                          isonum_711(ep->flags)&4);
+                               idp->current.d_namlen = (u_char)elen;
+                               if (imp->iso_ftype == ISO_FTYPE_DEFAULT)
+                                       error = iso_shipdir(idp);
+                               else
+                                       error = iso_uiodir(idp,&idp->current,idp->curroff);
+                               break;
+                       }
+               }
+               if (error)
+                       break;
+               
+               entryoffsetinblock += reclen;
+       }
+       
+       if (!error && imp->iso_ftype == ISO_FTYPE_DEFAULT) {
+               idp->current.d_namlen = 0;
+               error = iso_shipdir(idp);
+       }
+       if (error < 0)
+               error = 0;
+       
+       if (bp)
+               brelse (bp);
+
+       uio->uio_offset = idp->uio_off;
+#if 0
+       *eofflagp = idp->eof;
+#endif
+       
+       FREE(idp,M_TEMP);
+       
+       return (error);
+}
+
+/*
+ * Return target name of a symbolic link
+ * Shouldn't we get the parent vnode and read the data from there?
+ * This could eventually result in deadlocks in isofs_lookup.
+ * But otherwise the block read here is in the block buffer two times.
+ */
+typedef struct iso_directory_record ISODIR;
+typedef struct iso_node             ISONODE;
+typedef struct iso_mnt              ISOMNT;
+int
+isofs_readlink(ap)
+       struct vop_readlink_args /* {
+               struct vnode *a_vp;
+               struct uio *a_uio;
+               struct ucred *a_cred;
+       } */ *ap;
+{
+       ISONODE *ip;
+       ISODIR  *dirp;                   
+       ISOMNT  *imp;
+       struct  buf *bp;
+       u_short symlen;
+       int     error;
+       char    *symname;
+       ino_t   ino;
+       
+       ip  = VTOI(ap->a_vp);
+       imp = ip->i_mnt;
+       
+       if (imp->iso_ftype != ISO_FTYPE_RRIP)
+               return EINVAL;
+       
+       /*
+        * Get parents directory record block that this inode included.
+        */
+       error = bread(imp->im_devvp,
+                     (daddr_t)(ip->i_number / DEV_BSIZE),
+                     imp->logical_block_size,
+                     NOCRED,
+                     &bp);
+       if (error) {
+               brelse(bp);
+               return EINVAL;
+       }
+
+       /*
+        * Setup the directory pointer for this inode
+        */
+       dirp = (ISODIR *)(bp->b_un.b_addr + (ip->i_number & imp->im_bmask));
+#ifdef DEBUG
+       printf("lbn=%d,off=%d,bsize=%d,DEV_BSIZE=%d, dirp= %08x, b_addr=%08x, offset=%08x(%08x)\n",
+              (daddr_t)(ip->i_number >> imp->im_bshift),
+              ip->i_number & imp->im_bmask,
+              imp->logical_block_size,
+              DEV_BSIZE,
+              dirp,
+              bp->b_un.b_addr,
+              ip->i_number,
+              ip->i_number & imp->im_bmask );
+#endif
+       
+       /*
+        * Just make sure, we have a right one....
+        *   1: Check not cross boundary on block
+        */
+       if ((ip->i_number & imp->im_bmask) + isonum_711(dirp->length)
+           > imp->logical_block_size) {
+               brelse(bp);
+               return EINVAL;
+       }
+       
+       /*
+        * Now get a buffer
+        * Abuse a namei buffer for now.
+        */
+       MALLOC(symname,char *,MAXPATHLEN,M_NAMEI,M_WAITOK);
+       
+       /*
+        * Ok, we just gathering a symbolic name in SL record.
+        */
+       if (isofs_rrip_getsymname(dirp,symname,&symlen,imp) == 0) {
+               FREE(symname,M_NAMEI);
+               brelse(bp);
+               return EINVAL;
+       }
+       /*
+        * Don't forget before you leave from home ;-)
+        */
+       brelse(bp);
+       
+       /*
+        * return with the symbolic name to caller's.
+        */
+       error = uiomove(symname,symlen,ap->a_uio);
+       
+       FREE(symname,M_NAMEI);
+       
+       return error;
+}
+
+/*
+ * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually
+ * done. If a buffer has been saved in anticipation of a CREATE, delete it.
+ */
+int
+isofs_abortop(ap)
+       struct vop_abortop_args /* {
+               struct vnode *a_dvp;
+               struct componentname *a_cnp;
+       } */ *ap;
+{
+       if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF)
+               FREE(ap->a_cnp->cn_pnbuf, M_NAMEI);
+       return 0;
+}
+
+/*
+ * Lock an inode.
+ */
+int
+isofs_lock(ap)
+       struct vop_lock_args /* {
+               struct vnode *a_vp;
+       } */ *ap;
+{
+       register struct iso_node *ip = VTOI(ap->a_vp);
+
+       ISO_ILOCK(ip);
+       return 0;
+}
+
+/*
+ * Unlock an inode.
+ */
+int
+isofs_unlock(ap)
+       struct vop_unlock_args /* {
+               struct vnode *a_vp;
+       } */ *ap;
+{
+       register struct iso_node *ip = VTOI(ap->a_vp);
+
+       if (!(ip->i_flag & ILOCKED))
+               panic("isofs_unlock NOT LOCKED");
+       ISO_IUNLOCK(ip);
+       return 0;
+}
+
+/*
+ * Check for a locked inode.
+ */
+int
+isofs_islocked(ap)
+       struct vop_islocked_args /* {
+               struct vnode *a_vp;
+       } */ *ap;
+{
+
+       if (VTOI(ap->a_vp)->i_flag & ILOCKED)
+               return 1;
+       return 0;
+}
+
+/*
+ * Calculate the logical to physical mapping if not done already,
+ * then call the device strategy routine.
+ */
+int
+isofs_strategy(ap)
+       struct vop_strategy_args /* {
+               struct buf *a_bp;
+       } */ *ap;
+{
+       register struct buf *bp = ap->a_bp;
+       register struct vnode *vp = bp->b_vp;
+       register struct iso_node *ip;
+       int error;
+
+       ip = VTOI(vp);
+       if (vp->v_type == VBLK || vp->v_type == VCHR)
+               panic("isofs_strategy: spec");
+       if (bp->b_blkno == bp->b_lblkno) {
+               if (error =
+                   VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL)) {
+                       bp->b_error = error;
+                       bp->b_flags |= B_ERROR;
+                       biodone(bp);
+                       return (error);
+               }
+               if ((long)bp->b_blkno == -1)
+                       clrbuf(bp);
+       }
+       if ((long)bp->b_blkno == -1) {
+               biodone(bp);
+               return (0);
+       }
+       vp = ip->i_devvp;
+       bp->b_dev = vp->v_rdev;
+       VOCALL (vp->v_op, VOFFSET(vop_strategy), ap);
+       return (0);
+}
+
+/*
+ * Print out the contents of an inode.
+ */
+int
+isofs_print(ap)
+       struct vop_print_args /* {
+               struct vnode *a_vp;
+       } */ *ap;
+{
+       printf("tag VT_ISOFS, isofs vnode\n");
+       return 0;
+}
+
+/*
+ * Unsupported operation
+ */
+int
+isofs_enotsupp()
+{
+
+       return (EOPNOTSUPP);
+}
+
+/*
+ * Global vfs data structures for isofs
+ */
+#define isofs_create ((int (*) __P((struct  vop_create_args *)))isofs_enotsupp)
+#define isofs_mknod ((int (*) __P((struct  vop_mknod_args *)))isofs_enotsupp)
+#define isofs_setattr \
+       ((int (*) __P((struct  vop_setattr_args *)))isofs_enotsupp)
+#define isofs_write ((int (*) __P((struct  vop_write_args *)))isofs_enotsupp)
+#define isofs_fsync ((int (*) __P((struct  vop_fsync_args *)))nullop)
+#define isofs_remove ((int (*) __P((struct  vop_remove_args *)))isofs_enotsupp)
+#define isofs_link ((int (*) __P((struct  vop_link_args *)))isofs_enotsupp)
+#define isofs_rename ((int (*) __P((struct  vop_rename_args *)))isofs_enotsupp)
+#define isofs_mkdir ((int (*) __P((struct  vop_mkdir_args *)))isofs_enotsupp)
+#define isofs_rmdir ((int (*) __P((struct  vop_rmdir_args *)))isofs_enotsupp)
+#define isofs_symlink \
+       ((int (*) __P((struct vop_symlink_args *)))isofs_enotsupp)
+#define isofs_pathconf \
+       ((int (*) __P((struct vop_pathconf_args *)))isofs_enotsupp)
+#define isofs_advlock \
+       ((int (*) __P((struct vop_advlock_args *)))isofs_enotsupp)
+#define isofs_blkatoff \
+       ((int (*) __P((struct  vop_blkatoff_args *)))isofs_enotsupp)
+#define isofs_valloc ((int(*) __P(( \
+               struct vnode *pvp, \
+               int mode, \
+               struct ucred *cred, \
+               struct vnode **vpp))) isofs_enotsupp)
+#define isofs_vfree ((int (*) __P((struct  vop_vfree_args *)))isofs_enotsupp)
+#define isofs_truncate \
+       ((int (*) __P((struct  vop_truncate_args *)))isofs_enotsupp)
+#define isofs_update ((int (*) __P((struct  vop_update_args *)))isofs_enotsupp)
+#define isofs_bwrite ((int (*) __P((struct  vop_bwrite_args *)))isofs_enotsupp)
+
+/*
+ * Global vfs data structures for nfs
+ */
+int (**isofs_vnodeop_p)();
+struct vnodeopv_entry_desc isofs_vnodeop_entries[] = {
+       { &vop_default_desc, vn_default_error },
+       { &vop_lookup_desc, isofs_lookup },     /* lookup */
+       { &vop_create_desc, isofs_create },     /* create */
+       { &vop_mknod_desc, isofs_mknod },       /* mknod */
+       { &vop_open_desc, isofs_open },         /* open */
+       { &vop_close_desc, isofs_close },       /* close */
+       { &vop_access_desc, isofs_access },     /* access */
+       { &vop_getattr_desc, isofs_getattr },   /* getattr */
+       { &vop_setattr_desc, isofs_setattr },   /* setattr */
+       { &vop_read_desc, isofs_read },         /* read */
+       { &vop_write_desc, isofs_write },       /* write */
+       { &vop_ioctl_desc, isofs_ioctl },       /* ioctl */
+       { &vop_select_desc, isofs_select },     /* select */
+       { &vop_mmap_desc, isofs_mmap },         /* mmap */
+       { &vop_fsync_desc, isofs_fsync },       /* fsync */
+       { &vop_seek_desc, isofs_seek },         /* seek */
+       { &vop_remove_desc, isofs_remove },     /* remove */
+       { &vop_link_desc, isofs_link },         /* link */
+       { &vop_rename_desc, isofs_rename },     /* rename */
+       { &vop_mkdir_desc, isofs_mkdir },       /* mkdir */
+       { &vop_rmdir_desc, isofs_rmdir },       /* rmdir */
+       { &vop_symlink_desc, isofs_symlink },   /* symlink */
+       { &vop_readdir_desc, isofs_readdir },   /* readdir */
+       { &vop_readlink_desc, isofs_readlink }, /* readlink */
+       { &vop_abortop_desc, isofs_abortop },   /* abortop */
+       { &vop_inactive_desc, isofs_inactive }, /* inactive */
+       { &vop_reclaim_desc, isofs_reclaim },   /* reclaim */
+       { &vop_lock_desc, isofs_lock },         /* lock */
+       { &vop_unlock_desc, isofs_unlock },     /* unlock */
+       { &vop_bmap_desc, isofs_bmap },         /* bmap */
+       { &vop_strategy_desc, isofs_strategy }, /* strategy */
+       { &vop_print_desc, isofs_print },       /* print */
+       { &vop_islocked_desc, isofs_islocked }, /* islocked */
+       { &vop_pathconf_desc, isofs_pathconf }, /* pathconf */
+       { &vop_advlock_desc, isofs_advlock },   /* advlock */
+       { &vop_blkatoff_desc, isofs_blkatoff }, /* blkatoff */
+       { &vop_valloc_desc, isofs_valloc },     /* valloc */
+       { &vop_vfree_desc, isofs_vfree },       /* vfree */
+       { &vop_truncate_desc, isofs_truncate }, /* truncate */
+       { &vop_update_desc, isofs_update },     /* update */
+       { &vop_bwrite_desc, vn_bwrite },
+       { (struct vnodeop_desc*)NULL, (int(*)())NULL }
+};
+struct vnodeopv_desc isofs_vnodeop_opv_desc =
+       { &isofs_vnodeop_p, isofs_vnodeop_entries };
+
+/*
+ * Special device vnode ops
+ */
+int (**isofs_specop_p)();
+struct vnodeopv_entry_desc isofs_specop_entries[] = {
+       { &vop_default_desc, vn_default_error },
+       { &vop_lookup_desc, spec_lookup },      /* lookup */
+       { &vop_create_desc, isofs_create },     /* create */
+       { &vop_mknod_desc, isofs_mknod },       /* mknod */
+       { &vop_open_desc, spec_open },          /* open */
+       { &vop_close_desc, spec_close },        /* close */
+       { &vop_access_desc, isofs_access },     /* access */
+       { &vop_getattr_desc, isofs_getattr },   /* getattr */
+       { &vop_setattr_desc, isofs_setattr },   /* setattr */
+       { &vop_read_desc, spec_read },          /* read */
+       { &vop_write_desc, spec_write },        /* write */
+       { &vop_ioctl_desc, spec_ioctl },        /* ioctl */
+       { &vop_select_desc, spec_select },      /* select */
+       { &vop_mmap_desc, spec_mmap },          /* mmap */
+       { &vop_fsync_desc, spec_fsync },        /* fsync */
+       { &vop_seek_desc, spec_seek },          /* seek */
+       { &vop_remove_desc, isofs_remove },     /* remove */
+       { &vop_link_desc, isofs_link },         /* link */
+       { &vop_rename_desc, isofs_rename },     /* rename */
+       { &vop_mkdir_desc, isofs_mkdir },       /* mkdir */
+       { &vop_rmdir_desc, isofs_rmdir },       /* rmdir */
+       { &vop_symlink_desc, isofs_symlink },   /* symlink */
+       { &vop_readdir_desc, spec_readdir },    /* readdir */
+       { &vop_readlink_desc, spec_readlink },  /* readlink */
+       { &vop_abortop_desc, spec_abortop },    /* abortop */
+       { &vop_inactive_desc, isofs_inactive }, /* inactive */
+       { &vop_reclaim_desc, isofs_reclaim },   /* reclaim */
+       { &vop_lock_desc, isofs_lock },         /* lock */
+       { &vop_unlock_desc, isofs_unlock },     /* unlock */
+       { &vop_bmap_desc, spec_bmap },          /* bmap */
+               /* XXX strategy: panics, should be notsupp instead? */
+       { &vop_strategy_desc, isofs_strategy }, /* strategy */
+       { &vop_print_desc, isofs_print },       /* print */
+       { &vop_islocked_desc, isofs_islocked }, /* islocked */
+       { &vop_pathconf_desc, spec_pathconf },  /* pathconf */
+       { &vop_advlock_desc, spec_advlock },    /* advlock */
+       { &vop_blkatoff_desc, spec_blkatoff },  /* blkatoff */
+       { &vop_valloc_desc, spec_valloc },      /* valloc */
+       { &vop_vfree_desc, spec_vfree },        /* vfree */
+       { &vop_truncate_desc, spec_truncate },  /* truncate */
+       { &vop_update_desc, isofs_update },     /* update */
+       { &vop_bwrite_desc, vn_bwrite },
+       { (struct vnodeop_desc*)NULL, (int(*)())NULL }
+};
+struct vnodeopv_desc isofs_specop_opv_desc =
+       { &isofs_specop_p, isofs_specop_entries };
+
+#ifdef FIFO
+int (**isofs_fifoop_p)();
+struct vnodeopv_entry_desc isofs_fifoop_entries[] = {
+       { &vop_default_desc, vn_default_error },
+       { &vop_lookup_desc, fifo_lookup },      /* lookup */
+       { &vop_create_desc, isofs_create },     /* create */
+       { &vop_mknod_desc, isofs_mknod },       /* mknod */
+       { &vop_open_desc, fifo_open },          /* open */
+       { &vop_close_desc, fifo_close },        /* close */
+       { &vop_access_desc, isofs_access },     /* access */
+       { &vop_getattr_desc, isofs_getattr },   /* getattr */
+       { &vop_setattr_desc, isofs_setattr },   /* setattr */
+       { &vop_read_desc, fifo_read },          /* read */
+       { &vop_write_desc, fifo_write },        /* write */
+       { &vop_ioctl_desc, fifo_ioctl },        /* ioctl */
+       { &vop_select_desc, fifo_select },      /* select */
+       { &vop_mmap_desc, fifo_mmap },          /* mmap */
+       { &vop_fsync_desc, fifo_fsync },        /* fsync */
+       { &vop_seek_desc, fifo_seek },          /* seek */
+       { &vop_remove_desc, isofs_remove },     /* remove */
+       { &vop_link_desc, isofs_link },         /* link */
+       { &vop_rename_desc, isofs_rename },     /* rename */
+       { &vop_mkdir_desc, isofs_mkdir },       /* mkdir */
+       { &vop_rmdir_desc, isofs_rmdir },       /* rmdir */
+       { &vop_symlink_desc, isofs_symlink },   /* symlink */
+       { &vop_readdir_desc, fifo_readdir },    /* readdir */
+       { &vop_readlink_desc, fifo_readlink },  /* readlink */
+       { &vop_abortop_desc, fifo_abortop },    /* abortop */
+       { &vop_inactive_desc, isofs_inactive }, /* inactive */
+       { &vop_reclaim_desc, isofs_reclaim },   /* reclaim */
+       { &vop_lock_desc, isofs_lock },         /* lock */
+       { &vop_unlock_desc, isofs_unlock },     /* unlock */
+       { &vop_bmap_desc, fifo_bmap },          /* bmap */
+       { &vop_strategy_desc, fifo_badop },     /* strategy */
+       { &vop_print_desc, isofs_print },       /* print */
+       { &vop_islocked_desc, isofs_islocked }, /* islocked */
+       { &vop_pathconf_desc, fifo_pathconf },  /* pathconf */
+       { &vop_advlock_desc, fifo_advlock },    /* advlock */
+       { &vop_blkatoff_desc, fifo_blkatoff },  /* blkatoff */
+       { &vop_valloc_desc, fifo_valloc },      /* valloc */
+       { &vop_vfree_desc, fifo_vfree },        /* vfree */
+       { &vop_truncate_desc, fifo_truncate },  /* truncate */
+       { &vop_update_desc, isofs_update },     /* update */
+       { &vop_bwrite_desc, vn_bwrite },
+       { (struct vnodeop_desc*)NULL, (int(*)())NULL }
+};
+struct vnodeopv_desc isofs_fifoop_opv_desc =
+       { &isofs_fifoop_p, isofs_fifoop_entries };
+#endif /* FIFO */
diff --git a/usr/src/sys/isofs/cd9660/iso.h b/usr/src/sys/isofs/cd9660/iso.h
new file mode 100644 (file)
index 0000000..dc5c3af
--- /dev/null
@@ -0,0 +1,230 @@
+/*-
+ * Copyright (c) 1994
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley
+ * by Pace Willisson (pace@blitz.com).  The Rock Ridge Extension
+ * Support code is derived from software contributed to Berkeley
+ * by Atsushi Murai (amurai@spec.co.jp).
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)iso.h       8.1 (Berkeley) %G%
+ */
+
+#define ISODCL(from, to) (to - from + 1)
+
+struct iso_volume_descriptor {
+       char type[ISODCL(1,1)]; /* 711 */
+       char id[ISODCL(2,6)];
+       char version[ISODCL(7,7)];
+       char data[ISODCL(8,2048)];
+};
+
+/* volume descriptor types */
+#define ISO_VD_PRIMARY 1
+#define ISO_VD_END 255
+
+#define ISO_STANDARD_ID "CD001"
+#define ISO_ECMA_ID     "CDW01"
+
+struct iso_primary_descriptor {
+       char type                       [ISODCL (  1,   1)]; /* 711 */
+       char id                         [ISODCL (  2,   6)];
+       char version                    [ISODCL (  7,   7)]; /* 711 */
+       char unused1                    [ISODCL (  8,   8)];
+       char system_id                  [ISODCL (  9,  40)]; /* achars */
+       char volume_id                  [ISODCL ( 41,  72)]; /* dchars */
+       char unused2                    [ISODCL ( 73,  80)];
+       char volume_space_size          [ISODCL ( 81,  88)]; /* 733 */
+       char unused3                    [ISODCL ( 89, 120)];
+       char volume_set_size            [ISODCL (121, 124)]; /* 723 */
+       char volume_sequence_number     [ISODCL (125, 128)]; /* 723 */
+       char logical_block_size         [ISODCL (129, 132)]; /* 723 */
+       char path_table_size            [ISODCL (133, 140)]; /* 733 */
+       char type_l_path_table          [ISODCL (141, 144)]; /* 731 */
+       char opt_type_l_path_table      [ISODCL (145, 148)]; /* 731 */
+       char type_m_path_table          [ISODCL (149, 152)]; /* 732 */
+       char opt_type_m_path_table      [ISODCL (153, 156)]; /* 732 */
+       char root_directory_record      [ISODCL (157, 190)]; /* 9.1 */
+       char volume_set_id              [ISODCL (191, 318)]; /* dchars */
+       char publisher_id               [ISODCL (319, 446)]; /* achars */
+       char preparer_id                [ISODCL (447, 574)]; /* achars */
+       char application_id             [ISODCL (575, 702)]; /* achars */
+       char copyright_file_id          [ISODCL (703, 739)]; /* 7.5 dchars */
+       char abstract_file_id           [ISODCL (740, 776)]; /* 7.5 dchars */
+       char bibliographic_file_id      [ISODCL (777, 813)]; /* 7.5 dchars */
+       char creation_date              [ISODCL (814, 830)]; /* 8.4.26.1 */
+       char modification_date          [ISODCL (831, 847)]; /* 8.4.26.1 */
+       char expiration_date            [ISODCL (848, 864)]; /* 8.4.26.1 */
+       char effective_date             [ISODCL (865, 881)]; /* 8.4.26.1 */
+       char file_structure_version     [ISODCL (882, 882)]; /* 711 */
+       char unused4                    [ISODCL (883, 883)];
+       char application_data           [ISODCL (884, 1395)];
+       char unused5                    [ISODCL (1396, 2048)];
+};
+#define ISO_DEFAULT_BLOCK_SIZE         2048
+
+struct iso_directory_record {
+       char length                     [ISODCL (1, 1)]; /* 711 */
+       char ext_attr_length            [ISODCL (2, 2)]; /* 711 */
+       unsigned char extent            [ISODCL (3, 10)]; /* 733 */
+       unsigned char size              [ISODCL (11, 18)]; /* 733 */
+       char date                       [ISODCL (19, 25)]; /* 7 by 711 */
+       char flags                      [ISODCL (26, 26)];
+       char file_unit_size             [ISODCL (27, 27)]; /* 711 */
+       char interleave                 [ISODCL (28, 28)]; /* 711 */
+       char volume_sequence_number     [ISODCL (29, 32)]; /* 723 */
+       char name_len                   [ISODCL (33, 33)]; /* 711 */
+       char name                       [0];
+};
+/* can't take sizeof(iso_directory_record), because of possible alignment
+   of the last entry (34 instead of 33) */
+#define ISO_DIRECTORY_RECORD_SIZE      33
+
+struct iso_extended_attributes {
+       unsigned char owner             [ISODCL (1, 4)]; /* 723 */
+       unsigned char group             [ISODCL (5, 8)]; /* 723 */
+       unsigned char perm              [ISODCL (9, 10)]; /* 9.5.3 */
+       char ctime                      [ISODCL (11, 27)]; /* 8.4.26.1 */
+       char mtime                      [ISODCL (28, 44)]; /* 8.4.26.1 */
+       char xtime                      [ISODCL (45, 61)]; /* 8.4.26.1 */
+       char ftime                      [ISODCL (62, 78)]; /* 8.4.26.1 */
+       char recfmt                     [ISODCL (79, 79)]; /* 711 */
+       char recattr                    [ISODCL (80, 80)]; /* 711 */
+       unsigned char reclen            [ISODCL (81, 84)]; /* 723 */
+       char system_id                  [ISODCL (85, 116)]; /* achars */
+       char system_use                 [ISODCL (117, 180)];
+       char version                    [ISODCL (181, 181)]; /* 711 */
+       char len_esc                    [ISODCL (182, 182)]; /* 711 */
+       char reserved                   [ISODCL (183, 246)];
+       unsigned char len_au            [ISODCL (247, 250)]; /* 723 */
+};
+
+/* CD-ROM Format type */
+enum ISO_FTYPE  { ISO_FTYPE_DEFAULT, ISO_FTYPE_9660, ISO_FTYPE_RRIP, ISO_FTYPE_ECMA };
+
+#ifndef        ISOFSMNT_ROOT
+#define        ISOFSMNT_ROOT   0
+#endif
+
+struct iso_mnt {
+       int im_flags;
+
+       struct mount *im_mountp;
+       dev_t im_dev;
+       struct vnode *im_devvp;
+
+       int logical_block_size;
+       int im_bshift;
+       int im_bmask;
+       
+       int volume_space_size;
+       char im_fsmnt[50];
+       struct netexport im_export;
+       
+       char root[ISODCL (157, 190)];
+       int root_extent;
+       int root_size;
+       enum ISO_FTYPE  iso_ftype;
+       
+       int rr_skip;
+       int rr_skip0;
+};
+
+#define VFSTOISOFS(mp) ((struct iso_mnt *)((mp)->mnt_data))
+
+#define iso_blkoff(imp, loc) ((loc) & (imp)->im_bmask)
+#define iso_lblkno(imp, loc) ((loc) >> (imp)->im_bshift)
+#define iso_blksize(imp, ip, lbn) ((imp)->logical_block_size)
+#define iso_lblktosize(imp, blk) ((blk) << (imp)->im_bshift)
+
+int isofs_mount __P((struct mount *,
+           char *, caddr_t, struct nameidata *, struct proc *));
+int isofs_start __P((struct mount *, int, struct proc *));
+int isofs_unmount __P((struct mount *, int, struct proc *));
+int isofs_root __P((struct mount *, struct vnode **));
+int isofs_quotactl __P((struct mount *, int, uid_t, caddr_t, struct proc *));
+int isofs_statfs __P((struct mount *, struct statfs *, struct proc *));
+int isofs_sync __P((struct mount *, int, struct ucred *, struct proc *));
+int isofs_vget __P((struct mount *, ino_t, struct vnode **));
+int isofs_fhtovp __P((struct mount *, struct fid *, struct mbuf *,
+           struct vnode **, int *, struct ucred **));
+int isofs_vptofh __P((struct vnode *, struct fid *));
+int isofs_init __P(());
+
+struct iso_node;
+int iso_blkatoff __P((struct iso_node *ip, long offset, struct buf **bpp)); 
+int iso_iget __P((struct iso_node *xp, ino_t ino, int relocated,
+                 struct iso_node **ipp, struct iso_directory_record *isodir));
+int iso_iput __P((struct iso_node *ip)); 
+int iso_ilock __P((struct iso_node *ip)); 
+int iso_iunlock __P((struct iso_node *ip)); 
+int isofs_mountroot __P((void)); 
+
+extern int (**isofs_vnodeop_p)();
+
+extern inline int
+isonum_711(p)
+       unsigned char *p;
+{
+       return *p;
+}
+
+extern inline int
+isonum_712(p)
+       char *p;
+{
+       return *p;
+}
+
+extern inline int
+isonum_721(p)
+       unsigned char *p;
+{
+       return *p|((char)p[1] << 8);
+}
+
+extern inline int
+isonum_722(p)
+       unsigned char *p;
+{
+       return ((char)*p << 8)|p[1];
+}
+
+extern inline int
+isonum_723(p)
+       unsigned char *p;
+{
+       return isonum_721(p);
+}
+
+extern inline int
+isonum_731(p)
+       unsigned char *p;
+{
+       return *p|(p[1] << 8)|(p[2] << 16)|(p[3] << 24);
+}
+
+extern inline int
+isonum_732(p)
+       unsigned char *p;
+{
+       return (*p << 24)|(p[1] << 16)|(p[2] << 8)|p[3];
+}
+
+extern inline int
+isonum_733(p)
+       unsigned char *p;
+{
+       return isonum_731(p);
+}
+
+int isofncmp __P((unsigned char *, int, unsigned char *, int));
+void isofntrans __P((unsigned char *, int, unsigned char *, unsigned short *,
+                    int, int));
+
+/*
+ * Associated files have a leading '='.
+ */
+#define        ASSOCCHAR       '='
diff --git a/usr/src/sys/isofs/cd9660/iso_rrip.h b/usr/src/sys/isofs/cd9660/iso_rrip.h
new file mode 100644 (file)
index 0000000..ee639d0
--- /dev/null
@@ -0,0 +1,57 @@
+/*-
+ * Copyright (c) 1993, 1994
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley
+ * by Pace Willisson (pace@blitz.com).  The Rock Ridge Extension
+ * Support code is derived from software contributed to Berkeley
+ * by Atsushi Murai (amurai@spec.co.jp).
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)iso_rrip.h  8.1 (Berkeley) %G%
+ */
+
+
+/*
+ *     Analyze function flag (similar to RR field bits)
+ */
+#define        ISO_SUSP_ATTR           0x0001
+#define        ISO_SUSP_DEVICE         0x0002
+#define        ISO_SUSP_SLINK          0x0004
+#define        ISO_SUSP_ALTNAME        0x0008
+#define        ISO_SUSP_CLINK          0x0010
+#define        ISO_SUSP_PLINK          0x0020
+#define        ISO_SUSP_RELDIR         0x0040
+#define        ISO_SUSP_TSTAMP         0x0080
+#define        ISO_SUSP_IDFLAG         0x0100
+#define        ISO_SUSP_EXTREF         0x0200
+#define        ISO_SUSP_CONT           0x0400
+#define        ISO_SUSP_OFFSET         0x0800
+#define        ISO_SUSP_STOP           0x1000
+#define        ISO_SUSP_UNKNOWN        0x8000
+
+typedef struct {
+       struct iso_node *inop;
+       int             fields;         /* interesting fields in this analysis */
+       daddr_t         iso_ce_blk;     /* block of continuation area */
+       off_t           iso_ce_off;     /* offset of continuation area */
+       int             iso_ce_len;     /* length of continuation area */
+       struct iso_mnt  *imp;           /* mount structure */
+       ino_t           *inump;         /* inode number pointer */
+       char            *outbuf;        /* name/symbolic link output area */
+       u_short         *outlen;        /* length of above */
+       u_short         maxlen;         /* maximum length of above */
+       int             cont;           /* continuation of above */
+} ISO_RRIP_ANALYZE;
+
+int isofs_rrip_analyze __P((struct iso_directory_record *isodir,
+                           struct iso_node *inop, struct iso_mnt *imp));
+int isofs_rrip_getname __P((struct iso_directory_record *isodir,
+                           char *outbuf, u_short *outlen,
+                           ino_t *inump, struct iso_mnt *imp));
+int isofs_rrip_getsymname __P((struct iso_directory_record *isodir,
+                              char *outbuf, u_short *outlen,
+                              struct iso_mnt *imp));
+int isofs_rrip_offset __P((struct iso_directory_record *isodir,
+                          struct iso_mnt *imp));