]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/vfs/vfs_xattr.c
xnu-2422.1.72.tar.gz
[apple/xnu.git] / bsd / vfs / vfs_xattr.c
index 30e62d8ce8c2a9f989d0a7f92a3cd92b1b82434a..dc2e09d325ac889328a4d8c1599434115f0ace1e 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2004-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2012 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
 #include <security/mac_framework.h>
 #endif
 
 #include <security/mac_framework.h>
 #endif
 
+#if !CONFIG_APPLEDOUBLE
+#define        PANIC_ON_NOAPPLEDOUBLE  1
+#endif
 
 #if NAMEDSTREAMS
 
 
 #if NAMEDSTREAMS
 
+static int shadow_sequence;
+
 /*
 /*
- * Cast to 'unsigned int' loses precision - hope that's OK...
+ * We use %p to prevent loss of precision for pointers on varying architectures.
  */
  */
+
+#define SHADOW_NAME_FMT                ".vfs_rsrc_stream_%p%08x%p"
+#define SHADOW_DIR_FMT         ".vfs_rsrc_streams_%p%x"
+#define SHADOW_DIR_CONTAINER "/var/run"
+
 #define MAKE_SHADOW_NAME(VP, NAME)  \
 #define MAKE_SHADOW_NAME(VP, NAME)  \
-       snprintf((NAME), sizeof((NAME)), ".vfs_rsrc_stream_%x%08x%x", (unsigned int)(VP), (VP)->v_id, (unsigned int)(VP)->v_data);
+       snprintf((NAME), sizeof((NAME)), (SHADOW_NAME_FMT), \
+                       ((void*)(VM_KERNEL_ADDRPERM(VP))), \
+                       (VP)->v_id, \
+                       ((void*)(VM_KERNEL_ADDRPERM((VP)->v_data))))
 
 
-static vnode_t shadow_dvp;  /* tmp directory to hold stream shadow files */
-static int shadow_vid;
-static int shadow_sequence;
+/* The full path to the shadow directory */
+#define MAKE_SHADOW_DIRNAME(VP, NAME)  \
+       snprintf((NAME), sizeof((NAME)), (SHADOW_DIR_CONTAINER "/" SHADOW_DIR_FMT), \
+                       ((void*)(VM_KERNEL_ADDRPERM(VP))), shadow_sequence)
 
 
+/* The shadow directory as a 'leaf' entry */
+#define MAKE_SHADOW_DIR_LEAF(VP, NAME) \
+       snprintf((NAME), sizeof((NAME)), (SHADOW_DIR_FMT), \
+                       ((void*)(VM_KERNEL_ADDRPERM(VP))), shadow_sequence)
 
 static int  default_getnamedstream(vnode_t vp, vnode_t *svpp, const char *name, enum nsoperation op, vfs_context_t context);
 
 
 static int  default_getnamedstream(vnode_t vp, vnode_t *svpp, const char *name, enum nsoperation op, vfs_context_t context);
 
@@ -78,19 +96,22 @@ static int  default_removenamedstream(vnode_t vp, const char *name, vfs_context_
 
 static int  getshadowfile(vnode_t vp, vnode_t *svpp, int makestream, size_t *rsrcsize, int *creator, vfs_context_t context);
 
 
 static int  getshadowfile(vnode_t vp, vnode_t *svpp, int makestream, size_t *rsrcsize, int *creator, vfs_context_t context);
 
-static int  get_shadow_dir(vnode_t *sdvpp, vfs_context_t context);
-
-#endif
+static int  get_shadow_dir(vnode_t *sdvpp);
 
 
+#endif /* NAMEDSTREAMS */
 
 /*
  * Default xattr support routines.
  */
 
 
 /*
  * Default xattr support routines.
  */
 
+static int default_getxattr(vnode_t vp, const char *name, uio_t uio, size_t *size, int options,
+    vfs_context_t context);
+static int default_setxattr(vnode_t vp, const char *name, uio_t uio, int options,
+    vfs_context_t context);
 static int default_listxattr(vnode_t vp, uio_t uio, size_t *size, int options,
 static int default_listxattr(vnode_t vp, uio_t uio, size_t *size, int options,
-                             vfs_context_t context);
-
-
+    vfs_context_t context);
+static int default_removexattr(vnode_t vp, const char *name, int options,
+    vfs_context_t context);
 
 /*
  *  Retrieve the data of an extended attribute.
 
 /*
  *  Retrieve the data of an extended attribute.
@@ -101,7 +122,7 @@ vn_getxattr(vnode_t vp, const char *name, uio_t uio, size_t *size,
 {
        int error;
 
 {
        int error;
 
-       if (!(vp->v_type == VREG || vp->v_type == VDIR || vp->v_type == VLNK)) {
+       if (!XATTR_VNODE_SUPPORTED(vp)) {
                return (EPERM);
        }
 #if NAMEDSTREAMS
                return (EPERM);
        }
 #if NAMEDSTREAMS
@@ -147,7 +168,6 @@ vn_getxattr(vnode_t vp, const char *name, uio_t uio, size_t *size,
        if (error == ENOTSUP && !(options & XATTR_NODEFAULT)) {
                /*
                 * A filesystem may keep some EAs natively and return ENOTSUP for others.
        if (error == ENOTSUP && !(options & XATTR_NODEFAULT)) {
                /*
                 * A filesystem may keep some EAs natively and return ENOTSUP for others.
-                * SMB returns ENOTSUP for finderinfo and resource forks.
                 */
                error = default_getxattr(vp, name, uio, size, options, context);
        }
                 */
                error = default_getxattr(vp, name, uio, size, options, context);
        }
