]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/hfs/hfs_xattr.c
xnu-3247.10.11.tar.gz
[apple/xnu.git] / bsd / hfs / hfs_xattr.c
index e7a91adddf500de41e88bec397d4384f56d6dfc2..c63dce8ea8ba0286d2c7b82de48e1ea1d22e8d82 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2014 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
@@ -38,6 +38,7 @@
 #include <sys/fsctl.h>
 #include <sys/vnode_internal.h>
 #include <sys/kauth.h>
+#include <sys/uio_internal.h>
 
 #include "hfs.h"
 #include "hfs_cnode.h"
@@ -46,6 +47,7 @@
 #include "hfs_endian.h"
 #include "hfs_btreeio.h"
 #include "hfs_fsctl.h"
+#include "hfs_cprotect.h"
 
 #include "hfscommon/headers/BTreesInternal.h"
 
@@ -67,20 +69,14 @@ struct listattr_callback_state {
 #endif /* HFS_COMPRESSION */
 };
 
-#define HFS_MAXATTRBLKS         (32 * 1024)
-
 
 /* HFS Internal Names */
 #define        XATTR_EXTENDEDSECURITY_NAME   "system.extendedsecurity"
 #define XATTR_XATTREXTENTS_NAME              "system.xattrextents"
 
-/* Faster version if we already know this is the data fork. */
-#define RSRC_FORK_EXISTS(CP)   \
-       (((CP)->c_attr.ca_blocks - (CP)->c_datafork->ff_data.cf_blocks) > 0)
-
 static u_int32_t emptyfinfo[8] = {0};
 
-static int hfs_zero_dateadded (struct cnode *cp, u_int8_t *finderinfo); 
+static int hfs_zero_hidden_fields (struct cnode *cp, u_int8_t *finderinfo); 
 
 const char hfs_attrdatafilename[] = "Attribute Data";
 
@@ -132,10 +128,10 @@ hfs_vnop_getnamedstream(struct vnop_getnamedstream_args* ap)
 #if HFS_COMPRESSION
        int hide_rsrc = hfs_hides_rsrc(ap->a_context, VTOC(vp), 1);
 #endif /* HFS_COMPRESSION */
