+
+ /*
+ * If we represent the last fork (or none in the case of a dir),
+ * and the cnode has become open-unlinked,
+ * AND it has EA's, then we need to get rid of them.
+ *
+ * Note that this must happen outside of any other transactions
+ * because it starts/ends its own transactions and grabs its
+ * own locks. This is to prevent a file with a lot of attributes
+ * from creating a transaction that is too large (which panics).
+ */
+ if ((cp->c_attr.ca_recflags & kHFSHasAttributesMask) != 0 &&
+ (cp->c_flag & C_DELETED) &&
+ (forkcount <= 1)) {
+
+ ea_error = hfs_removeallattr(hfsmp, cp->c_fileid);
+ }
+
+
+ /*
+ * If the cnode represented an open-unlinked file, then now
+ * actually remove the cnode's catalog entry and release all blocks
+ * it may have been using.
+ */
+ if ((cp->c_flag & C_DELETED) && (forkcount <= 1)) {
+ /*
+ * Mark cnode in transit so that no one can get this
+ * cnode from cnode hash.
+ */
+ // hfs_chash_mark_in_transit(hfsmp, cp);
+ // XXXdbg - remove the cnode from the hash table since it's deleted
+ // otherwise someone could go to sleep on the cnode and not
+ // be woken up until this vnode gets recycled which could be
+ // a very long time...
+ hfs_chashremove(hfsmp, cp);
+
+ cp->c_flag |= C_NOEXISTS; // XXXdbg
+ cp->c_rdev = 0;
+
+ if (started_tr == 0) {
+ if (hfs_start_transaction(hfsmp) != 0) {
+ error = EINVAL;
+ goto out;
+ }
+ started_tr = 1;
+ }
+
+ /*
+ * Reserve some space in the Catalog file.
+ */
+ if ((error = cat_preflight(hfsmp, CAT_DELETE, &cookie, p))) {
+ goto out;
+ }
+ cat_reserve = 1;
+
+ lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG | SFL_ATTRIBUTE, HFS_EXCLUSIVE_LOCK);
+
+ if (cp->c_blocks > 0) {
+ printf("hfs_inactive: deleting non-empty%sfile %d, "
+ "blks %d\n", VNODE_IS_RSRC(vp) ? " rsrc " : " ",
+ (int)cp->c_fileid, (int)cp->c_blocks);
+ }
+
+ //
+ // release the name pointer in the descriptor so that
+ // cat_delete() will use the file-id to do the deletion.
+ // in the case of hard links this is imperative (in the
+ // case of regular files the fileid and cnid are the
+ // same so it doesn't matter).
+ //
+ cat_releasedesc(&cp->c_desc);
+
+ /*
+ * The descriptor name may be zero,
+ * in which case the fileid is used.
+ */
+ error = cat_delete(hfsmp, &cp->c_desc, &cp->c_attr);
+
+ if (error && truncated && (error != ENXIO))
+ printf("hfs_inactive: couldn't delete a truncated file!");
+
+ /* Update HFS Private Data dir */
+ if (error == 0) {
+ hfsmp->hfs_private_attr[FILE_HARDLINKS].ca_entries--;
+ if (vnode_isdir(vp)) {
+ DEC_FOLDERCOUNT(hfsmp, hfsmp->hfs_private_attr[FILE_HARDLINKS]);
+ }
+ (void)cat_update(hfsmp, &hfsmp->hfs_private_desc[FILE_HARDLINKS],
+ &hfsmp->hfs_private_attr[FILE_HARDLINKS], NULL, NULL);
+ }
+
+ hfs_systemfile_unlock(hfsmp, lockflags);
+
+ if (error) {
+ goto out;
+ }
+
+#if QUOTA
+ if (hfsmp->hfs_flags & HFS_QUOTAS)
+ (void)hfs_chkiq(cp, -1, NOCRED, 0);
+#endif /* QUOTA */
+
+ /* Already set C_NOEXISTS at the beginning of this block */
+ cp->c_flag &= ~C_DELETED;
+ cp->c_touch_chgtime = TRUE;
+ cp->c_touch_modtime = TRUE;
+
+ if (error == 0)
+ hfs_volupdate(hfsmp, (v_type == VDIR) ? VOL_RMDIR : VOL_RMFILE, 0);
+ }
+
+ /*
+ * A file may have had delayed allocations, in which case hfs_update
+ * would not have updated the catalog record (cat_update). We need
+ * to do that now, before we lose our fork data. We also need to
+ * force the update, or hfs_update will again skip the cat_update.
+ *
+ * If the file has C_NOEXISTS set, then we can skip the hfs_update call
+ * because the catalog entry has already been removed. There would be no point
+ * to looking up the entry in the catalog to modify it when we already know it's gone
+ */
+ if ((!ISSET(cp->c_flag, C_NOEXISTS)) &&
+ ((cp->c_flag & C_MODIFIED) || cp->c_touch_acctime ||
+ cp->c_touch_chgtime || cp->c_touch_modtime)) {
+
+ if ((cp->c_flag & C_MODIFIED) || cp->c_touch_modtime){
+ cp->c_flag |= C_FORCEUPDATE;
+ }
+ hfs_update(vp, 0);
+ }
+