+ if (error = VOP_BLKATOFF(ndp->ni_dvp, ndp->ni_ufs.ufs_offset,
+ (char **)&ep, &bp))
+ return (error);
+ ep->d_ino = 0;
+ error = VOP_BWRITE(bp);
+ dp->i_flag |= IUPD|ICHG;
+ return (error);
+ }
+ /*
+ * Collapse new free space into previous entry.
+ */
+ if (error = VOP_BLKATOFF(ndp->ni_dvp,
+ ndp->ni_ufs.ufs_offset - ndp->ni_ufs.ufs_count, (char **)&ep, &bp))
+ return (error);
+ ep->d_reclen += ndp->ni_ufs.ufs_reclen;
+ error = VOP_BWRITE(bp);
+ dp->i_flag |= IUPD|ICHG;
+ return (error);
+}
+
+/*
+ * Rewrite an existing directory entry to point at the inode
+ * supplied. The parameters describing the directory entry are
+ * set up by a call to namei.
+ */
+int
+ufs_dirrewrite(dp, ip, ndp)
+ struct inode *dp, *ip;
+ struct nameidata *ndp;
+{
+ struct buf *bp;
+ struct direct *ep;
+ int error;
+
+ if (error = VOP_BLKATOFF(ITOV(dp), ndp->ni_ufs.ufs_offset,
+ (char **)&ep, &bp))
+ return (error);
+ ep->d_ino = ip->i_number;
+ error = VOP_BWRITE(bp);
+ dp->i_flag |= IUPD|ICHG;
+ return (error);
+}
+
+/*
+ * Check if a directory is empty or not.
+ * Inode supplied must be locked.
+ *
+ * Using a struct dirtemplate here is not precisely
+ * what we want, but better than using a struct direct.
+ *
+ * NB: does not handle corrupted directories.
+ */
+int
+ufs_dirempty(ip, parentino, cred)
+ register struct inode *ip;
+ ino_t parentino;
+ struct ucred *cred;
+{
+ register off_t off;
+ struct dirtemplate dbuf;
+ register struct direct *dp = (struct direct *)&dbuf;
+ int error, count;
+#define MINDIRSIZ (sizeof (struct dirtemplate) / 2)
+
+ for (off = 0; off < ip->i_size; off += dp->d_reclen) {
+ error = vn_rdwr(UIO_READ, ITOV(ip), (caddr_t)dp, MINDIRSIZ, off,
+ UIO_SYSSPACE, IO_NODELOCKED, cred, &count, (struct proc *)0);