@@ -163,7 +183,7 @@ vn_setxattr(vnode_t vp, const char *name, uio_t uio, int options, vfs_context_t
 {
        int error;
 
 {
        int error;
 
-       if (!(vp->v_type == VREG || vp->v_type == VDIR || vp->v_type == VLNK)) {
+       if (!XATTR_VNODE_SUPPORTED(vp)) {
                return (EPERM);
        }
 #if NAMEDSTREAMS
                return (EPERM);
        }
 #if NAMEDSTREAMS
@@ -233,7 +253,6 @@ vn_setxattr(vnode_t vp, const char *name, uio_t uio, int options, vfs_context_t
        if (error == ENOTSUP && !(options & XATTR_NODEFAULT)) {
                /*
                 * A filesystem may keep some EAs natively and return ENOTSUP for others.
        if (error == ENOTSUP && !(options & XATTR_NODEFAULT)) {
                /*
                 * A filesystem may keep some EAs natively and return ENOTSUP for others.
-                * SMB returns ENOTSUP for finderinfo and resource forks.
                 */
                error = default_setxattr(vp, name, uio, options, context);
        }
                 */
                error = default_setxattr(vp, name, uio, options, context);
        }
@@ -254,7 +273,7 @@ vn_removexattr(vnode_t vp, const char * name, int options, vfs_context_t context
 {
        int error;
 
 {
        int error;
 
-       if (!(vp->v_type == VREG || vp->v_type == VDIR || vp->v_type == VLNK)) {
+       if (!XATTR_VNODE_SUPPORTED(vp)) {
                return (EPERM);
        }
 #if NAMEDSTREAMS
                return (EPERM);
        }
 #if NAMEDSTREAMS
@@ -281,7 +300,6 @@ vn_removexattr(vnode_t vp, const char * name, int options, vfs_context_t context
        if (error == ENOTSUP && !(options & XATTR_NODEFAULT)) {
                /*
                 * A filesystem may keep some EAs natively and return ENOTSUP for others.
        if (error == ENOTSUP && !(options & XATTR_NODEFAULT)) {
                /*
                 * A filesystem may keep some EAs natively and return ENOTSUP for others.
-                * SMB returns ENOTSUP for finderinfo and resource forks.
                 */
                error = default_removexattr(vp, name, options, context);
 #ifdef DUAL_EAS
                 */
                error = default_removexattr(vp, name, options, context);
 #ifdef DUAL_EAS
@@ -314,7 +332,7 @@ vn_listxattr(vnode_t vp, uio_t uio, size_t *size, int options, vfs_context_t con
 {
        int error;
 
 {
        int error;
 
-       if (!(vp->v_type == VREG || vp->v_type == VDIR || vp->v_type == VLNK)) {
+       if (!XATTR_VNODE_SUPPORTED(vp)) {
                return (EPERM);
        }
 #if NAMEDSTREAMS
                return (EPERM);
        }
 #if NAMEDSTREAMS
@@ -341,8 +359,7 @@ vn_listxattr(vnode_t vp, uio_t uio, size_t *size, int options, vfs_context_t con
                /*
                 * A filesystem may keep some but not all EAs natively, in which case
                 * the native EA names will have been uiomove-d out (or *size updated)
                /*
                 * A filesystem may keep some but not all EAs natively, in which case
                 * the native EA names will have been uiomove-d out (or *size updated)
-                * and the default_listxattr here will finish the job.  Note SMB takes
-                * advantage of this for its finder-info and resource forks.
+                * and the default_listxattr here will finish the job.  
                 */
                error = default_listxattr(vp, uio, size, options, context);
        }
                 */
                error = default_listxattr(vp, uio, size, options, context);
        }
@@ -380,6 +397,7 @@ xattr_protected(const char *attrname)
 
 
 #if NAMEDSTREAMS
 
 
 #if NAMEDSTREAMS
+
 /*
  * Obtain a named stream from vnode vp.
  */
 /*
  * Obtain a named stream from vnode vp.
  */
@@ -394,13 +412,31 @@ vnode_getnamedstream(vnode_t vp, vnode_t *svpp, const char *name, enum nsoperati
                error = default_getnamedstream(vp, svpp, name, op, context);
 
        if (error == 0) {
                error = default_getnamedstream(vp, svpp, name, op, context);
 
        if (error == 0) {
+               uint32_t streamflags = VISNAMEDSTREAM;
                vnode_t svp = *svpp;
                vnode_t svp = *svpp;
+
+               if ((vp->v_mount->mnt_kern_flag & MNTK_NAMED_STREAMS) == 0) {
+                       streamflags |= VISSHADOW;
+               }
                
                /* Tag the vnode. */
                
                /* Tag the vnode. */
-               vnode_lock(svp);
-               svp->v_flag |= VISNAMEDSTREAM;
+               vnode_lock_spin(svp);
+               svp->v_flag |= streamflags;
                vnode_unlock(svp);
                vnode_unlock(svp);
-               /* Make the file it's parent. */
+
+               /* Tag the parent so we know to flush credentials for streams on setattr */
+               vnode_lock_spin(vp);
+               vp->v_lflag |= VL_HASSTREAMS;
+               vnode_unlock(vp);
+
+               /* Make the file it's parent.  
+                * Note:  This parent link helps us distinguish vnodes for 
+                * shadow stream files from vnodes for resource fork on file 
+                * systems that support namedstream natively (both have 
+                * VISNAMEDSTREAM set) by allowing access to mount structure 
+                * for checking MNTK_NAMED_STREAMS bit at many places in the 
+                * code.
+                */
                vnode_update_identity(svp, vp, NULL, 0, 0, VNODE_UPDATE_PARENT);
        }               
 
                vnode_update_identity(svp, vp, NULL, 0, 0, VNODE_UPDATE_PARENT);
        }               
 
@@ -421,13 +457,32 @@ vnode_makenamedstream(vnode_t vp, vnode_t *svpp, const char *name, int flags, vf
                error = default_makenamedstream(vp, svpp, name, context);
 
        if (error == 0) {
                error = default_makenamedstream(vp, svpp, name, context);
 
        if (error == 0) {
+               uint32_t streamflags = VISNAMEDSTREAM;
                vnode_t svp = *svpp;
 
                /* Tag the vnode. */
                vnode_t svp = *svpp;
 
                /* Tag the vnode. */
-               vnode_lock(svp);
-               svp->v_flag |= VISNAMEDSTREAM;
+               if ((vp->v_mount->mnt_kern_flag & MNTK_NAMED_STREAMS) == 0) {
+                       streamflags |= VISSHADOW;
+               }
+               
+               /* Tag the vnode. */
+               vnode_lock_spin(svp);
+               svp->v_flag |= streamflags;
                vnode_unlock(svp);
                vnode_unlock(svp);
-               /* Make the file it's parent. */
+
+               /* Tag the parent so we know to flush credentials for streams on setattr */
+               vnode_lock_spin(vp);
+               vp->v_lflag |= VL_HASSTREAMS;
+               vnode_unlock(vp);
+
+               /* Make the file it's parent.
+                * Note:  This parent link helps us distinguish vnodes for 
+                * shadow stream files from vnodes for resource fork on file 
+                * systems that support namedstream natively (both have 
+                * VISNAMEDSTREAM set) by allowing access to mount structure 
+                * for checking MNTK_NAMED_STREAMS bit at many places in the 
+                * code.
+                */
                vnode_update_identity(svp, vp, NULL, 0, 0, VNODE_UPDATE_PARENT);
        }
        return (error);
                vnode_update_identity(svp, vp, NULL, 0, 0, VNODE_UPDATE_PARENT);
        }
        return (error);
@@ -453,18 +508,32 @@ vnode_removenamedstream(vnode_t vp, vnode_t svp, const char *name, int flags, vf
 
 /*
  * Release a named stream shadow file.
 
 /*
  * Release a named stream shadow file.
+ *
+ * Note: This function is called from two places where we do not need 
+ * to check if the vnode has any references held before deleting the 
+ * shadow file.  Once from vclean() when the vnode is being reclaimed 
+ * and we do not hold any references on the vnode.  Second time from 
+ * default_getnamedstream() when we get an error during shadow stream 
+ * file initialization so that other processes who are waiting for the 
+ * shadow stream file initialization by the creator will get opportunity 
+ * to create and initialize the file again.
  */
 errno_t
  */
 errno_t
-vnode_relenamedstream(vnode_t vp, vnode_t svp, vfs_context_t context)
-{
+vnode_relenamedstream(vnode_t vp, vnode_t svp) {
        vnode_t dvp;
        struct componentname cn;
        vnode_t dvp;
        struct componentname cn;
-       char tmpname[48];
+       char tmpname[80];
        errno_t err;
        errno_t err;
+       
+       /* 
+        * We need to use the kernel context here.  If we used the supplied
+        * VFS context we have no clue whether or not it originated from userland
+        * where it could be subject to a chroot jail.  We need to ensure that all
+        * filesystem access to shadow files is done on the same FS regardless of
+        * userland process restrictions.
+        */
+       vfs_context_t kernelctx = vfs_context_kernel();
 
 
-       if (vnode_isinuse(svp, 1)) {
-               return (EBUSY);
-       }
        cache_purge(svp);
 
        vnode_lock(svp);
        cache_purge(svp);
 
        vnode_lock(svp);
@@ -473,22 +542,22 @@ vnode_relenamedstream(vnode_t vp, vnode_t svp, vfs_context_t context)
 
        cn.cn_nameiop = DELETE;
        cn.cn_flags = ISLASTCN;
 
        cn.cn_nameiop = DELETE;
        cn.cn_flags = ISLASTCN;
-       cn.cn_context = context;
+       cn.cn_context = kernelctx;
        cn.cn_pnbuf = tmpname;
        cn.cn_pnlen = sizeof(tmpname);
        cn.cn_nameptr = cn.cn_pnbuf;
        cn.cn_namelen = strlen(tmpname);
 
        cn.cn_pnbuf = tmpname;
        cn.cn_pnlen = sizeof(tmpname);
        cn.cn_nameptr = cn.cn_pnbuf;
        cn.cn_namelen = strlen(tmpname);
 
-       /* Obtain the vnode for the shadow files directory. */
-       err = get_shadow_dir(&dvp, context);
+       /* 
+        * Obtain the vnode for the shadow files directory.  Make sure to 
+        * use the kernel ctx as described above.
+        */
+       err = get_shadow_dir(&dvp);
        if (err != 0) {
                return err;
        }
        if (err != 0) {
                return err;
        }
-       /* Check for busy svp one last time. */
-       if (vnode_isinuse(svp, 1) == 0) {
-               (void) VNOP_REMOVE(dvp, svp, &cn, 0, context);
-               (void) vnode_recycle(svp);
-       }
+
+       (void) VNOP_REMOVE(dvp, svp, &cn, 0, kernelctx);
        vnode_put(dvp);
 
        return (0);
        vnode_put(dvp);
 
        return (0);
@@ -496,6 +565,9 @@ vnode_relenamedstream(vnode_t vp, vnode_t svp, vfs_context_t context)
 
 /*
  * Flush a named stream shadow file.
 
 /*
  * Flush a named stream shadow file.
+ * 
+ * 'vp' represents the AppleDouble file.
+ * 'svp' represents the shadow file.
  */
 errno_t 
 vnode_flushnamedstream(vnode_t vp, vnode_t svp, vfs_context_t context)
  */
 errno_t 
 vnode_flushnamedstream(vnode_t vp, vnode_t svp, vfs_context_t context)
@@ -508,6 +580,13 @@ vnode_flushnamedstream(vnode_t vp, vnode_t svp, vfs_context_t context)
        size_t  iosize;
        size_t datasize;
        int error;
        size_t  iosize;
        size_t datasize;
        int error;
+       /* 
+        * The kernel context must be used for all I/O to the shadow file 
+        * and its namespace operations
+        */
+       vfs_context_t kernelctx = vfs_context_kernel();
+
+       /* The supplied context is used for access to the AD file itself */
 
        VATTR_INIT(&va);
        VATTR_WANTED(&va, va_data_size);
 
        VATTR_INIT(&va);
        VATTR_WANTED(&va, va_data_size);
@@ -516,7 +595,7 @@ vnode_flushnamedstream(vnode_t vp, vnode_t svp, vfs_context_t context)
                return (0);
        }
        datasize = va.va_data_size;
                return (0);
        }
        datasize = va.va_data_size;
-       if ((datasize == 0)) {
+       if (datasize == 0) {
                (void) default_removexattr(vp, XATTR_RESOURCEFORK_NAME, 0, context);
                return (0);
        }
                (void) default_removexattr(vp, XATTR_RESOURCEFORK_NAME, 0, context);
                return (0);
        }
@@ -525,13 +604,13 @@ vnode_flushnamedstream(vnode_t vp, vnode_t svp, vfs_context_t context)
        if (kmem_alloc(kernel_map, (vm_offset_t *)&bufptr, bufsize)) {
                return (ENOMEM);
        }
        if (kmem_alloc(kernel_map, (vm_offset_t *)&bufptr, bufsize)) {
                return (ENOMEM);
        }
-       auio = uio_create(1, 0, UIO_SYSSPACE32, UIO_READ);
+       auio = uio_create(1, 0, UIO_SYSSPACE, UIO_READ);
        offset = 0;
 
        /*
         * Copy the shadow stream file data into the resource fork.
         */
        offset = 0;
 
        /*
         * Copy the shadow stream file data into the resource fork.
         */
-       error = VNOP_OPEN(svp, 0, context);
+       error = VNOP_OPEN(svp, 0, kernelctx);
        if (error) {
                printf("vnode_flushnamedstream: err %d opening file\n", error);
                goto out;
        if (error) {
                printf("vnode_flushnamedstream: err %d opening file\n", error);
                goto out;
@@ -539,9 +618,9 @@ vnode_flushnamedstream(vnode_t vp, vnode_t svp, vfs_context_t context)
        while (offset < datasize) {
                iosize = MIN(datasize - offset, iosize);
 
        while (offset < datasize) {
                iosize = MIN(datasize - offset, iosize);
 
-               uio_reset(auio, offset, UIO_SYSSPACE32, UIO_READ);
+               uio_reset(auio, offset, UIO_SYSSPACE, UIO_READ);
                uio_addiov(auio, (uintptr_t)bufptr, iosize);
                uio_addiov(auio, (uintptr_t)bufptr, iosize);
-               error = VNOP_READ(svp, auio, 0, context);
+               error = VNOP_READ(svp, auio, 0, kernelctx);
                if (error) {
                        break;
                }
                if (error) {
                        break;
                }
@@ -552,7 +631,7 @@ vnode_flushnamedstream(vnode_t vp, vnode_t svp, vfs_context_t context)
                                break;
                        }
                }
                                break;
                        }
                }
-               uio_reset(auio, offset, UIO_SYSSPACE32, UIO_WRITE);
+               uio_reset(auio, offset, UIO_SYSSPACE, UIO_WRITE);
                uio_addiov(auio, (uintptr_t)bufptr, iosize);
                error = vn_setxattr(vp, XATTR_RESOURCEFORK_NAME, auio, XATTR_NOSECURITY, context);
                if (error) {
                uio_addiov(auio, (uintptr_t)bufptr, iosize);
                error = vn_setxattr(vp, XATTR_RESOURCEFORK_NAME, auio, XATTR_NOSECURITY, context);
                if (error) {
@@ -560,7 +639,9 @@ vnode_flushnamedstream(vnode_t vp, vnode_t svp, vfs_context_t context)
                }
                offset += iosize;
        }
                }
                offset += iosize;
        }
-       (void) VNOP_CLOSE(svp, 0, context);
+
+       /* close shadowfile */
+       (void) VNOP_CLOSE(svp, 0, kernelctx);
 out:
        if (bufptr) {
                kmem_free(kernel_map, (vm_offset_t)bufptr, bufsize);
 out:
        if (bufptr) {
                kmem_free(kernel_map, (vm_offset_t)bufptr, bufsize);
@@ -572,6 +653,75 @@ out:
 }
 
 
 }
 
 
+/* 
+ * Verify that the vnode 'vp' is a vnode that lives in the shadow
+ * directory.  We can't just query the parent pointer directly since
+ * the shadowfile is hooked up to the actual file it's a stream for.
+ */
+errno_t vnode_verifynamedstream(vnode_t vp) {
+       int error;
+       struct vnode *shadow_dvp = NULL;
+       struct vnode *shadowfile = NULL;
+       struct componentname cn;
+       
+       /* 
+        * We need to use the kernel context here.  If we used the supplied
+        * VFS context we have no clue whether or not it originated from userland
+        * where it could be subject to a chroot jail.  We need to ensure that all
+        * filesystem access to shadow files is done on the same FS regardless of
+        * userland process restrictions.
+        */
+       vfs_context_t kernelctx = vfs_context_kernel();
+       char tmpname[80];
+       
+
+       /* Get the shadow directory vnode */
+       error = get_shadow_dir(&shadow_dvp);
+       if (error) {
+               return error;
+       }
+
+       /* Re-generate the shadow name in the buffer */
+       MAKE_SHADOW_NAME (vp, tmpname);
+
+       /* Look up item in shadow dir */
+       bzero(&cn, sizeof(cn));
+       cn.cn_nameiop = LOOKUP;
+       cn.cn_flags = ISLASTCN | CN_ALLOWRSRCFORK;
+       cn.cn_context = kernelctx;
+       cn.cn_pnbuf = tmpname;
+       cn.cn_pnlen = sizeof(tmpname);
+       cn.cn_nameptr = cn.cn_pnbuf;
+       cn.cn_namelen = strlen(tmpname);
+
+       if (VNOP_LOOKUP (shadow_dvp, &shadowfile, &cn, kernelctx) == 0) {
+               /* is the pointer the same? */
+               if (shadowfile == vp) {
+                       error = 0;      
+               }
+               else {
+                       error = EPERM;
+               }
+               /* drop the iocount acquired */
+               vnode_put (shadowfile);
+       }       
+
+       /* Drop iocount on shadow dir */
+       vnode_put (shadow_dvp);
+       return error;
+}      
+
+/* 
+ * Access or create the shadow file as needed. 
+ * 
+ * 'makestream' with non-zero value means that we need to guarantee we were the
+ * creator of the shadow file.
+ *
+ * 'context' is the user supplied context for the original VFS operation that
+ * caused us to need a shadow file.
+ *
+ * int pointed to by 'creator' is nonzero if we created the shadowfile.
+ */
 static int
 getshadowfile(vnode_t vp, vnode_t *svpp, int makestream, size_t *rsrcsize,
               int *creator, vfs_context_t context)
 static int
 getshadowfile(vnode_t vp, vnode_t *svpp, int makestream, size_t *rsrcsize,
               int *creator, vfs_context_t context)
@@ -580,12 +730,14 @@ getshadowfile(vnode_t vp, vnode_t *svpp, int makestream, size_t *rsrcsize,
        vnode_t  svp = NULLVP;
        struct componentname cn;
        struct vnode_attr va;
        vnode_t  svp = NULLVP;
        struct componentname cn;
        struct vnode_attr va;
-       char tmpname[48];
+       char tmpname[80];
        size_t datasize = 0;
        int  error = 0;
        size_t datasize = 0;
        int  error = 0;
+       int retries = 0;
+       vfs_context_t kernelctx = vfs_context_kernel();
 
 
+retry_create:
        *creator = 0;
        *creator = 0;
-
        /* Establish a unique file name. */
        MAKE_SHADOW_NAME(vp, tmpname);
        bzero(&cn, sizeof(cn));
        /* Establish a unique file name. */
        MAKE_SHADOW_NAME(vp, tmpname);
        bzero(&cn, sizeof(cn));
@@ -618,13 +770,13 @@ getshadowfile(vnode_t vp, vnode_t *svpp, int makestream, size_t *rsrcsize,
        VATTR_SET(&va, va_flags, UF_HIDDEN);
 
        /* Obtain the vnode for the shadow files directory. */
        VATTR_SET(&va, va_flags, UF_HIDDEN);
 
        /* Obtain the vnode for the shadow files directory. */
-       if (get_shadow_dir(&dvp, context) != 0) {
+       if (get_shadow_dir(&dvp) != 0) {
                error = ENOTDIR;
                goto out;
        }
        if (!makestream) {
                /* See if someone else already has it open. */
                error = ENOTDIR;
                goto out;
        }
        if (!makestream) {
                /* See if someone else already has it open. */
-               if (VNOP_LOOKUP(dvp, &svp, &cn, context) == 0) {
+               if (VNOP_LOOKUP(dvp, &svp, &cn, kernelctx) == 0) {
                        /* Double check existence by asking for size. */
                        VATTR_INIT(&va);
                        VATTR_WANTED(&va, va_data_size);
                        /* Double check existence by asking for size. */
                        VATTR_INIT(&va);
                        VATTR_WANTED(&va, va_data_size);
@@ -634,7 +786,10 @@ getshadowfile(vnode_t vp, vnode_t *svpp, int makestream, size_t *rsrcsize,
                        }
                }
                
                        }
                }
                
-               /* Otherwise make sure the resource fork data exists. */
+               /* 
+                * Otherwise make sure the resource fork data exists. 
+                * Use the supplied context for accessing the AD file.
+                */
                error = vn_getxattr(vp, XATTR_RESOURCEFORK_NAME, NULL, &datasize,
                                    XATTR_NOSECURITY, context);
                /*
                error = vn_getxattr(vp, XATTR_RESOURCEFORK_NAME, NULL, &datasize,
                                    XATTR_NOSECURITY, context);
                /*
@@ -661,12 +816,36 @@ getshadowfile(vnode_t vp, vnode_t *svpp, int makestream, size_t *rsrcsize,
                }
        }
        /* Create the shadow stream file. */
                }
        }
        /* Create the shadow stream file. */
-       error = VNOP_CREATE(dvp, &svp, &cn, &va, context);
+       error = VNOP_CREATE(dvp, &svp, &cn, &va, kernelctx);
        if (error == 0) {
        if (error == 0) {
+               vnode_recycle(svp);
                *creator = 1;
                *creator = 1;
-       } else if ((error == EEXIST) && !makestream) {
-               error = VNOP_LOOKUP(dvp, &svp, &cn, context);
+       } 
+       else if ((error == EEXIST) && !makestream) {
+               error = VNOP_LOOKUP(dvp, &svp, &cn, kernelctx);
+       }
+       else if ((error == ENOENT) && !makestream) {
+               /*
+                * We could have raced with a rmdir on the shadow directory
+                * post-lookup.  Retry from the beginning, 1x only, to
+                * try and see if we need to re-create the shadow directory     
+                * in get_shadow_dir.
+                */
+               if (retries == 0) {
+                       retries++;
+                       if (dvp) {
+                               vnode_put (dvp);
+                               dvp = NULLVP;
+                       }
+                       if (svp) {
+                               vnode_put (svp);
+                               svp = NULLVP;
+                       }
+                       goto retry_create;
+               }
+               /* Otherwise, just error out normally below */
        }
        }
+       
 out:
        if (dvp) {
                vnode_put(dvp);
 out:
        if (dvp) {
                vnode_put(dvp);
@@ -697,6 +876,9 @@ default_getnamedstream(vnode_t vp, vnode_t *svpp, const char *name, enum nsopera
        int  creator;
        int  error;
 
        int  creator;
        int  error;
 
+       /* need the kernel context for accessing the shadowfile */
+       vfs_context_t kernelctx = vfs_context_kernel();
+
        /*
         * Only the "com.apple.ResourceFork" stream is supported here.
         */
        /*
         * Only the "com.apple.ResourceFork" stream is supported here.
         */
@@ -707,6 +889,9 @@ default_getnamedstream(vnode_t vp, vnode_t *svpp, const char *name, enum nsopera
 retry:
        /*
         * Obtain a shadow file for the resource fork I/O.
 retry:
        /*
         * Obtain a shadow file for the resource fork I/O.
+        * 
+        * Need to pass along the supplied context so that getshadowfile
+        * can access the AD file as needed, using it.
         */
        error = getshadowfile(vp, &svp, 0, &datasize, &creator, context);
        if (error) {
         */
        error = getshadowfile(vp, &svp, 0, &datasize, &creator, context);
        if (error) {
@@ -716,7 +901,14 @@ retry:
 
        /*
         * The creator of the shadow file provides its file data,
 
        /*
         * The creator of the shadow file provides its file data,
-        * all other threads should wait until its ready.
+        * all other threads should wait until its ready.  In order to 
+        * prevent a deadlock during error codepaths, we need to check if the
+        * vnode is being created, or if it has failed out. Regardless of success or 
+        * failure, we set the VISSHADOW bit on the vnode, so we check that
+        * if the vnode's flags don't have VISNAMEDSTREAM set.  If it doesn't,
+        * then we can infer the creator isn't done yet.  If it's there, but
+        * VISNAMEDSTREAM is not set, then we can infer it errored out and we should
+        * try again.
         */
        if (!creator) {
                vnode_lock(svp);
         */
        if (!creator) {
                vnode_lock(svp);
@@ -725,9 +917,19 @@ retry:
                        vnode_unlock(svp);
                        goto out;
                } else {
                        vnode_unlock(svp);
                        goto out;
                } else {
-                       /* its not ready, wait for it (sleep using v_parent as channel) */
-                       msleep((caddr_t)&svp->v_parent, &svp->v_lock, PINOD | PDROP,
-                               "getnamedstream", NULL);
+                       /* It's not ready, wait for it (sleep using v_parent as channel) */
+                       if ((svp->v_flag & VISSHADOW)) {
+                               /* 
+                                * No VISNAMEDSTREAM, but we did see VISSHADOW, indicating that the other
+                                * thread is done with this vnode. Just unlock the vnode and try again
+                                */
+                               vnode_unlock(svp);
+                       }       
+                       else {
+                               /* Otherwise, sleep if the shadow file is not created yet */
+                               msleep((caddr_t)&svp->v_parent, &svp->v_lock, PINOD | PDROP,
+                                               "getnamedstream", NULL);
+                       }
                        vnode_put(svp);
                        svp = NULLVP;
                        goto retry;
                        vnode_put(svp);
                        svp = NULLVP;
                        goto retry;
@@ -747,10 +949,11 @@ retry:
                        goto out;
                }
 
                        goto out;
                }
 
-               auio = uio_create(1, 0, UIO_SYSSPACE32, UIO_READ);
+               auio = uio_create(1, 0, UIO_SYSSPACE, UIO_READ);
                offset = 0;
 
                offset = 0;
 
-               error = VNOP_OPEN(svp, 0, context);
+               /* open the shadow file */
+               error = VNOP_OPEN(svp, 0, kernelctx);
                if (error) {
                        goto out;
                }
                if (error) {
                        goto out;
                }
@@ -759,37 +962,50 @@ retry:
 
                        iosize = MIN(datasize - offset, iosize);
 
 
                        iosize = MIN(datasize - offset, iosize);
 
-                       uio_reset(auio, offset, UIO_SYSSPACE32, UIO_READ);
+                       uio_reset(auio, offset, UIO_SYSSPACE, UIO_READ);
                        uio_addiov(auio, (uintptr_t)bufptr, iosize);
                        uio_addiov(auio, (uintptr_t)bufptr, iosize);
+                       /* use supplied ctx for AD file */
                        error = vn_getxattr(vp, XATTR_RESOURCEFORK_NAME, auio, &tmpsize,
                                            XATTR_NOSECURITY, context);
                        if (error) {
                                break;
                        }
                
                        error = vn_getxattr(vp, XATTR_RESOURCEFORK_NAME, auio, &tmpsize,
                                            XATTR_NOSECURITY, context);
                        if (error) {
                                break;
                        }
                
-                       uio_reset(auio, offset, UIO_SYSSPACE32, UIO_WRITE);
+                       uio_reset(auio, offset, UIO_SYSSPACE, UIO_WRITE);
                        uio_addiov(auio, (uintptr_t)bufptr, iosize);
                        uio_addiov(auio, (uintptr_t)bufptr, iosize);
-                       error = VNOP_WRITE(svp, auio, 0, context);
+                       /* kernel context for writing shadowfile */
+                       error = VNOP_WRITE(svp, auio, 0, kernelctx);
                        if (error) {
                                break;
                        }
                        offset += iosize;
                }
                        if (error) {
                                break;
                        }
                        offset += iosize;
                }
-               (void) VNOP_CLOSE(svp, 0, context);
+
+               /* close shadow file */
+               (void) VNOP_CLOSE(svp, 0, kernelctx);
        }
 out:
        /* Wake up anyone waiting for svp file content */
        if (creator) {
                if (error == 0) {
                        vnode_lock(svp);
        }
 out:
        /* Wake up anyone waiting for svp file content */
        if (creator) {
                if (error == 0) {
                        vnode_lock(svp);
-                       svp->v_flag |= VISNAMEDSTREAM;
+                       /* VISSHADOW would be set later on anyway, so we set it now */
+                       svp->v_flag |= (VISNAMEDSTREAM | VISSHADOW);
                        wakeup((caddr_t)&svp->v_parent);
                        vnode_unlock(svp);
                } else {
                        wakeup((caddr_t)&svp->v_parent);
                        vnode_unlock(svp);
                } else {
-                       /* On post create errors, get rid of shadow file. */
-                       (void)vnode_relenamedstream(vp, svp, context);
-
+                       /* On post create errors, get rid of the shadow file.  This 
+                        * way if there is another process waiting for initialization 
+                        * of the shadowfile by the current process will wake up and 
+                        * retry by creating and initializing the shadow file again.
+                        * Also add the VISSHADOW bit here to indicate we're done operating
+                        * on this vnode.
+                        */
+                       (void)vnode_relenamedstream(vp, svp);
+                       vnode_lock (svp);
+                       svp->v_flag |= VISSHADOW;
                        wakeup((caddr_t)&svp->v_parent);
                        wakeup((caddr_t)&svp->v_parent);
+                       vnode_unlock(svp);
                }
        }
 
                }
        }
 
@@ -823,6 +1039,8 @@ default_makenamedstream(vnode_t vp, vnode_t *svpp, const char *name, vfs_context
                *svpp = NULLVP;
                return (ENOATTR);
        }
                *svpp = NULLVP;
                return (ENOATTR);
        }
+
+       /* Supply the context to getshadowfile so it can manipulate the AD file */
        error = getshadowfile(vp, svpp, 1, NULL, &creator, context);
 
        /*
        error = getshadowfile(vp, svpp, 1, NULL, &creator, context);
 
        /*
@@ -832,11 +1050,14 @@ default_makenamedstream(vnode_t vp, vnode_t *svpp, const char *name, vfs_context
                vnode_t svp = *svpp;
 
                vnode_lock(svp);
                vnode_t svp = *svpp;
 
                vnode_lock(svp);
-               svp->v_flag |= VISNAMEDSTREAM;
+               /* If we're the creator, mark it as a named stream */
+               svp->v_flag |= (VISNAMEDSTREAM | VISSHADOW);
                /* Wakeup any waiters on the v_parent channel */
                wakeup((caddr_t)&svp->v_parent);
                vnode_unlock(svp);
                /* Wakeup any waiters on the v_parent channel */
                wakeup((caddr_t)&svp->v_parent);
                vnode_unlock(svp);
+
        }
        }
+
        return (error);
 }
 
        return (error);
 }
 
@@ -856,39 +1077,60 @@ default_removenamedstream(vnode_t vp, const char *name, vfs_context_t context)
 }
 
 static int
 }
 
 static int
-get_shadow_dir(vnode_t *sdvpp, vfs_context_t context)
-{
+get_shadow_dir(vnode_t *sdvpp) {
        vnode_t  dvp = NULLVP;
        vnode_t  sdvp = NULLVP;
        struct componentname  cn;
        struct vnode_attr  va;
        vnode_t  dvp = NULLVP;
        vnode_t  sdvp = NULLVP;
        struct componentname  cn;
        struct vnode_attr  va;
-       char tmpname[48];
+       char tmpname[80];
        uint32_t  tmp_fsid;
        int  error;
        uint32_t  tmp_fsid;
        int  error;
-
-       /* Check if we've already created it. */
-       if (shadow_dvp != NULLVP) {
-               if ((error = vnode_getwithvid(shadow_dvp, shadow_vid))) {
-                       shadow_dvp = NULLVP;
-               } else {
-                       *sdvpp = shadow_dvp;
-                       return (0);
-               }
+       vfs_context_t kernelctx = vfs_context_kernel();
+
+       bzero(tmpname, sizeof(tmpname));
+       MAKE_SHADOW_DIRNAME(rootvnode, tmpname);
+       /* 
+        * Look up the shadow directory to ensure that it still exists. 
+        * By looking it up, we get an iocounted dvp to use, and avoid some coherency issues
+        * in caching it when multiple threads may be trying to manipulate the pointers.
+        * 
+        * Make sure to use the kernel context.  We want a singular view of
+        * the shadow dir regardless of chrooted processes.
+        */
+       error = vnode_lookup(tmpname, 0, &sdvp, kernelctx);
+       if (error == 0) {
+               /*
+                * If we get here, then we have successfully looked up the shadow dir, 
+                * and it has an iocount from the lookup. Return the vp in the output argument.
+                */
+               *sdvpp = sdvp;
+               return (0);
        }
        }
+       /* In the failure case, no iocount is acquired */
+       sdvp = NULLVP;
+       bzero (tmpname, sizeof(tmpname));
 
 
-       /* Obtain the vnode for "/tmp" directory. */
-       if (vnode_lookup("/tmp", 0, &dvp, context) != 0) {
+       /* 
+        * Obtain the vnode for "/var/run" directory using the kernel
+        * context.
+        *
+        * This is defined in the SHADOW_DIR_CONTAINER macro
+        */
+       if (vnode_lookup(SHADOW_DIR_CONTAINER, 0, &dvp, kernelctx) != 0) {
                error = ENOTSUP;
                goto out;
        }
 
                error = ENOTSUP;
                goto out;
        }
 
-       /* Create the shadow stream directory. */
-       snprintf(tmpname, sizeof(tmpname), ".vfs_rsrc_streams_%x%x",
-                (unsigned int)rootvnode, shadow_sequence);
+       /* 
+        * Create the shadow stream directory.
+        * 'dvp' below suggests the parent directory so 
+        * we only need to provide the leaf entry name
+        */
+       MAKE_SHADOW_DIR_LEAF(rootvnode, tmpname);
        bzero(&cn, sizeof(cn));
        cn.cn_nameiop = LOOKUP;
        cn.cn_flags = ISLASTCN;
        bzero(&cn, sizeof(cn));
        cn.cn_nameiop = LOOKUP;
        cn.cn_flags = ISLASTCN;
-       cn.cn_context = context;
+       cn.cn_context = kernelctx;
        cn.cn_pnbuf = tmpname;
        cn.cn_pnlen = sizeof(tmpname);
        cn.cn_nameptr = cn.cn_pnbuf;
        cn.cn_pnbuf = tmpname;
        cn.cn_pnlen = sizeof(tmpname);
        cn.cn_nameptr = cn.cn_pnbuf;
@@ -905,30 +1147,23 @@ get_shadow_dir(vnode_t *sdvpp, vfs_context_t context)
        VATTR_SET(&va, va_flags, UF_HIDDEN);
        va.va_vaflags = VA_EXCLUSIVE;
 
        VATTR_SET(&va, va_flags, UF_HIDDEN);
        va.va_vaflags = VA_EXCLUSIVE;
 
-       error = VNOP_MKDIR(dvp, &sdvp, &cn, &va, context);
+       error = VNOP_MKDIR(dvp, &sdvp, &cn, &va, kernelctx);
        
        /*
         * There can be only one winner for an exclusive create.
         */
        
        /*
         * There can be only one winner for an exclusive create.
         */
-       if (error == 0) {
-               /* Take a long term ref to keep this dir around. */
-               error = vnode_ref(sdvp);
-               if (error == 0) {
-                       shadow_dvp = sdvp;
-                       shadow_vid = sdvp->v_id;
-               }
-       } else if (error == EEXIST) {
+       if (error == EEXIST) {
                /* loser has to look up directory */
                /* loser has to look up directory */
-               error = VNOP_LOOKUP(dvp, &sdvp, &cn, context);
+               error = VNOP_LOOKUP(dvp, &sdvp, &cn, kernelctx);
                if (error == 0) {
                        /* Make sure its in fact a directory */
                        if (sdvp->v_type != VDIR) {
                                goto baddir;
                        }
                if (error == 0) {
                        /* Make sure its in fact a directory */
                        if (sdvp->v_type != VDIR) {
                                goto baddir;
                        }
-                       /* Obtain the fsid for /tmp directory */
+                       /* Obtain the fsid for /var/run directory */
                        VATTR_INIT(&va);
                        VATTR_WANTED(&va, va_fsid);
                        VATTR_INIT(&va);
                        VATTR_WANTED(&va, va_fsid);
-                       if (VNOP_GETATTR(dvp, &va, context) != 0  ||
+                       if (VNOP_GETATTR(dvp, &va, kernelctx) != 0  ||
                            !VATTR_IS_SUPPORTED(&va, va_fsid)) {
                                goto baddir;
                        }
                            !VATTR_IS_SUPPORTED(&va, va_fsid)) {
                                goto baddir;
                        }
@@ -945,7 +1180,7 @@ get_shadow_dir(vnode_t *sdvpp, vfs_context_t context)
                        va.va_dirlinkcount = 1;
                        va.va_acl = (kauth_acl_t) KAUTH_FILESEC_NONE;
 
                        va.va_dirlinkcount = 1;
                        va.va_acl = (kauth_acl_t) KAUTH_FILESEC_NONE;
 
-                       if (VNOP_GETATTR(sdvp, &va, context) != 0  ||
+                       if (VNOP_GETATTR(sdvp, &va, kernelctx) != 0  ||
                            !VATTR_IS_SUPPORTED(&va, va_uid)  ||
                            !VATTR_IS_SUPPORTED(&va, va_gid)  ||
                            !VATTR_IS_SUPPORTED(&va, va_mode)  ||
                            !VATTR_IS_SUPPORTED(&va, va_uid)  ||
                            !VATTR_IS_SUPPORTED(&va, va_gid)  ||
                            !VATTR_IS_SUPPORTED(&va, va_mode)  ||
@@ -956,7 +1191,7 @@ get_shadow_dir(vnode_t *sdvpp, vfs_context_t context)
                         * Make sure its what we want: 
                         *      - owned by root
                         *      - not writable by anyone
                         * Make sure its what we want: 
                         *      - owned by root
                         *      - not writable by anyone
-                        *      - on same file system as /tmp
+                        *      - on same file system as /var/run
                         *      - not a hard-linked directory
                         *      - no ACLs (they might grant write access)
                         */
                         *      - not a hard-linked directory
                         *      - no ACLs (they might grant write access)
                         */
@@ -989,10 +1224,10 @@ baddir:
        error = ENOTDIR;
        goto out;
 }
        error = ENOTDIR;
        goto out;
 }
-#endif
-
+#endif /* NAMEDSTREAMS */
 
 
 
 
+#if CONFIG_APPLEDOUBLE
 /*
  * Default Implementation (Non-native EA) 
  */
 /*
  * Default Implementation (Non-native EA) 
  */
@@ -1086,7 +1321,7 @@ baddir:
 #define ATTR_BUF_SIZE      4096        /* default size of the attr file and how much we'll grow by */
 
 /* Implementation Limits */
 #define ATTR_BUF_SIZE      4096        /* default size of the attr file and how much we'll grow by */
 
 /* Implementation Limits */
-#define ATTR_MAX_SIZE      (128*1024)  /* 128K maximum attribute data size */
+#define ATTR_MAX_SIZE      AD_XATTR_MAXSIZE
 #define ATTR_MAX_HDR_SIZE  65536
 /*
  * Note: ATTR_MAX_HDR_SIZE is the largest attribute header
 #define ATTR_MAX_HDR_SIZE  65536
 /*
  * Note: ATTR_MAX_HDR_SIZE is the largest attribute header
@@ -1106,15 +1341,13 @@ baddir:
  */
 
 
  */
 
 
-#pragma options align=mac68k
-
 #define FINDERINFOSIZE 32
 
 typedef struct apple_double_entry {
        u_int32_t   type;     /* entry type: see list, 0 invalid */ 
        u_int32_t   offset;   /* entry data offset from the beginning of the file. */
        u_int32_t   length;   /* entry data length in bytes. */
 #define FINDERINFOSIZE 32
 
 typedef struct apple_double_entry {
        u_int32_t   type;     /* entry type: see list, 0 invalid */ 
        u_int32_t   offset;   /* entry data offset from the beginning of the file. */
        u_int32_t   length;   /* entry data length in bytes. */
-} apple_double_entry_t;
+} __attribute__((aligned(2), packed)) apple_double_entry_t;
 
 
 typedef struct apple_double_header {
 
 
 typedef struct apple_double_header {
@@ -1125,7 +1358,7 @@ typedef struct apple_double_header {
        apple_double_entry_t   entries[2];  /* 'finfo' & 'rsrc' always exist */
        u_int8_t    finfo[FINDERINFOSIZE];  /* Must start with Finder Info (32 bytes) */
        u_int8_t    pad[2];        /* get better alignment inside attr_header */
        apple_double_entry_t   entries[2];  /* 'finfo' & 'rsrc' always exist */
        u_int8_t    finfo[FINDERINFOSIZE];  /* Must start with Finder Info (32 bytes) */
        u_int8_t    pad[2];        /* get better alignment inside attr_header */
-} apple_double_header_t;
+} __attribute__((aligned(2), packed)) apple_double_header_t;
 
 #define ADHDRSIZE  (4+4+16+2)
 
 
 #define ADHDRSIZE  (4+4+16+2)
 
@@ -1136,7 +1369,7 @@ typedef struct attr_entry {
        u_int16_t   flags;
        u_int8_t    namelen;
        u_int8_t    name[1];    /* NULL-terminated UTF-8 name (up to 128 bytes max) */
        u_int16_t   flags;
        u_int8_t    namelen;
        u_int8_t    name[1];    /* NULL-terminated UTF-8 name (up to 128 bytes max) */
-} attr_entry_t;
+} __attribute__((aligned(2), packed)) attr_entry_t;
 
 
 /* Header + entries must fit into 64K.  Data may extend beyond 64K. */
 
 
 /* Header + entries must fit into 64K.  Data may extend beyond 64K. */
@@ -1150,7 +1383,7 @@ typedef struct attr_header {
        u_int32_t   reserved[3];
        u_int16_t   flags;
        u_int16_t   num_attrs;
        u_int32_t   reserved[3];
        u_int16_t   flags;
        u_int16_t   num_attrs;
-} attr_header_t;
+} __attribute__((aligned(2), packed)) attr_header_t;
 
 
 /* Empty Resource Fork Header */
 
 
 /* Empty Resource Fork Header */
@@ -1172,14 +1405,12 @@ typedef struct rsrcfork_header {
        u_int16_t    mh_Types;
        u_int16_t    mh_Names;
        u_int16_t    typeCount;
        u_int16_t    mh_Types;
        u_int16_t    mh_Names;
        u_int16_t    typeCount;
-} rsrcfork_header_t;
+} __attribute__((aligned(2), packed)) rsrcfork_header_t;
 
 #define RF_FIRST_RESOURCE    256
 #define RF_NULL_MAP_LENGTH    30
 #define RF_EMPTY_TAG  "This resource fork intentionally left blank   "
 
 
 #define RF_FIRST_RESOURCE    256
 #define RF_NULL_MAP_LENGTH    30
 #define RF_EMPTY_TAG  "This resource fork intentionally left blank   "
 
-#pragma options align=reset
-
 /* Runtime information about the attribute file. */
 typedef struct attr_info {
        vfs_context_t          context;
 /* Runtime information about the attribute file. */
 typedef struct attr_info {
        vfs_context_t          context;
@@ -1353,7 +1584,7 @@ static int check_and_swap_apple_double_header(attr_info_t *ainfop)
 /*
  * Retrieve the data of an extended attribute.
  */
 /*
  * Retrieve the data of an extended attribute.
  */
-int
+static int
 default_getxattr(vnode_t vp, const char *name, uio_t uio, size_t *size,
                  __unused int options, vfs_context_t context)
 {
 default_getxattr(vnode_t vp, const char *name, uio_t uio, size_t *size,
                  __unused int options, vfs_context_t context)
 {
@@ -1475,7 +1706,7 @@ out:
 /*
  * Set the data of an extended attribute.
  */
 /*
  * Set the data of an extended attribute.
  */
-int
+static int
 default_setxattr(vnode_t vp, const char *name, uio_t uio, int options, vfs_context_t context)
 {
        vnode_t xvp = NULL;
 default_setxattr(vnode_t vp, const char *name, uio_t uio, int options, vfs_context_t context)
 {
        vnode_t xvp = NULL;
@@ -1602,19 +1833,34 @@ start:
                        error = EPERM;
                        goto out;
                }
                        error = EPERM;
                        goto out;
                }
-               if (ainfo.rsrcfork && ainfo.rsrcfork->length) {
-                       /* attr exists and "create" was specified? */
-                       if (options & XATTR_CREATE) {
-                               error = EEXIST;
-                               goto out;
+               /* Make sure we have a rsrc fork pointer.. */
+               if (ainfo.rsrcfork == NULL) {
+                       error = ENOATTR;
+                       goto out;
+               }
+               if (ainfo.rsrcfork) {
+                       if (ainfo.rsrcfork->length != 0) {
+                               if (options & XATTR_CREATE) {
+                                       /* attr exists, and create specified ? */
+                                       error = EEXIST;
+                                       goto out;
+                               }       
                        }
                        }
-               } else {
-                       /* attr doesn't exists and "replace" was specified? */
-                       if (options & XATTR_REPLACE) {
-                               error = ENOATTR;
-                               goto out;
+                       else {
+                               /* Zero length AD rsrc fork */
+                               if (options & XATTR_REPLACE) {
+                                       /* attr doesn't exist (0-length), but replace specified ? */
+                                       error = ENOATTR;
+                                       goto out;
+                               }
                        }
                }
                        }
                }
+               else {
+                       /* We can't do much if we somehow didn't get an AD rsrc pointer */
+                       error = ENOATTR;
+                       goto out;
+               }
+
                endoffset = uio_resid(uio) + uio_offset(uio); /* new size */
                uio_setoffset(uio, uio_offset(uio) + ainfo.rsrcfork->offset);
                error = VNOP_WRITE(xvp, uio, 0, context);
                endoffset = uio_resid(uio) + uio_offset(uio); /* new size */
                uio_setoffset(uio, uio_offset(uio) + ainfo.rsrcfork->offset);
                error = VNOP_WRITE(xvp, uio, 0, context);
@@ -1834,6 +2080,9 @@ out:
                        (void) vnode_setattr(vp, &va, context);
                }
        }
                        (void) vnode_setattr(vp, &va, context);
                }
        }
+       
+       post_event_if_success(vp, error, NOTE_ATTRIB);
+
        return (error);
 }
 
        return (error);
 }
 
@@ -1841,7 +2090,7 @@ out:
 /*
  * Remove an extended attribute.
  */
 /*
  * Remove an extended attribute.
  */
-int
+static int
 default_removexattr(vnode_t vp, const char *name, __unused int options, vfs_context_t context)
 {
        vnode_t xvp = NULL;
 default_removexattr(vnode_t vp, const char *name, __unused int options, vfs_context_t context)
 {
        vnode_t xvp = NULL;
@@ -2053,6 +2302,9 @@ out:
                        (void) vnode_setattr(vp, &va, context);
                }
        }
                        (void) vnode_setattr(vp, &va, context);
                }
        }
+
+       post_event_if_success(vp, error, NOTE_ATTRIB);
+
        return (error);
        
 }
        return (error);
        
 }
@@ -2082,6 +2334,8 @@ default_listxattr(vnode_t vp, uio_t uio, size_t *size, __unused int options, vfs
                return (error);
        }
        if ((error = get_xattrinfo(xvp, 0, &ainfo, context))) {
                return (error);
        }
        if ((error = get_xattrinfo(xvp, 0, &ainfo, context))) {
+               if (error == ENOATTR)
+                       error = 0;
                close_xattrfile(xvp, FREAD, context);
                return (error);
        }
                close_xattrfile(xvp, FREAD, context);
                return (error);
        }
@@ -2209,12 +2463,15 @@ open_xattrfile(vnode_t vp, int fileflags, vnode_t *xvpp, vfs_context_t context)
         * file security from the EA must always get access
         */
 lookup:
         * file security from the EA must always get access
         */
 lookup:
-       NDINIT(&nd, LOOKUP, LOCKLEAF | NOFOLLOW | USEDVP | DONOTAUTH, UIO_SYSSPACE,
-              CAST_USER_ADDR_T(filename), context);
+       NDINIT(&nd, LOOKUP, OP_OPEN, LOCKLEAF | NOFOLLOW | USEDVP | DONOTAUTH,
+              UIO_SYSSPACE, CAST_USER_ADDR_T(filename), context);
        nd.ni_dvp = dvp;
 
        if (fileflags & O_CREAT) {
                nd.ni_cnd.cn_nameiop = CREATE;
        nd.ni_dvp = dvp;
 
        if (fileflags & O_CREAT) {
                nd.ni_cnd.cn_nameiop = CREATE;
+#if CONFIG_TRIGGERS
+               nd.ni_op = OP_LINK;
+#endif
                if (dvp != vp) {
                        nd.ni_cnd.cn_flags |= LOCKPARENT;
                }
                if (dvp != vp) {
                        nd.ni_cnd.cn_flags |= LOCKPARENT;
                }
@@ -2256,11 +2513,14 @@ lookup:
                        if (gid != KAUTH_GID_NONE)
                                VATTR_SET(&va, va_gid, gid);
 
                        if (gid != KAUTH_GID_NONE)
                                VATTR_SET(&va, va_gid, gid);
 
-                       error = vn_create(dvp, &nd.ni_vp, &nd.ni_cnd, &va,
+                       error = vn_create(dvp, &nd.ni_vp, &nd, &va,
                                          VN_CREATE_NOAUTH | VN_CREATE_NOINHERIT | VN_CREATE_NOLABEL,
                                          VN_CREATE_NOAUTH | VN_CREATE_NOINHERIT | VN_CREATE_NOLABEL,
+                                         0, NULL,
                                          context);
                                          context);
-                       if (error == 0)
-                               xvp = nd.ni_vp;
+                       if (error)
+                               error = ENOATTR;
+                       else
+                               xvp = nd.ni_vp;
                }
                nameidone(&nd);
                if (dvp != vp) {
                }
                nameidone(&nd);
                if (dvp != vp) {
@@ -2269,10 +2529,10 @@ lookup:
                if (error)
                        goto out;
        } else {
                if (error)
                        goto out;
        } else {
-               if ((error = namei(&nd))) {
-                       nd.ni_dvp = NULLVP;
+               if ((error = namei(&nd))) {
+                       nd.ni_dvp = NULLVP;
                        error = ENOATTR;
                        error = ENOATTR;
-                       goto out;
+                       goto out;
                }
                xvp = nd.ni_vp;
                nameidone(&nd);
                }
                xvp = nd.ni_vp;
                nameidone(&nd);
@@ -2338,22 +2598,21 @@ lookup:
 
                locktype = (fileflags & O_EXLOCK) ? F_WRLCK : F_RDLCK;
                error = lock_xattrfile(xvp, locktype, context);
 
                locktype = (fileflags & O_EXLOCK) ? F_WRLCK : F_RDLCK;
                error = lock_xattrfile(xvp, locktype, context);
+               if (error)
+                       error = ENOATTR;
        }
 out:
        }
 out:
-       if (dvp && (dvp != vp)) {
-               vnode_put(dvp);
-       }
-       if (basename) {
-               vnode_putname(basename);
-       }
-       if (filename && filename != &smallname[0]) {
-               FREE(filename, M_TEMP);
-       }
        if (error) {
                if (xvp != NULLVP) {
                        if (opened) {
                                (void) VNOP_CLOSE(xvp, fileflags, context);
                        }
        if (error) {
                if (xvp != NULLVP) {
                        if (opened) {
                                (void) VNOP_CLOSE(xvp, fileflags, context);
                        }
+
+                       if (fileflags & O_CREAT) {
+                               /* Delete the xattr file if we encountered any errors */
+                               (void) remove_xattrfile (xvp, context); 
+                       }
+
                        if (referenced) {
                                (void) vnode_rele(xvp);
                        }
                        if (referenced) {
                                (void) vnode_rele(xvp);
                        }
@@ -2364,6 +2623,17 @@ out:
                        error = EPERM;
                }
        }
                        error = EPERM;
                }
        }
+       /* Release resources after error-handling */
+       if (dvp && (dvp != vp)) {
+               vnode_put(dvp);
+       }
+       if (basename) {
+               vnode_putname(basename);
+       }
+       if (filename && filename != &smallname[0]) {
+               FREE(filename, M_TEMP);
+       }
+
        *xvpp = xvp;  /* return a referenced vnode */
        return (error);
 }
        *xvpp = xvp;  /* return a referenced vnode */
        return (error);
 }
@@ -2402,7 +2672,7 @@ remove_xattrfile(vnode_t xvp, vfs_context_t context)
                return (error);
        }
 
                return (error);
        }
 