-       if ((error = hfs_lock(VTOC(vp), HFS_EXCLUSIVE_LOCK))) {
+       if ((error = hfs_lock(VTOC(vp), HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT))) {
                return (error);
        }
-       if ((!RSRC_FORK_EXISTS(cp)
+       if ((!hfs_has_rsrc(cp)
 #if HFS_COMPRESSION
             || hide_rsrc
 #endif /* HFS_COMPRESSION */
@@ -143,7 +139,7 @@ hfs_vnop_getnamedstream(struct vnop_getnamedstream_args* ap)
                hfs_unlock(cp);
                return (ENOATTR);
        }
-       error = hfs_vgetrsrc(VTOHFS(vp), vp, svpp, TRUE, FALSE);
+       error = hfs_vgetrsrc(VTOHFS(vp), vp, svpp);
        hfs_unlock(cp);
 
        return (error);
@@ -183,10 +179,10 @@ hfs_vnop_makenamedstream(struct vnop_makenamedstream_args* ap)
                }
        }
 #endif /* HFS_COMPRESSION */
-       if ((error = hfs_lock(cp, HFS_EXCLUSIVE_LOCK))) {
+       if ((error = hfs_lock(cp, HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT))) {
                return (error);
        }
-       error = hfs_vgetrsrc(VTOHFS(vp), vp, svpp, TRUE, FALSE);
+       error = hfs_vgetrsrc(VTOHFS(vp), vp, svpp);
        hfs_unlock(cp);
 
        return (error);
@@ -199,7 +195,7 @@ int
 hfs_vnop_removenamedstream(struct vnop_removenamedstream_args* ap)
 {
        vnode_t svp = ap->a_svp;
-       struct cnode *scp;
+       cnode_t *scp = VTOC(svp);
        int error = 0;
 
        /*
@@ -209,46 +205,43 @@ hfs_vnop_removenamedstream(struct vnop_removenamedstream_args* ap)
                return (ENOATTR);
        }
 #if HFS_COMPRESSION
-       if (hfs_hides_rsrc(ap->a_context, VTOC(svp), 1)) {
+       if (hfs_hides_rsrc(ap->a_context, scp, 1)) {
                /* do nothing */
                return 0;
        }
 #endif /* HFS_COMPRESSION */
-       
-       scp = VTOC(svp);
 
-       /* Take truncate lock before taking cnode lock. */
-       hfs_lock_truncate(scp, HFS_EXCLUSIVE_LOCK);
-       if ((error = hfs_lock(scp, HFS_EXCLUSIVE_LOCK))) {
-               goto out;
-       }
-       if (VTOF(svp)->ff_size != 0) {
-               error = hfs_truncate(svp, 0, IO_NDELAY, 0, 0, ap->a_context);
+       hfs_lock_truncate(scp, HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT);
+       if (VTOF(svp)->ff_size) {
+               // hfs_truncate will deal with the cnode lock
+               error = hfs_truncate(svp, 0, IO_NDELAY, 0, ap->a_context);
        }
-       hfs_unlock(scp);
-out:
-       hfs_unlock_truncate(scp, 0);
-       return (error);
+       hfs_unlock_truncate(scp, HFS_LOCK_DEFAULT);
+
+       return error;
 }
 #endif
 
 
 /* Zero out the date added field for the specified cnode */
-static int hfs_zero_dateadded (struct cnode *cp, u_int8_t *finderinfo) {
+static int hfs_zero_hidden_fields (struct cnode *cp, u_int8_t *finderinfo) 
+{
        u_int8_t *finfo = finderinfo;
     
        /* Advance finfo by 16 bytes to the 2nd half of the finderinfo */
        finfo = finfo + 16;
        
-    if (S_ISREG(cp->c_attr.ca_mode)) {
-        struct FndrExtendedFileInfo *extinfo = (struct FndrExtendedFileInfo *)finfo;
-        extinfo->date_added = 0;
-    }
-    else if (S_ISDIR(cp->c_attr.ca_mode)) {
-        struct FndrExtendedDirInfo *extinfo = (struct FndrExtendedDirInfo *)finfo;
-        extinfo->date_added = 0;
-    }
-       else {
+       if (S_ISREG(cp->c_attr.ca_mode) || S_ISLNK(cp->c_attr.ca_mode)) {
+               struct FndrExtendedFileInfo *extinfo = (struct FndrExtendedFileInfo *)finfo;
+               extinfo->document_id = 0;
+               extinfo->date_added = 0;
+               extinfo->write_gen_counter = 0;
+       } else if (S_ISDIR(cp->c_attr.ca_mode)) {
+               struct FndrExtendedDirInfo *extinfo = (struct FndrExtendedDirInfo *)finfo;
+               extinfo->document_id = 0;
+               extinfo->date_added = 0;
+               extinfo->write_gen_counter = 0;
+       } else {
                /* Return an error */
                return -1;
        }
@@ -293,15 +286,15 @@ hfs_vnop_getxattr(struct vnop_getxattr_args *ap)
                        u_int8_t finderinfo[32];
                        bufsize = 32;
 
-                       if ((result = hfs_lock(cp, HFS_SHARED_LOCK))) {
+                       if ((result = hfs_lock(cp, HFS_SHARED_LOCK, HFS_LOCK_DEFAULT))) {
                                return (result);
                        }
                        /* Make a copy since we may not export all of it. */
                        bcopy(cp->c_finderinfo, finderinfo, sizeof(finderinfo));
                        hfs_unlock(cp);
-            
-            /* Zero out the date added field in the local copy */
-                       hfs_zero_dateadded (cp, finderinfo);
+                       
+                       /* Zero out the date added field in the local copy */
+                       hfs_zero_hidden_fields (cp, finderinfo);
 
                        /* Don't expose a symlink's private type/creator. */
                        if (vnode_islnk(vp)) {
@@ -335,12 +328,12 @@ hfs_vnop_getxattr(struct vnop_getxattr_args *ap)
                        if ( !S_ISREG(cp->c_mode) ) {
                                return (EPERM);
                        }
-                       if ((result = hfs_lock(cp, HFS_EXCLUSIVE_LOCK))) {
+                       if ((result = hfs_lock(cp, HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT))) {
                                return (result);
                        }
                        namelen = cp->c_desc.cd_namelen;
 
-                       if ( !RSRC_FORK_EXISTS(cp)) {
+                       if (!hfs_has_rsrc(cp)) {
                                hfs_unlock(cp);
                                return (ENOATTR);
                        }
@@ -349,7 +342,7 @@ hfs_vnop_getxattr(struct vnop_getxattr_args *ap)
                                openunlinked = 1;
                        }
                        
-                       result = hfs_vgetrsrc(hfsmp, vp, &rvp, TRUE, FALSE);
+                       result = hfs_vgetrsrc(hfsmp, vp, &rvp);
                        hfs_unlock(cp);
                        if (result) {
                                return (result);
@@ -405,7 +398,7 @@ hfs_vnop_getxattr(struct vnop_getxattr_args *ap)
                return (EPERM);
        }
 
-       if ((result = hfs_lock(cp, HFS_SHARED_LOCK))) {
+       if ((result = hfs_lock(cp, HFS_SHARED_LOCK, HFS_LOCK_DEFAULT))) {
                return (result);
        }
        
@@ -417,7 +410,23 @@ hfs_vnop_getxattr(struct vnop_getxattr_args *ap)
        return MacToVFSError(result);
 }
 
+// Has same limitations as hfs_getxattr_internal below
+int hfs_xattr_read(vnode_t vp, const char *name, void *data, size_t *size)
+{
+       char  uio_buf[UIO_SIZEOF(1)];
+       uio_t uio = uio_createwithbuffer(1, 0, UIO_SYSSPACE, UIO_READ, uio_buf, 
+                                                                        sizeof(uio_buf));
+
+       uio_addiov(uio, CAST_USER_ADDR_T(data), *size);
 
+       struct vnop_getxattr_args args = {
+               .a_uio = uio,
+               .a_name = name,
+               .a_size = size
+       };
+
+       return hfs_getxattr_internal(VTOC(vp), &args, VTOHFS(vp), 0);
+}
 
 /*
  * getxattr_internal
@@ -435,10 +444,9 @@ hfs_vnop_getxattr(struct vnop_getxattr_args *ap)
  *
  * NOTE: This function assumes the cnode lock for 'cp' is held exclusive or shared. 
  */ 
-
-
 int hfs_getxattr_internal (struct cnode *cp, struct vnop_getxattr_args *ap, 
-               struct hfsmount *hfsmp, u_int32_t fileid) {
+               struct hfsmount *hfsmp, u_int32_t fileid) 
+{
        
        struct filefork *btfile;
        struct BTreeIterator * iterator = NULL;
@@ -453,8 +461,7 @@ int hfs_getxattr_internal (struct cnode *cp, struct vnop_getxattr_args *ap,
 
        if (cp) {
                target_id = cp->c_fileid;
-       }
-       else {
+       } else {
                target_id = fileid;
        }
 
@@ -476,20 +483,19 @@ int hfs_getxattr_internal (struct cnode *cp, struct vnop_getxattr_args *ap,
        }
        bzero(iterator, sizeof(*iterator));
        
-       bufsize = sizeof(HFSPlusAttrData) - 2;
-       if (uio) {
-               bufsize += uio_resid(uio);
-       }
-       bufsize = MAX(bufsize, sizeof(HFSPlusAttrRecord));
-       MALLOC(recp, HFSPlusAttrRecord *, bufsize, M_TEMP, M_WAITOK);
+       /* Allocate memory for reading in the attribute record.  This buffer is 
+        * big enough to read in all types of attribute records.  It is not big 
+        * enough to read inline attribute data which is read in later.
+        */
+       MALLOC(recp, HFSPlusAttrRecord *, sizeof(HFSPlusAttrRecord), M_TEMP, M_WAITOK);
        if (recp == NULL) {
                result = ENOMEM;
                goto exit;
        }
        btdata.bufferAddress = recp;
-       btdata.itemSize = bufsize;
+       btdata.itemSize = sizeof(HFSPlusAttrRecord);
        btdata.itemCount = 1;
-       
+
        result = hfs_buildattrkey(target_id, ap->a_name, (HFSPlusAttrKey *)&iterator->key);
        if (result) {
                goto exit;
@@ -512,8 +518,9 @@ int hfs_getxattr_internal (struct cnode *cp, struct vnop_getxattr_args *ap,
         * we have extent based EAs.
         */
        switch (recp->recordType) {
+
                /* Attribute fits in the Attribute B-Tree */
-               case kHFSPlusAttrInlineData:
+               case kHFSPlusAttrInlineData: {
                        /*
                         * Sanity check record size. It's not required to have any
                         * user data, so the minimum size is 2 bytes less that the
@@ -521,26 +528,63 @@ int hfs_getxattr_internal (struct cnode *cp, struct vnop_getxattr_args *ap,
                         * has 2 bytes set aside for attribute data).
                         */
                        if (datasize < (sizeof(HFSPlusAttrData) - 2)) {
-                               printf("hfs_getxattr: %d,%s invalid record size %d (expecting %lu)\n", 
-                                          target_id, ap->a_name, datasize, sizeof(HFSPlusAttrData));
+                               printf("hfs_getxattr: vol=%s %d,%s invalid record size %d (expecting %lu)\n", 
+                                          hfsmp->vcbVN, target_id, ap->a_name, datasize, sizeof(HFSPlusAttrData));
                                result = ENOATTR;
                                break;
                        }
                        *ap->a_size = recp->attrData.attrSize;
                        if (uio && recp->attrData.attrSize != 0) {
                                if (*ap->a_size > (user_size_t)uio_resid(uio)) {
+                                       /* User provided buffer is not large enough for the xattr data */
                                        result = ERANGE;
-                               }
-                               else {
+                               } else {
+                                       /* Previous BTreeSearchRecord() read in only the attribute record, 
+                                        * and not the attribute data.  Now allocate enough memory for 
+                                        * both attribute record and data, and read the attribute record again. 
+                                        */
+                                       bufsize = sizeof(HFSPlusAttrData) - 2 + recp->attrData.attrSize;
+                                       FREE(recp, M_TEMP);
+                                       MALLOC(recp, HFSPlusAttrRecord *, bufsize, M_TEMP, M_WAITOK);
+                                       if (recp == NULL) {
+                                               result = ENOMEM;
+                                               goto exit;
+                                       }
+
+                                       btdata.bufferAddress = recp;
+                                       btdata.itemSize = bufsize;
+                                       btdata.itemCount = 1;
+
+                                       bzero(iterator, sizeof(*iterator));
+                                       result = hfs_buildattrkey(target_id, ap->a_name, (HFSPlusAttrKey *)&iterator->key);
+                                       if (result) {
+                                               goto exit;
+                                       }
+
+                                       /* Lookup the attribute record and inline data */
+                                       lockflags = hfs_systemfile_lock(hfsmp, SFL_ATTRIBUTE, HFS_SHARED_LOCK);
+                                       result = BTSearchRecord(btfile, iterator, &btdata, &datasize, NULL);
+                                       hfs_systemfile_unlock(hfsmp, lockflags);
+                                       if (result) {
+                                               if (result == btNotFound) {
+                                                       result = ENOATTR;
+                                               }
+                                               goto exit;
+                                       }
+
+                                       /* Copy-out the attribute data to the user buffer */
+                                       *ap->a_size = recp->attrData.attrSize;
                                        result = uiomove((caddr_t) &recp->attrData.attrData , recp->attrData.attrSize, uio);
                                }
                        }
                        break;
+               }
+
                /* Extent-Based EAs */
                case kHFSPlusAttrForkData: {
                        if (datasize < sizeof(HFSPlusAttrForkData)) {
-                               printf("hfs_getxattr: %d,%s invalid record size %d (expecting %lu)\n", 
-                                          target_id, ap->a_name, datasize, sizeof(HFSPlusAttrForkData));
+                               printf("hfs_getxattr: vol=%s %d,%s invalid record size %d (expecting %lu)\n", 
+                                          hfsmp->vcbVN, target_id, ap->a_name, datasize, sizeof(HFSPlusAttrForkData));
                                result = ENOATTR;
                                break;
                        }
@@ -563,7 +607,7 @@ int hfs_getxattr_internal (struct cnode *cp, struct vnop_getxattr_args *ap,
                                
                                totalblocks = recp->forkData.theFork.totalBlocks;
                                /* Ignore bogus block counts. */
-                               if (totalblocks > HFS_MAXATTRBLKS) {
+                               if (totalblocks > howmany(HFS_XATTR_MAXSIZE, hfsmp->blockSize)) {
                                        result = ERANGE;
                                        break;
                                }
@@ -609,14 +653,12 @@ int hfs_getxattr_internal (struct cnode *cp, struct vnop_getxattr_args *ap,
                                
                                if (blkcnt < totalblocks) {
                                        result = ENOATTR;
-                               } 
-                               else {
+                               } else {
                                        result = read_attr_data(hfsmp, uio, attrlen, extentbuf);
                                }
                                FREE(extentbuf, M_TEMP);
                                
-                       } 
-                       else /* No overflow extents. */ {
+                       } else { /* No overflow extents. */
                                result = read_attr_data(hfsmp, uio, recp->forkData.theFork.logicalSize, recp->forkData.theFork.extents);
                        }
                        break;
@@ -680,9 +722,9 @@ hfs_vnop_setxattr(struct vnop_setxattr_args *ap)
                if (result != 0)
                        return result;
        }
-
-       check_for_tracked_file(vp, orig_ctime, NAMESPACE_HANDLER_METADATA_WRITE_OP, NULL);
 #endif /* HFS_COMPRESSION */
+
+       check_for_tracked_file(vp, orig_ctime, NAMESPACE_HANDLER_METADATA_WRITE_OP, NSPACE_REARM_NO_ARG);
        
        /* Set the Finder Info. */
        if (bcmp(ap->a_name, XATTR_FINDERINFO_NAME, sizeof(XATTR_FINDERINFO_NAME)) == 0) {
@@ -692,6 +734,8 @@ hfs_vnop_setxattr(struct vnop_setxattr_args *ap)
                u_int8_t *finfo = NULL;
                u_int16_t fdFlags;
                u_int32_t dateadded = 0;
+               u_int32_t write_gen_counter = 0;
+               u_int32_t document_id = 0;
 
                attrsize = sizeof(VTOC(vp)->c_finderinfo);
 
@@ -704,7 +748,7 @@ hfs_vnop_setxattr(struct vnop_setxattr_args *ap)
                }
                fip = (struct FndrFileInfo *)&finderinfo;
 
-               if ((result = hfs_lock(VTOC(vp), HFS_EXCLUSIVE_LOCK))) {
+               if ((result = hfs_lock(VTOC(vp), HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT))) {
                        return (result);
                }
                cp = VTOC(vp);
@@ -728,9 +772,28 @@ hfs_vnop_setxattr(struct vnop_setxattr_args *ap)
 
                /* Grab the current date added from the cnode */
                dateadded = hfs_get_dateadded (cp);
-        
-               /* Zero out the date added field to ignore user's attempts to set it */
-               hfs_zero_dateadded(cp, finderinfo);
+               if (S_ISREG(cp->c_attr.ca_mode) || S_ISLNK(cp->c_attr.ca_mode)) {
+                       struct FndrExtendedFileInfo *extinfo = (struct FndrExtendedFileInfo *)((u_int8_t*)cp->c_finderinfo + 16);
+                       /* 
+                        * Grab generation counter directly from the cnode 
+                        * instead of calling hfs_get_gencount(), because 
+                        * for zero generation count values hfs_get_gencount() 
+                        * lies and bumps it up to one.
+                        */
+                       write_gen_counter = extinfo->write_gen_counter;
+                       document_id = extinfo->document_id;
+               } else if (S_ISDIR(cp->c_attr.ca_mode)) {
+                       struct FndrExtendedDirInfo *extinfo = (struct FndrExtendedDirInfo *)((u_int8_t*)cp->c_finderinfo + 16);
+                       write_gen_counter = extinfo->write_gen_counter;
+                       document_id = extinfo->document_id;
+               }
+
+               /* 
+                * Zero out the finder info's reserved fields like date added, 
+                * generation counter, and document id to ignore user's attempts 
+                * to set it 
+                */ 
+               hfs_zero_hidden_fields(cp, finderinfo);
 
                if (bcmp(finderinfo_start, emptyfinfo, attrsize)) {
                        /* attr exists and "create" was specified. */
@@ -738,7 +801,7 @@ hfs_vnop_setxattr(struct vnop_setxattr_args *ap)
                                hfs_unlock(cp);
                                return (EEXIST);
                        }
-               } else /* empty */ {
+               } else { /* empty */
                        /* attr doesn't exists and "replace" was specified. */
                        if (ap->a_options & XATTR_REPLACE) {
                                hfs_unlock(cp);
@@ -747,30 +810,33 @@ hfs_vnop_setxattr(struct vnop_setxattr_args *ap)
                }
 
                /* 
-                * Now restore the date added to the finderinfo to be written out.
-                * Advance to the 2nd half of the finderinfo to write out the date added
-                * into the buffer.
+                * Now restore the date added and other reserved fields to the finderinfo to 
+                * be written out.  Advance to the 2nd half of the finderinfo to write them 
+                * out into the buffer.
                 *
                 * Make sure to endian swap the date added back into big endian.  When we used
                 * hfs_get_dateadded above to retrieve it, it swapped into local endianness
                 * for us.  But now that we're writing it out, put it back into big endian.
                 */
                finfo = &finderinfo[16];
-
-               if (S_ISREG(cp->c_attr.ca_mode)) {
+               if (S_ISREG(cp->c_attr.ca_mode) || S_ISLNK(cp->c_attr.ca_mode)) {
                        struct FndrExtendedFileInfo *extinfo = (struct FndrExtendedFileInfo *)finfo;
                        extinfo->date_added = OSSwapHostToBigInt32(dateadded);
-               }
-               else if (S_ISDIR(cp->c_attr.ca_mode)) {
+                       extinfo->write_gen_counter = write_gen_counter;
+                       extinfo->document_id = document_id;
+               } else if (S_ISDIR(cp->c_attr.ca_mode)) {
                        struct FndrExtendedDirInfo *extinfo = (struct FndrExtendedDirInfo *)finfo;
                        extinfo->date_added = OSSwapHostToBigInt32(dateadded);
+                       extinfo->write_gen_counter = write_gen_counter;
+                       extinfo->document_id = document_id;
                }
 
                /* Set the cnode's Finder Info. */
-               if (attrsize == sizeof(cp->c_finderinfo))
+               if (attrsize == sizeof(cp->c_finderinfo)) {
                        bcopy(&finderinfo[0], finderinfo_start, attrsize);
-               else
+               } else {
                        bcopy(&finderinfo[8], finderinfo_start, attrsize);
+               }
        
                /* Updating finderInfo updates change time and modified time */
                cp->c_touch_chgtime = TRUE;
@@ -784,12 +850,13 @@ hfs_vnop_setxattr(struct vnop_setxattr_args *ap)
                 * are both 16-bit fields.
                 */
                fdFlags = *((u_int16_t *) &cp->c_finderinfo[8]);
-               if (fdFlags & OSSwapHostToBigConstInt16(kFinderInvisibleMask))
+               if (fdFlags & OSSwapHostToBigConstInt16(kFinderInvisibleMask)) {
                        cp->c_bsdflags |= UF_HIDDEN;
-               else
+               } else {
                        cp->c_bsdflags &= ~UF_HIDDEN;
+               }
 
-               result = hfs_update(vp, FALSE);
+               result = hfs_update(vp, 0);
 
                hfs_unlock(cp);
                return (result);
@@ -803,13 +870,13 @@ hfs_vnop_setxattr(struct vnop_setxattr_args *ap)
                if (!vnode_isreg(vp)) {
                        return (EPERM);
                }
-               if ((result = hfs_lock(VTOC(vp), HFS_EXCLUSIVE_LOCK))) {
+               if ((result = hfs_lock(VTOC(vp), HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT))) {
                        return (result);
                }
                cp = VTOC(vp);
                namelen = cp->c_desc.cd_namelen;
 
-               if (RSRC_FORK_EXISTS(cp)) {
+               if (hfs_has_rsrc(cp)) {
                        /* attr exists and "create" was specified. */
                        if (ap->a_options & XATTR_CREATE) {
                                hfs_unlock(cp);
@@ -831,7 +898,7 @@ hfs_vnop_setxattr(struct vnop_setxattr_args *ap)
                        openunlinked = 1;
                }
 
-               result = hfs_vgetrsrc(hfsmp, vp, &rvp, TRUE, FALSE);
+               result = hfs_vgetrsrc(hfsmp, vp, &rvp);
                hfs_unlock(cp);
                if (result) {
                        return (result);
@@ -847,10 +914,9 @@ hfs_vnop_setxattr(struct vnop_setxattr_args *ap)
                                vnode_rele(rvp);
                        }
                        vnode_recycle (rvp);    
-               }
-               else {
+               } else {
                        /* cnode is not open-unlinked, so re-lock cnode to sync */
-                       if ((result = hfs_lock(cp, HFS_EXCLUSIVE_LOCK))) {
+                       if ((result = hfs_lock(cp, HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT))) {
                                vnode_recycle (rvp);
                                vnode_put(rvp);
                                return result;
@@ -879,7 +945,9 @@ hfs_vnop_setxattr(struct vnop_setxattr_args *ap)
        }
 
        /*
-        * Attempt to copy the users attr data before taking any locks.
+        * Attempt to copy the users attr data before taking any locks,
+        * only if it will be an inline attribute.  For larger attributes, 
+        * the data will be directly read from the uio.
         */
        if (attrsize > 0 &&
            hfsmp->hfs_max_inline_attrsize != 0 &&
@@ -896,7 +964,7 @@ hfs_vnop_setxattr(struct vnop_setxattr_args *ap)
                }
        }
 
-       result = hfs_lock(VTOC(vp), HFS_EXCLUSIVE_LOCK);
+       result = hfs_lock(VTOC(vp), HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT);
        if (result) {
                goto exit;
        }
@@ -919,6 +987,16 @@ hfs_vnop_setxattr(struct vnop_setxattr_args *ap)
        return (result == btNotFound ? ENOATTR : MacToVFSError(result));
 }
 
+// Has same limitations as hfs_setxattr_internal below
+int hfs_xattr_write(vnode_t vp, const char *name, const void *data, size_t size)
+{
+       struct vnop_setxattr_args args = {
+               .a_vp   = vp,
+               .a_name = name,
+       };
+
+       return hfs_setxattr_internal(VTOC(vp), data, size, &args, VTOHFS(vp), 0);
+}
 
 /*
  * hfs_setxattr_internal
@@ -936,9 +1014,10 @@ hfs_vnop_setxattr(struct vnop_setxattr_args *ap)
  *             3. If data originates entirely in-kernel, use a null UIO, and ensure the size is less than 
  *                     hfsmp->hfs_max_inline_attrsize bytes long. 
  */ 
-int hfs_setxattr_internal (struct cnode *cp, caddr_t data_ptr, size_t attrsize,
+int hfs_setxattr_internal (struct cnode *cp, const void *data_ptr, size_t attrsize,
                                                   struct vnop_setxattr_args *ap, struct hfsmount *hfsmp, 
-                                                  u_int32_t fileid) {
+                                                  u_int32_t fileid) 
+{
        uio_t uio = ap->a_uio;
        struct vnode *vp = ap->a_vp;
        int started_transaction = 0;
@@ -953,22 +1032,11 @@ int hfs_setxattr_internal (struct cnode *cp, caddr_t data_ptr, size_t attrsize,
        int exists = 0;
        int allocatedblks = 0;
        u_int32_t target_id;
-       int takelock = 1;
 
        if (cp) {
                target_id = cp->c_fileid;
-       }
-       else {
+       } else {
                target_id = fileid;
-               if (target_id != 1) {
-                       /* 
-                        * If we are manipulating something other than 
-                        * the root folder (id 1), and do not have a cnode-in-hand, 
-                        * then we must already hold the requisite b-tree locks from 
-                        * earlier up the call stack. (See hfs_makenode)
-                        */
-                       takelock = 0;
-               }
        }
        
        /* Start a transaction for our changes. */
@@ -1001,10 +1069,7 @@ int hfs_setxattr_internal (struct cnode *cp, caddr_t data_ptr, size_t attrsize,
                hfsmp->hfs_max_inline_attrsize = getmaxinlineattrsize(hfsmp->hfs_attribute_vp);
        }
 
-       if (takelock) {
-               /* Take exclusive access to the attributes b-tree. */
-               lockflags = hfs_systemfile_lock(hfsmp, SFL_ATTRIBUTE, HFS_EXCLUSIVE_LOCK);
-       }
+       lockflags = hfs_systemfile_lock(hfsmp, SFL_ATTRIBUTE, HFS_EXCLUSIVE_LOCK);
 
        /* Build the b-tree key. */
        MALLOC(iterator, BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK);
@@ -1074,8 +1139,8 @@ int hfs_setxattr_internal (struct cnode *cp, caddr_t data_ptr, size_t attrsize,
                if (result) {
                        if (vp) {
                                const char *name = vnode_getname(vp);
-                               printf("hfs_setxattr: write_attr_data err (%d) %s:%s\n",
-                                               result,  name ? name : "", ap->a_name);
+                               printf("hfs_setxattr: write_attr_data vol=%s err (%d) %s:%s\n",
+                                               hfsmp->vcbVN, result,  name ? name : "", ap->a_name);
                                if (name)
                                        vnode_putname(name);
                        }
@@ -1088,8 +1153,8 @@ int hfs_setxattr_internal (struct cnode *cp, caddr_t data_ptr, size_t attrsize,
                        if (result) {
                                if (vp) {
                                        const char *name = vnode_getname(vp);
-                                       printf("hfs_setxattr: remove_attribute_records err (%d) %s:%s\n",
-                                                       result, name ? name : "", ap->a_name);
+                                       printf("hfs_setxattr: remove_attribute_records vol=%s err (%d) %s:%s\n",
+                                                       hfsmp->vcbVN, result, name ? name : "", ap->a_name);
                                        if (name)
                                                vnode_putname(name);
                                }
@@ -1117,8 +1182,8 @@ int hfs_setxattr_internal (struct cnode *cp, caddr_t data_ptr, size_t attrsize,
                
                result = BTInsertRecord(btfile, iterator, &btdata, btdata.itemSize);
                if (result) {
-                       printf ("hfs_setxattr: BTInsertRecord() - %d,%s err=%d\n", 
-                                       target_id, ap->a_name, result);
+                       printf ("hfs_setxattr: BTInsertRecord(): vol=%s %d,%s err=%d\n", 
+                                       hfsmp->vcbVN, target_id, ap->a_name, result);
                        goto exit; 
                }
                extentblks = count_extent_blocks(blkcnt, recp->forkData.theFork.extents);
@@ -1140,15 +1205,14 @@ int hfs_setxattr_internal (struct cnode *cp, caddr_t data_ptr, size_t attrsize,
                        
                        result = BTInsertRecord(btfile, iterator, &btdata, btdata.itemSize);
                        if (result) {
-                               printf ("hfs_setxattr: BTInsertRecord() overflow - %d,%s err=%d\n", 
-                                               target_id, ap->a_name, result);
+                               printf ("hfs_setxattr: BTInsertRecord() overflow: vol=%s %d,%s err=%d\n", 
+                                               hfsmp->vcbVN, target_id, ap->a_name, result);
                                goto exit;
                        }
                        extentblks = count_extent_blocks(blkcnt, recp->overflowExtents.extents);
                        blkcnt -= extentblks;
                }
-       }
-       else { /* Inline data */ 
+       } else { /* Inline data */ 
                if (exists) {
                        result = remove_attribute_records(hfsmp, iterator);
                        if (result) {
@@ -1172,8 +1236,7 @@ int hfs_setxattr_internal (struct cnode *cp, caddr_t data_ptr, size_t attrsize,
                if (attrsize > 0) {
                        if (data_ptr) {
                                bcopy(data_ptr, &recp->attrData.attrData, attrsize);
-                       }
-                       else {
+                       } else {
                                /* 
                                 * A null UIO meant it originated in-kernel.  If they didn't supply data_ptr 
                                 * then deny the copy operation.
@@ -1201,9 +1264,7 @@ exit:
        if (btfile && started_transaction) {
                (void) BTFlushPath(btfile);
        }
-       if (lockflags) {
-               hfs_systemfile_unlock(hfsmp, lockflags);
-       }
+       hfs_systemfile_unlock(hfsmp, lockflags);
        if (result == 0) {
                if (vp) {
                        cp = VTOC(vp);
@@ -1211,6 +1272,7 @@ exit:
                         * modified time of the file.
                         */
                        cp->c_touch_chgtime = TRUE;
+                       cp->c_flag |= C_MODIFIED;
                        cp->c_attr.ca_recflags |= kHFSHasAttributesMask;
                        if ((bcmp(ap->a_name, KAUTH_FILESEC_XATTR, sizeof(KAUTH_FILESEC_XATTR)) == 0)) {
                                cp->c_attr.ca_recflags |= kHFSHasSecurityMask;
@@ -1276,9 +1338,9 @@ hfs_vnop_removexattr(struct vnop_removexattr_args *ap)
        if (hfs_hides_xattr(ap->a_context, VTOC(vp), ap->a_name, 1) && !(ap->a_options & XATTR_SHOWCOMPRESSION)) {
                return ENOATTR;
        }
-
-       check_for_tracked_file(vp, orig_ctime, NAMESPACE_HANDLER_METADATA_DELETE_OP, NULL);
 #endif /* HFS_COMPRESSION */
+
+       check_for_tracked_file(vp, orig_ctime, NAMESPACE_HANDLER_METADATA_DELETE_OP, NSPACE_REARM_NO_ARG);
        
        /* If Resource Fork is non-empty then truncate it. */
        if (bcmp(ap->a_name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) == 0) {
@@ -1287,22 +1349,26 @@ hfs_vnop_removexattr(struct vnop_removexattr_args *ap)
                if ( !vnode_isreg(vp) ) {
                        return (EPERM);
                }
-               if ((result = hfs_lock(cp, HFS_EXCLUSIVE_LOCK))) {
+               if ((result = hfs_lock(cp, HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT))) {
                        return (result);
                }
-               if ( !RSRC_FORK_EXISTS(cp)) {
+               if (!hfs_has_rsrc(cp)) {
                        hfs_unlock(cp);
                        return (ENOATTR);
                }
-               result = hfs_vgetrsrc(hfsmp, vp, &rvp, TRUE, FALSE);
+               result = hfs_vgetrsrc(hfsmp, vp, &rvp);
                hfs_unlock(cp);
                if (result) {
                        return (result);
                }
 
-               hfs_lock_truncate(VTOC(rvp), HFS_EXCLUSIVE_LOCK);
-               if ((result = hfs_lock(VTOC(rvp), HFS_EXCLUSIVE_LOCK))) {
-                       hfs_unlock_truncate(cp, 0);
+               hfs_lock_truncate(VTOC(rvp), HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT);
+
+               // Tell UBC now before we take the cnode lock and start the transaction
+               hfs_ubc_setsize(rvp, 0, false);
+
+               if ((result = hfs_lock(VTOC(rvp), HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT))) {
+                       hfs_unlock_truncate(cp, HFS_LOCK_DEFAULT);
                        vnode_put(rvp);
                        return (result);
                }
@@ -1311,21 +1377,21 @@ hfs_vnop_removexattr(struct vnop_removexattr_args *ap)
                 * hfs_truncate() and hfs_update()
                 */
                if ((result = hfs_start_transaction(hfsmp))) {
-                       hfs_unlock_truncate(cp, 0);
+                       hfs_unlock_truncate(cp, HFS_LOCK_DEFAULT);
                        hfs_unlock(cp);
                        vnode_put(rvp);
                        return (result);
                }
 
-               result = hfs_truncate(rvp, (off_t)0, IO_NDELAY, 0, 0, ap->a_context);
+               result = hfs_truncate(rvp, (off_t)0, IO_NDELAY, 0, ap->a_context);
                if (result == 0) {
                        cp->c_touch_chgtime = TRUE;
                        cp->c_flag |= C_MODIFIED;
-                       result = hfs_update(vp, FALSE);
+                       result = hfs_update(vp, 0);
                }
 
                hfs_end_transaction(hfsmp);
-               hfs_unlock_truncate(VTOC(rvp), 0);
+               hfs_unlock_truncate(VTOC(rvp), HFS_LOCK_DEFAULT);
                hfs_unlock(VTOC(rvp));
 
                vnode_put(rvp);
@@ -1336,10 +1402,10 @@ hfs_vnop_removexattr(struct vnop_removexattr_args *ap)
                void * finderinfo_start;
                int finderinfo_size;
                u_int8_t finderinfo[32];
-               u_int32_t date_added;
+               u_int32_t date_added, write_gen_counter, document_id;
                u_int8_t *finfo = NULL;
         
-               if ((result = hfs_lock(cp, HFS_EXCLUSIVE_LOCK))) {
+               if ((result = hfs_lock(cp, HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT))) {
                        return (result);
                }
                
@@ -1348,7 +1414,7 @@ hfs_vnop_removexattr(struct vnop_removexattr_args *ap)
                
                
                /* Zero out the date added field in the local copy */
-               hfs_zero_dateadded (cp, finderinfo);
+               hfs_zero_hidden_fields (cp, finderinfo);
                
                /* Don't expose a symlink's private type/creator. */
                if (vnode_islnk(vp)) {
@@ -1371,21 +1437,23 @@ hfs_vnop_removexattr(struct vnop_removexattr_args *ap)
                 */
                finfo = cp->c_finderinfo;
                finfo = finfo + 16;
-               if (S_ISREG(cp->c_attr.ca_mode)) {
+               if (S_ISREG(cp->c_attr.ca_mode) || S_ISLNK(cp->c_attr.ca_mode)) {
                        struct FndrExtendedFileInfo *extinfo = (struct FndrExtendedFileInfo *)finfo;
                        date_added = extinfo->date_added;
-               }
-               else if (S_ISDIR(cp->c_attr.ca_mode)) {
+                       write_gen_counter = extinfo->write_gen_counter;
+                       document_id = extinfo->document_id;
+               } else if (S_ISDIR(cp->c_attr.ca_mode)) {
                        struct FndrExtendedDirInfo *extinfo = (struct FndrExtendedDirInfo *)finfo;
                        date_added = extinfo->date_added;
+                       write_gen_counter = extinfo->write_gen_counter;
+                       document_id = extinfo->document_id;
                }
                
                if (vnode_islnk(vp)) {
                        /* Ignore type/creator */
                        finderinfo_start = &cp->c_finderinfo[8];
                        finderinfo_size = sizeof(cp->c_finderinfo) - 8;
-               }
-               else {
+               } else {
                        finderinfo_start = &cp->c_finderinfo[0];
                        finderinfo_size = sizeof(cp->c_finderinfo);
                }
@@ -1393,19 +1461,22 @@ hfs_vnop_removexattr(struct vnop_removexattr_args *ap)
                
                
                /* Now restore the date added */
-               if (S_ISREG(cp->c_attr.ca_mode)) {
+               if (S_ISREG(cp->c_attr.ca_mode) || S_ISLNK(cp->c_attr.ca_mode)) {
                        struct FndrExtendedFileInfo *extinfo = (struct FndrExtendedFileInfo *)finfo;
                        extinfo->date_added = date_added;
-               }
-               else if (S_ISDIR(cp->c_attr.ca_mode)) {
+                       extinfo->write_gen_counter = write_gen_counter;
+                       extinfo->document_id = document_id;
+               } else if (S_ISDIR(cp->c_attr.ca_mode)) {
                        struct FndrExtendedDirInfo *extinfo = (struct FndrExtendedDirInfo *)finfo;
                        extinfo->date_added = date_added;
+                       extinfo->write_gen_counter = write_gen_counter;
+                       extinfo->document_id = document_id;
                }
         
                /* Updating finderInfo updates change time and modified time */
                cp->c_touch_chgtime = TRUE;
                cp->c_flag |= C_MODIFIED;
-               hfs_update(vp, FALSE);
+               hfs_update(vp, 0);
         
                hfs_unlock(cp);
         
@@ -1427,7 +1498,7 @@ hfs_vnop_removexattr(struct vnop_removexattr_args *ap)
        }
        bzero(iterator, sizeof(*iterator));
 
-       if ((result = hfs_lock(cp, HFS_EXCLUSIVE_LOCK))) {
+       if ((result = hfs_lock(cp, HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT))) {
                goto exit_nolock;
        }
 
@@ -1455,6 +1526,7 @@ hfs_vnop_removexattr(struct vnop_removexattr_args *ap)
                result = file_attribute_exist(hfsmp, cp->c_fileid);
                if (result == 0) {
                        cp->c_attr.ca_recflags &= ~kHFSHasAttributesMask;
+                       cp->c_flag |= C_MODIFIED;
                }
                if (result == EEXIST) {
                        result = 0;
@@ -1465,6 +1537,7 @@ hfs_vnop_removexattr(struct vnop_removexattr_args *ap)
                /* If ACL was removed, clear security bit */
                if ((bcmp(ap->a_name, KAUTH_FILESEC_XATTR, sizeof(KAUTH_FILESEC_XATTR)) == 0)) {
                        cp->c_attr.ca_recflags &= ~kHFSHasSecurityMask;
+                       cp->c_flag |= C_MODIFIED;
                }
                (void) hfs_update(vp, 0);
        }
@@ -1601,8 +1674,8 @@ remove_attribute_records(struct hfsmount *hfsmp, BTreeIterator * iterator)
                        if (result ||
                            (attrdata.recordType != kHFSPlusAttrExtents) ||
                            (datasize < sizeof(HFSPlusAttrExtents))) {
-                               printf("hfs: remove_attribute_records: BTSearchRecord %d (%d), totalblks %d\n",
-                                       MacToVFSError(result), attrdata.recordType != kHFSPlusAttrExtents, totalblks);
+                               printf("hfs: remove_attribute_records: BTSearchRecord: vol=%s, err=%d (%d), totalblks %d\n",
+                                       hfsmp->vcbVN, MacToVFSError(result), attrdata.recordType != kHFSPlusAttrExtents, totalblks);
                                result = ENOATTR;
                                break;   /* break from while */
                        }
@@ -1663,8 +1736,17 @@ hfs_vnop_listxattr(struct vnop_listxattr_args *ap)
        
        hfsmp = VTOHFS(vp);
        *ap->a_size = 0;
+       
+       /* 
+        * Take the truncate lock; this serializes us against the ioctl
+        * to truncate data & reset the decmpfs state
+        * in the compressed file handler. 
+        */
+       hfs_lock_truncate(cp, HFS_SHARED_LOCK, HFS_LOCK_DEFAULT);
 
-       if ((result = hfs_lock(cp, HFS_SHARED_LOCK))) {
+       /* Now the regular cnode lock (shared) */
+       if ((result = hfs_lock(cp, HFS_SHARED_LOCK, HFS_LOCK_DEFAULT))) {
+               hfs_unlock_truncate(cp, HFS_LOCK_DEFAULT);
                return (result);
        }
 
@@ -1674,7 +1756,7 @@ hfs_vnop_listxattr(struct vnop_listxattr_args *ap)
         * for symlinks.
         */
        bcopy(cp->c_finderinfo, finderinfo, sizeof(finderinfo));
-       hfs_zero_dateadded (cp, finderinfo);
+       hfs_zero_hidden_fields (cp, finderinfo);
        
        /* Don't expose a symlink's private type/creator. */
        if (vnode_islnk(vp)) {
@@ -1686,7 +1768,7 @@ hfs_vnop_listxattr(struct vnop_listxattr_args *ap)
        }       
 
        
-    /* If Finder Info is non-empty then export it's name. */
+       /* If Finder Info is non-empty then export it's name. */
        if (bcmp(finderinfo, emptyfinfo, sizeof(emptyfinfo)) != 0) {
                if (uio == NULL) {
                        *ap->a_size += sizeof(XATTR_FINDERINFO_NAME);
@@ -1701,11 +1783,11 @@ hfs_vnop_listxattr(struct vnop_listxattr_args *ap)
                }
        }
        /* If Resource Fork is non-empty then export it's name. */
-       if (S_ISREG(cp->c_mode) && RSRC_FORK_EXISTS(cp)) {
+       if (S_ISREG(cp->c_mode) && hfs_has_rsrc(cp)) {
 #if HFS_COMPRESSION
                if ((ap->a_options & XATTR_SHOWCOMPRESSION) ||
                    !compressed ||
-                   !hfs_hides_rsrc(ap->a_context, VTOC(vp), 1) /* 1 == don't take the cnode lock */
+                   !decmpfs_hides_rsrc(ap->a_context, VTOCMP(vp))
                    )
 #endif /* HFS_COMPRESSION */
                {
@@ -1800,6 +1882,7 @@ exit:
                FREE(iterator, M_TEMP);
        }
        hfs_unlock(cp);
+       hfs_unlock_truncate(cp, HFS_LOCK_DEFAULT);
        
        return MacToVFSError(result);
 }
@@ -1839,7 +1922,7 @@ listattr_callback(const HFSPlusAttrKey *key, __unused const HFSPlusAttrData *dat
                return (1);     /* continue */
 
 #if HFS_COMPRESSION
-       if (!state->showcompressed && hfs_hides_xattr(state->ctx, VTOC(state->vp), attrname, 1) ) /* 1 == don't take the cnode lock */
+       if (!state->showcompressed && decmpfs_hides_xattr(state->ctx, VTOCMP(state->vp), attrname) )
                return 1; /* continue */
 #endif /* HFS_COMPRESSION */
        
@@ -1868,18 +1951,28 @@ listattr_callback(const HFSPlusAttrKey *key, __unused const HFSPlusAttrData *dat
  *
  * This function takes the necessary locks on the attribute
  * b-tree file and the allocation (bitmap) file.
+ *
+ * NOTE: Upon sucecss, this function will return with an open
+ * transaction.  The reason we do it this way is because when we
+ * delete the last attribute, we must make sure the flag in the
+ * catalog record that indicates there are no more records is cleared.
+ * The caller is responsible for doing this and *must* do it before
+ * ending the transaction.
  */
 int
-hfs_removeallattr(struct hfsmount *hfsmp, u_int32_t fileid)
+hfs_removeallattr(struct hfsmount *hfsmp, u_int32_t fileid, 
+                                 bool *open_transaction)
 {
        BTreeIterator *iterator = NULL;
        HFSPlusAttrKey *key;
        struct filefork *btfile;
-       int result, lockflags;
+       int result, lockflags = 0;
+
+       *open_transaction = false;
+
+       if (hfsmp->hfs_attribute_vp == NULL)
+               return 0;
 
-       if (hfsmp->hfs_attribute_vp == NULL) {
-               return (0);
-       }
        btfile = VTOF(hfsmp->hfs_attribute_vp);
 
        MALLOC(iterator, BTreeIterator *, sizeof(BTreeIterator), M_TEMP, M_WAITOK);
@@ -1890,25 +1983,32 @@ hfs_removeallattr(struct hfsmount *hfsmp, u_int32_t fileid)
        key = (HFSPlusAttrKey *)&iterator->key;
 
        /* Loop until there are no more attributes for this file id */
-       for(;;) {
+       do {
+               if (!*open_transaction)
+                       lockflags = hfs_systemfile_lock(hfsmp, SFL_ATTRIBUTE, HFS_SHARED_LOCK);
+
+               (void) hfs_buildattrkey(fileid, NULL, key);
+               result = BTIterateRecord(btfile, kBTreeNextRecord, iterator, NULL, NULL);
+               if (result || key->fileID != fileid)
+                       goto exit;
+
+               hfs_systemfile_unlock(hfsmp, lockflags);
+               lockflags = 0;
+
+               if (*open_transaction) {
+                       hfs_end_transaction(hfsmp);
+                       *open_transaction = false;
+               }
+
                if (hfs_start_transaction(hfsmp) != 0) {
                        result = EINVAL;
                        goto exit;
                }
 
-               /* Lock the attribute b-tree and the allocation (bitmap) files */
+               *open_transaction = true;
+
                lockflags = hfs_systemfile_lock(hfsmp, SFL_ATTRIBUTE | SFL_BITMAP, HFS_EXCLUSIVE_LOCK);
 
-               /*
-                * Go to first possible attribute key/record pair
-                */
-               (void) hfs_buildattrkey(fileid, NULL, key);
-               result = BTIterateRecord(btfile, kBTreeNextRecord, iterator, NULL, NULL);
-               if (result || key->fileID != fileid) {
-                       hfs_systemfile_unlock(hfsmp, lockflags);
-                       hfs_end_transaction(hfsmp);
-                       goto exit;
-               }
                result = remove_attribute_records(hfsmp, iterator);
 
 #if HFS_XATTR_VERBOSE
@@ -1916,14 +2016,22 @@ hfs_removeallattr(struct hfsmount *hfsmp, u_int32_t fileid)
                        printf("hfs_removeallattr: unexpected err %d\n", result);
                }
 #endif
+       } while (!result);
+
+exit:
+       FREE(iterator, M_TEMP);
+
+       if (lockflags)
                hfs_systemfile_unlock(hfsmp, lockflags);
+
+       result = result == btNotFound ? 0 : MacToVFSError(result);
+
+       if (result && *open_transaction) {
                hfs_end_transaction(hfsmp);
-               if (result)
-                       break;
+               *open_transaction = false;
        }
-exit:
-       FREE(iterator, M_TEMP);
-       return (result == btNotFound ? 0: MacToVFSError(result));
+
+       return result;
 }
 
 __private_extern__
@@ -2030,13 +2138,13 @@ hfs_set_volxattr(struct hfsmount *hfsmp, unsigned int xattrtype, int state)
        hfs_end_transaction(hfsmp);
 
        /* Update the state in the mount point */
-       HFS_MOUNT_LOCK(hfsmp, TRUE);
+       hfs_lock_mount (hfsmp);
        if (state == 0) {
                hfsmp->hfs_flags &= ~HFS_XATTR_EXTENTS; 
        } else {
                hfsmp->hfs_flags |= HFS_XATTR_EXTENTS; 
        }
-       HFS_MOUNT_UNLOCK(hfsmp, TRUE); 
+       hfs_unlock_mount (hfsmp);
 
 exit:
        if (iterator) {
@@ -2103,11 +2211,12 @@ hfs_attrkeycompare(HFSPlusAttrKey *searchKey, HFSPlusAttrKey *trialKey)
                /*
                 * Names are equal; compare startBlock
                 */
-               if (searchKey->startBlock == trialKey->startBlock)
+               if (searchKey->startBlock == trialKey->startBlock) {
                        return (0);
-               else
+               } else {
                        return (searchKey->startBlock < trialKey->startBlock ? -1 : 1);
                }
+       }
 
        return result;
 }
@@ -2187,7 +2296,7 @@ getmaxinlineattrsize(struct vnode * attrvp)
        size_t maxsize;
 
        if (attrvp != NULL) {
-               (void) hfs_lock(VTOC(attrvp), HFS_SHARED_LOCK);
+               (void) hfs_lock(VTOC(attrvp), HFS_SHARED_LOCK, HFS_LOCK_DEFAULT);
                if (BTGetInformation(VTOF(attrvp), 0, &btinfo) == 0)
                        nodesize = btinfo.nodeSize;
                hfs_unlock(VTOC(attrvp));
@@ -2279,13 +2388,13 @@ read_attr_data(struct hfsmount *hfsmp, uio_t uio, size_t datasize, HFSPlusExtent
 {
        vnode_t evp = hfsmp->hfs_attrdata_vp;
        int bufsize;
-       int iosize;
+       int64_t iosize;
        int attrsize;
        int blksize;
        int i;
        int result = 0;
 
-       hfs_lock_truncate(VTOC(evp), HFS_SHARED_LOCK);
+       hfs_lock_truncate(VTOC(evp), HFS_SHARED_LOCK, HFS_LOCK_DEFAULT);
 
        bufsize = (int)uio_resid(uio);
        attrsize = (int)datasize;
@@ -2296,7 +2405,7 @@ read_attr_data(struct hfsmount *hfsmp, uio_t uio, size_t datasize, HFSPlusExtent
         * For the typical case there is only one extent.
         */
        for (i = 0; (attrsize > 0) && (bufsize > 0) && (extents[i].startBlock != 0); ++i) {
-               iosize = (int)extents[i].blockCount * blksize;
+               iosize = extents[i].blockCount * blksize;
                iosize = MIN(iosize, attrsize);
                iosize = MIN(iosize, bufsize);
                uio_setresid(uio, iosize);
@@ -2305,7 +2414,7 @@ read_attr_data(struct hfsmount *hfsmp, uio_t uio, size_t datasize, HFSPlusExtent
                result = cluster_read(evp, uio, VTOF(evp)->ff_size, IO_SYNC | IO_UNIT);
 
 #if HFS_XATTR_VERBOSE
-               printf("hfs: read_attr_data: cr iosize %d [%d, %d] (%d)\n",
+               printf("hfs: read_attr_data: cr iosize %lld [%d, %d] (%d)\n",
                        iosize, extents[i].startBlock, extents[i].blockCount, result);
 #endif
                if (result)
@@ -2316,7 +2425,7 @@ read_attr_data(struct hfsmount *hfsmp, uio_t uio, size_t datasize, HFSPlusExtent
        uio_setresid(uio, bufsize);
        uio_setoffset(uio, datasize);
 
-       hfs_unlock_truncate(VTOC(evp), 0);
+       hfs_unlock_truncate(VTOC(evp), HFS_LOCK_DEFAULT);
        return (result);
 }
 
@@ -2330,12 +2439,12 @@ write_attr_data(struct hfsmount *hfsmp, uio_t uio, size_t datasize, HFSPlusExten
        off_t filesize;
        int bufsize;
        int attrsize;
-       int iosize;
+       int64_t iosize;
        int blksize;
        int i;
        int result = 0;
 
-       hfs_lock_truncate(VTOC(evp), HFS_SHARED_LOCK);
+       hfs_lock_truncate(VTOC(evp), HFS_SHARED_LOCK, HFS_LOCK_DEFAULT);
 
        bufsize = uio_resid(uio);
        attrsize = (int) datasize;
@@ -2346,7 +2455,7 @@ write_attr_data(struct hfsmount *hfsmp, uio_t uio, size_t datasize, HFSPlusExten
         * Write the attribute data one extent at a time.
         */
        for (i = 0; (attrsize > 0) && (bufsize > 0) && (extents[i].startBlock != 0); ++i) {
-               iosize = (int)extents[i].blockCount * blksize;
+               iosize = extents[i].blockCount * blksize;
                iosize = MIN(iosize, attrsize);
                iosize = MIN(iosize, bufsize);
                uio_setresid(uio, iosize);
@@ -2355,7 +2464,7 @@ write_attr_data(struct hfsmount *hfsmp, uio_t uio, size_t datasize, HFSPlusExten
                result = cluster_write(evp, uio, filesize, filesize, filesize,
                                       (off_t) 0, IO_SYNC | IO_UNIT);
 #if HFS_XATTR_VERBOSE
-               printf("hfs: write_attr_data: cw iosize %d [%d, %d] (%d)\n",
+               printf("hfs: write_attr_data: cw iosize %lld [%d, %d] (%d)\n",
                        iosize, extents[i].startBlock, extents[i].blockCount, result);
 #endif
                if (result)
@@ -2366,7 +2475,7 @@ write_attr_data(struct hfsmount *hfsmp, uio_t uio, size_t datasize, HFSPlusExten
        uio_setresid(uio, bufsize);
        uio_setoffset(uio, datasize);
 
-       hfs_unlock_truncate(VTOC(evp), 0);
+       hfs_unlock_truncate(VTOC(evp), HFS_LOCK_DEFAULT);
        return (result);
 }
 
@@ -2394,8 +2503,19 @@ alloc_attr_blks(struct hfsmount *hfsmp, size_t attrsize, size_t extentbufsize, H
        lockflags = hfs_systemfile_lock(hfsmp, SFL_BITMAP, HFS_EXCLUSIVE_LOCK);
 
        for (i = 0; (blkcnt > 0) && (i < maxextents); i++) {
+               /* Try allocating and see if we find something decent */
                result = BlockAllocate(hfsmp, startblk, blkcnt, blkcnt, 0,
                                       &extents[i].startBlock, &extents[i].blockCount);
+               /* 
+                * If we couldn't find anything, then re-try the allocation but allow
+                * journal flushes.
+                */
+               if (result == dskFulErr) {
+                       result = BlockAllocate(hfsmp, startblk, blkcnt, blkcnt, HFS_ALLOC_FLUSHTXN,
+                                       &extents[i].startBlock, &extents[i].blockCount);
+               }
+
+               
 #if HFS_XATTR_VERBOSE
                printf("hfs: alloc_attr_blks: BA blkcnt %d [%d, %d] (%d)\n",
                        blkcnt, extents[i].startBlock, extents[i].blockCount, result);
@@ -2513,3 +2633,4 @@ count_extent_blocks(int maxblks, HFSPlusExtentRecord extents)
        }
        return (blocks);
 }
+