+ pdp = dp;
+ if (ndp->ni_isdotdot) {
+ IUNLOCK(pdp); /* race to get the inode */
+ if (error = iget(dp, ndp->ni_dent.d_ino, &tdp)) {
+ ILOCK(pdp);
+ return (error);
+ }
+ if (lockparent && *ndp->ni_next == '\0')
+ ILOCK(pdp);
+ ndp->ni_vp = ITOV(tdp);
+ } else if (dp->i_number == ndp->ni_dent.d_ino) {
+ VREF(vdp); /* we want ourself, ie "." */
+ ndp->ni_vp = vdp;
+ } else {
+ if (error = iget(dp, ndp->ni_dent.d_ino, &tdp))
+ return (error);
+ if (!lockparent || *ndp->ni_next != '\0')
+ IUNLOCK(pdp);
+ ndp->ni_vp = ITOV(tdp);
+ }
+
+ /*
+ * Insert name into cache if appropriate.
+ */
+ if (ndp->ni_makeentry)
+ cache_enter(ndp);
+ return (0);
+}
+
+
+dirbad(ip, offset, how)
+ struct inode *ip;
+ off_t offset;
+ char *how;
+{
+
+ printf("%s: bad dir ino %d at offset %d: %s\n",
+ ip->i_fs->fs_fsmnt, ip->i_number, offset, how);
+ if (ip->i_fs->fs_ronly == 0)
+ panic("bad dir");
+}
+
+/*
+ * Do consistency checking on a directory entry:
+ * record length must be multiple of 4
+ * entry must fit in rest of its DIRBLKSIZ block
+ * record must be large enough to contain entry
+ * name is not longer than MAXNAMLEN
+ * name must be as long as advertised, and null terminated
+ */
+dirbadentry(ep, entryoffsetinblock)
+ register struct direct *ep;
+ int entryoffsetinblock;
+{
+ register int i;
+
+ if ((ep->d_reclen & 0x3) != 0 ||
+ ep->d_reclen > DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)) ||
+ ep->d_reclen < DIRSIZ(ep) || ep->d_namlen > MAXNAMLEN)
+ return (1);
+ for (i = 0; i < ep->d_namlen; i++)
+ if (ep->d_name[i] == '\0')
+ return (1);
+ return (ep->d_name[i]);
+}
+
+/*
+ * Write a directory entry after a call to namei, using the parameters
+ * which it left in nameidata. The argument ip is the inode which the
+ * new directory entry will refer to. The nameidata field ndp->ni_dvp
+ * is a pointer to the directory to be written, which was left locked by
+ * namei. Remaining parameters (ndp->ni_offset, ndp->ni_count) indicate
+ * how the space for the new entry is to be gotten.
+ */
+direnter(ip, ndp)
+ struct inode *ip;
+ register struct nameidata *ndp;
+{
+ register struct direct *ep, *nep;
+ register struct inode *dp = VTOI(ndp->ni_dvp);
+ struct buf *bp;
+ int loc, spacefree, error = 0;
+ u_int dsize;
+ int newentrysize;
+ char *dirbuf;
+
+ ndp->ni_dent.d_ino = ip->i_number;
+ newentrysize = DIRSIZ(&ndp->ni_dent);
+ if (ndp->ni_count == 0) {
+ /*
+ * If ndp->ni_count is 0, then namei could find no space in the
+ * directory. In this case ndp->ni_offset will be on a directory
+ * block boundary and we will write the new entry into a fresh
+ * block.
+ */
+ if (ndp->ni_offset&(DIRBLKSIZ-1))
+ panic("wdir: newblk");
+ ndp->ni_dent.d_reclen = DIRBLKSIZ;
+ ndp->ni_count = newentrysize;
+ ndp->ni_resid = newentrysize;
+ ndp->ni_base = (caddr_t)&ndp->ni_dent;
+ ndp->ni_iov = &ndp->ni_nd.nd_iovec;
+ ndp->ni_iovcnt = 1;
+ ndp->ni_rw = UIO_WRITE;
+ ndp->ni_uioseg = UIO_SYSSPACE;
+ error =
+ ufs_write(ndp->ni_dvp, &ndp->ni_uio, IO_SYNC, ndp->ni_cred);
+ if (DIRBLKSIZ > dp->i_fs->fs_fsize) {
+ panic("wdir: blksize"); /* XXX - should grow w/balloc */
+ } else {
+ dp->i_size = roundup(dp->i_size, DIRBLKSIZ);
+ dp->i_flag |= ICHG;