-       NDINIT(&nd, DELETE, LOCKPARENT | NOFOLLOW | DONOTAUTH,
+       NDINIT(&nd, DELETE, OP_UNLINK, LOCKPARENT | NOFOLLOW | DONOTAUTH,
               UIO_SYSSPACE, CAST_USER_ADDR_T(path), context);
        error = namei(&nd);
        FREE_ZONE(path, MAXPATHLEN, M_NAMEI);
               UIO_SYSSPACE, CAST_USER_ADDR_T(path), context);
        error = namei(&nd);
        FREE_ZONE(path, MAXPATHLEN, M_NAMEI);
@@ -2478,7 +2748,7 @@ get_xattrinfo(vnode_t xvp, int setting, attr_info_t *ainfop, vfs_context_t conte
                goto bail;
        }
 
                goto bail;
        }
 
-       auio = uio_create(1, 0, UIO_SYSSPACE32, UIO_READ);
+       auio = uio_create(1, 0, UIO_SYSSPACE, UIO_READ);
        uio_addiov(auio, (uintptr_t)buffer, iosize);
 
        /* Read the file header. */
        uio_addiov(auio, (uintptr_t)buffer, iosize);
 
        /* Read the file header. */
@@ -2545,7 +2815,7 @@ get_xattrinfo(vnode_t xvp, int setting, attr_info_t *ainfop, vfs_context_t conte
 
 
                                /* Read the system data which starts at byte 16 */
 
 
                                /* Read the system data which starts at byte 16 */
-                               rf_uio = uio_create(1, 0, UIO_SYSSPACE32, UIO_READ);
+                               rf_uio = uio_create(1, 0, UIO_SYSSPACE, UIO_READ);
                                uio_addiov(rf_uio, (uintptr_t)systemData, sizeof(systemData));
                                uio_setoffset(rf_uio, filehdr->entries[i].offset + 16);
                                rf_err = VNOP_READ(xvp, rf_uio, 0, context);
                                uio_addiov(rf_uio, (uintptr_t)systemData, sizeof(systemData));
                                uio_setoffset(rf_uio, filehdr->entries[i].offset + 16);
                                rf_err = VNOP_READ(xvp, rf_uio, 0, context);
@@ -2633,7 +2903,7 @@ get_xattrinfo(vnode_t xvp, int setting, attr_info_t *ainfop, vfs_context_t conte
                        attrhdr->num_attrs   = 0;
        
                        /* Push out new header */
                        attrhdr->num_attrs   = 0;
        
                        /* Push out new header */
-                       uio_reset(auio, 0, UIO_SYSSPACE32, UIO_WRITE);
+                       uio_reset(auio, 0, UIO_SYSSPACE, UIO_WRITE);
                        uio_addiov(auio, (uintptr_t)filehdr, writesize);
        
                        swap_adhdr(filehdr);    /* to big endian */
                        uio_addiov(auio, (uintptr_t)filehdr, writesize);
        
                        swap_adhdr(filehdr);    /* to big endian */
@@ -2693,7 +2963,7 @@ create_xattrfile(vnode_t xvp, u_int32_t fileid, vfs_context_t context)
        bzero(buffer, ATTR_BUF_SIZE);
 
        xah = (attr_header_t *)buffer;
        bzero(buffer, ATTR_BUF_SIZE);
 
        xah = (attr_header_t *)buffer;
-       auio = uio_create(1, 0, UIO_SYSSPACE32, UIO_WRITE);
+       auio = uio_create(1, 0, UIO_SYSSPACE, UIO_WRITE);
        uio_addiov(auio, (uintptr_t)buffer, ATTR_BUF_SIZE);
        rsrcforksize = sizeof(rsrcfork_header_t);
        rsrcforkhdr = (rsrcfork_header_t *) ((char *)buffer + ATTR_BUF_SIZE - rsrcforksize);
        uio_addiov(auio, (uintptr_t)buffer, ATTR_BUF_SIZE);
        rsrcforksize = sizeof(rsrcfork_header_t);
        rsrcforkhdr = (rsrcfork_header_t *) ((char *)buffer + ATTR_BUF_SIZE - rsrcforksize);
@@ -2720,7 +2990,12 @@ create_xattrfile(vnode_t xvp, u_int32_t fileid, vfs_context_t context)
        init_empty_resource_fork(rsrcforkhdr);
 
        /* Push it out. */
        init_empty_resource_fork(rsrcforkhdr);
 
        /* Push it out. */
-       error = VNOP_WRITE(xvp, auio, 0, context);
+       error = VNOP_WRITE(xvp, auio, IO_UNIT, context);
+
+       /* Did we write out the full uio? */
+       if (uio_resid(auio) > 0) {
+               error = ENOSPC;
+       }
 
        uio_free(auio);
        FREE(buffer, M_TEMP);
 
        uio_free(auio);
        FREE(buffer, M_TEMP);
@@ -2757,7 +3032,7 @@ write_xattrinfo(attr_info_t *ainfop)
        uio_t auio;
        int error;
 
        uio_t auio;
        int error;
 
-       auio = uio_create(1, 0, UIO_SYSSPACE32, UIO_WRITE);
+       auio = uio_create(1, 0, UIO_SYSSPACE, UIO_WRITE);
        uio_addiov(auio, (uintptr_t)ainfop->filehdr, ainfop->iosize);
 
        swap_adhdr(ainfop->filehdr);
        uio_addiov(auio, (uintptr_t)ainfop->filehdr, ainfop->iosize);
 
        swap_adhdr(ainfop->filehdr);
@@ -2930,7 +3205,7 @@ shift_data_down(vnode_t xvp, off_t start, size_t len, off_t delta, vfs_context_t
        size_t chunk, orig_chunk;
        char *buff;
        off_t pos;
        size_t chunk, orig_chunk;
        char *buff;
        off_t pos;
-       ucred_t ucred = vfs_context_ucred(context);
+       kauth_cred_t ucred = vfs_context_ucred(context);
        proc_t p = vfs_context_proc(context);
     
        if (delta == 0 || len == 0) {
        proc_t p = vfs_context_proc(context);
     
        if (delta == 0 || len == 0) {
@@ -2962,7 +3237,7 @@ shift_data_down(vnode_t xvp, off_t start, size_t len, off_t delta, vfs_context_t
                        break;
                }
                
                        break;
                }
                
-               if ((pos - chunk) < start) {
+               if ((pos - (off_t)chunk) < start) {
                        chunk = pos - start;
            
                        if (chunk == 0) {   // we're all done
                        chunk = pos - start;
            
                        if (chunk == 0) {   // we're all done
@@ -2984,7 +3259,7 @@ shift_data_up(vnode_t xvp, off_t start, size_t len, off_t delta, vfs_context_t c
        char *buff;
        off_t pos;
        off_t end;
        char *buff;
        off_t pos;
        off_t end;
-       ucred_t ucred = vfs_context_ucred(context);
+       kauth_cred_t ucred = vfs_context_ucred(context);
        proc_t p = vfs_context_proc(context);
     
        if (delta == 0 || len == 0) {
        proc_t p = vfs_context_proc(context);
     
        if (delta == 0 || len == 0) {
@@ -3017,7 +3292,7 @@ shift_data_up(vnode_t xvp, off_t start, size_t len, off_t delta, vfs_context_t c
                        break;
                }
                
                        break;
                }
                
-               if ((pos + chunk) > end) {
+               if ((pos + (off_t)chunk) > end) {
                        chunk = end - pos;
            
                        if (chunk == 0) {   // we're all done
                        chunk = end - pos;
            
                        if (chunk == 0) {   // we're all done
@@ -3041,11 +3316,11 @@ lock_xattrfile(vnode_t xvp, short locktype, vfs_context_t context)
        lf.l_len = 0;
        lf.l_type = locktype; /* F_WRLCK or F_RDLCK */
        /* Note: id is just a kernel address that's not a proc */
        lf.l_len = 0;
        lf.l_type = locktype; /* F_WRLCK or F_RDLCK */
        /* Note: id is just a kernel address that's not a proc */
-       error = VNOP_ADVLOCK(xvp, (caddr_t)xvp, F_SETLK, &lf, F_FLOCK|F_WAIT, context);
+       error = VNOP_ADVLOCK(xvp, (caddr_t)xvp, F_SETLK, &lf, F_FLOCK|F_WAIT, context, NULL);
        return (error == ENOTSUP ? 0 : error);
 }
 
        return (error == ENOTSUP ? 0 : error);
 }
 
-static int
+ int
 unlock_xattrfile(vnode_t xvp, vfs_context_t context)
 {
        struct flock lf;
 unlock_xattrfile(vnode_t xvp, vfs_context_t context)
 {
        struct flock lf;
@@ -3056,7 +3331,55 @@ unlock_xattrfile(vnode_t xvp, vfs_context_t context)
        lf.l_len = 0;
        lf.l_type = F_UNLCK;
        /* Note: id is just a kernel address that's not a proc */
        lf.l_len = 0;
        lf.l_type = F_UNLCK;
        /* Note: id is just a kernel address that's not a proc */
-       error = VNOP_ADVLOCK(xvp, (caddr_t)xvp, F_UNLCK, &lf, F_FLOCK, context);
+       error = VNOP_ADVLOCK(xvp, (caddr_t)xvp, F_UNLCK, &lf, F_FLOCK, context, NULL);
        return (error == ENOTSUP ? 0 : error);
 }
 
        return (error == ENOTSUP ? 0 : error);
 }
 
+#else /* CONFIG_APPLEDOUBLE */
+
+#undef panic
+#define        panic   printf
+
+static int
+default_getxattr(vnode_t vp, const char *name,
+    __unused uio_t uio, __unused size_t *size, __unused int options,
+    __unused vfs_context_t context)
+{
+#if PANIC_ON_NOAPPLEDOUBLE
+       panic("%s: no AppleDouble support, vp %p name %s", __func__, vp, name);
+#endif
+       return (ENOTSUP);
+}
+
+static int
+default_setxattr(vnode_t vp, const char *name,
+    __unused uio_t uio, __unused int options, __unused vfs_context_t context)
+{
+#if PANIC_ON_NOAPPLEDOUBLE
+       panic("%s: no AppleDouble support, vp %p name %s", __func__, vp, name);
+#endif
+       return (ENOTSUP);
+}
+
+static int
+default_listxattr(vnode_t vp,
+    __unused uio_t uio, __unused size_t *size, __unused int options,
+    __unused vfs_context_t context)
+{
+#if PANIC_ON_NOAPPLEDOUBLE
+       panic("%s: no AppleDouble support, vp %p name %s", __func__, vp, ".");
+#endif
+       return (ENOTSUP);
+}
+
+static int
+default_removexattr(vnode_t vp, const char *name,
+   __unused int options, __unused vfs_context_t context)
+{
+#if PANIC_ON_NOAPPLEDOUBLE
+       panic("%s: no AppleDouble support, vp %p name %s", __func__, vp, name);
+#endif
+       return (ENOTSUP);
+}
+
+#endif /* CONFIG_APPLEDOUBLE */