speed-ups using the new constants
[unix-history] / usr / src / sys / kern / vfs_lookup.c
index 9455339..d42e012 100644 (file)
@@ -1,4 +1,4 @@
-/*     vfs_lookup.c    4.19    82/07/25        */
+/*     vfs_lookup.c    4.34    82/12/22        */
 
 #include "../h/param.h"
 #include "../h/systm.h"
 
 #include "../h/param.h"
 #include "../h/systm.h"
@@ -9,24 +9,31 @@
 #include "../h/user.h"
 #include "../h/buf.h"
 #include "../h/conf.h"
 #include "../h/user.h"
 #include "../h/buf.h"
 #include "../h/conf.h"
+#include "../h/uio.h"
+#include "../h/nami.h"
 
 
-#ifdef EFS
-extern int     efs_major;
-#endif
-
-struct buf *batoffset();
-int    dirchk = 1;
+struct buf *blkatoff();
+int    dirchk = 0;
 /*
  * Convert a pathname into a pointer to a locked inode,
  * with side effects usable in creating and removing files.
  * This is a very central and rather complicated routine.
  *
  * The func argument gives the routine which returns successive
 /*
  * Convert a pathname into a pointer to a locked inode,
  * with side effects usable in creating and removing files.
  * This is a very central and rather complicated routine.
  *
  * The func argument gives the routine which returns successive
- * characters of the name to be translated.  The flag
- * argument is (0, 1, 2) depending on whether the name is to be
- * (looked up, created, deleted).  The follow argument is 1 when
- * symbolic links are to be followed when they occur at the end of
- * the name translation process.
+ * characters of the name to be translated. 
+ *
+ * The flag argument is (LOOKUP, CREATE, DELETE) depending on whether
+ * the name is to be (looked up, created, deleted).  If flag has
+ * LOCKPARENT or'ed into it and the target of the pathname exists,
+ * namei returns both the target and its parent directory locked. 
+ * If the file system is not maintained in a strict tree hierarchy,
+ * this can result in a deadlock situation.  When creating and
+ * LOCKPARENT is specified, the target may not be ".".  When deleting
+ * and LOCKPARENT is specified, the target may be ".", but the caller
+ * must check to insure it does an irele and iput instead of two iputs.
+ *
+ * The follow argument is 1 when symbolic links are to be followed
+ * when they occur at the end of the name translation process.
  *
  * Overall outline:
  *
  *
  * Overall outline:
  *
@@ -39,14 +46,19 @@ int dirchk = 1;
  *     handle degenerate case where name is null string
  *     search for name in directory, to found or notfound
  * notfound:
  *     handle degenerate case where name is null string
  *     search for name in directory, to found or notfound
  * notfound:
- *     if creating, return locked inode, leaving information on avail. slots
+ *     if creating, return locked directory, leaving info on avail. slots
  *     else return error
  * found:
  *     if at end of path and deleting, return information to allow delete
  *     else return error
  * found:
  *     if at end of path and deleting, return information to allow delete
+ *     if at end of path and rewriting (create and LOCKPARENT), lock targe
+ *       inode and return info to allow rewrite
  *     if .. and on mounted filesys, look in mount table for parent
  *     if symbolic link, massage name in buffer and continue at dirloop
  *     if more components of name, do next level at dirloop
  *     return the answer as locked inode
  *     if .. and on mounted filesys, look in mount table for parent
  *     if symbolic link, massage name in buffer and continue at dirloop
  *     if more components of name, do next level at dirloop
  *     return the answer as locked inode
+ *
+ * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent inode,
+ *      but unlocked.
  */
 struct inode *
 namei(func, flag, follow)
  */
 struct inode *
 namei(func, flag, follow)
@@ -72,7 +84,10 @@ namei(func, flag, follow)
        int nlink = 0;                  /* number of symbolic links taken */
        struct inode *pdp;              /* saved dp during symlink work */
        int i;
        int nlink = 0;                  /* number of symbolic links taken */
        struct inode *pdp;              /* saved dp during symlink work */
        int i;
+       int lockparent;
 
 
+       lockparent = flag & LOCKPARENT;
+       flag &= ~LOCKPARENT;
        /*
         * Get a buffer for the name to be translated, and copy the
         * name into the buffer.
        /*
         * Get a buffer for the name to be translated, and copy the
         * name into the buffer.
@@ -117,12 +132,6 @@ dirloop:
        /*
         * Check accessiblity of directory.
         */
        /*
         * Check accessiblity of directory.
         */
-#ifdef EFS
-       if ((dp->i_mode & IFMT) == IFCHR && major(dp->i_rdev) == efs_major) {
-               brelse(nbp);
-               return(dp);
-       }
-#endif
        if ((dp->i_mode&IFMT) != IFDIR) {
                u.u_error = ENOTDIR;
                goto bad;
        if ((dp->i_mode&IFMT) != IFDIR) {
                u.u_error = ENOTDIR;
                goto bad;
@@ -150,7 +159,7 @@ dirloop2:
         * e.g. like "/." or ".".
         */
        if (u.u_dent.d_name[0] == 0) {
         * e.g. like "/." or ".".
         */
        if (u.u_dent.d_name[0] == 0) {
-               if (flag) {
+               if (flag || lockparent) {
                        u.u_error = ENOENT;
                        goto bad;
                }
                        u.u_error = ENOENT;
                        goto bad;
                }
@@ -165,7 +174,7 @@ dirloop2:
         * case it doesn't already exist.
         */
        slotstatus = FOUND;
         * case it doesn't already exist.
         */
        slotstatus = FOUND;
-       if (flag == 1 && *cp == 0) {
+       if (flag == CREATE && *cp == 0) {
                slotstatus = NONE;
                slotfreespace = 0;
                slotneeded = DIRSIZ(&u.u_dent);
                slotstatus = NONE;
                slotfreespace = 0;
                slotneeded = DIRSIZ(&u.u_dent);
@@ -182,7 +191,7 @@ dirloop2:
                if (blkoff(fs, u.u_offset) == 0) {
                        if (bp != NULL)
                                brelse(bp);
                if (blkoff(fs, u.u_offset) == 0) {
                        if (bp != NULL)
                                brelse(bp);
-                       bp = batoffset(dp, u.u_offset, (char **)0);
+                       bp = blkatoff(dp, u.u_offset, (char **)0);
                        if (bp == 0)
                                goto bad;
                        entryoffsetinblock = 0;
                        if (bp == 0)
                                goto bad;
                        entryoffsetinblock = 0;
@@ -202,16 +211,20 @@ dirloop2:
                /*
                 * Get pointer to next entry, and do consistency checking:
                 *      record length must be multiple of 4
                /*
                 * Get pointer to next entry, and do consistency checking:
                 *      record length must be multiple of 4
+                *      record length must not be zero
                 *      entry must fit in rest of this DIRBLKSIZ block
                 *      record must be large enough to contain name
                 *      entry must fit in rest of this DIRBLKSIZ block
                 *      record must be large enough to contain name
+                * When dirchk is set we also check:
+                *      name is not longer than MAXNAMLEN
                 *      name must be as long as advertised, and null terminated
                 *      name must be as long as advertised, and null terminated
-                * Checking last condition is expensive, it is done only
-                * when dirchk is set.
+                * Checking last two conditions is done only when dirchk is
+                * set, to save time.
                 */
                ep = (struct direct *)(bp->b_un.b_addr + entryoffsetinblock);
                i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1));
                 */
                ep = (struct direct *)(bp->b_un.b_addr + entryoffsetinblock);
                i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1));
-               if ((ep->d_reclen & 0x3) || ep->d_reclen > i ||
-                   DIRSIZ(ep) > ep->d_reclen || dirchk && dirbadname(ep)) {
+               if ((ep->d_reclen & 0x3) || ep->d_reclen == 0 ||
+                   ep->d_reclen > i || DIRSIZ(ep) > ep->d_reclen ||
+                   dirchk && (ep->d_namlen > MAXNAMLEN || dirbadname(ep))) {
                        dirbad(dp, "mangled entry");
                        u.u_offset += i;
                        entryoffsetinblock += i;
                        dirbad(dp, "mangled entry");
                        u.u_offset += i;
                        entryoffsetinblock += i;
@@ -263,10 +276,10 @@ dirloop2:
 /* notfound: */
        /*
         * If creating, and at end of pathname and current
 /* notfound: */
        /*
         * If creating, and at end of pathname and current
-        * directory has not been removed, then can consider allowing
-        * file to be created.
+        * directory has not been removed, then can consider
+        * allowing file to be created.
         */
         */
-       if (flag == 1 && *cp == 0 && dp->i_nlink != 0) {
+       if (flag == CREATE && *cp == 0 && dp->i_nlink != 0) {
                /*
                 * Access for write is interpreted as allowing
                 * creation of files in the directory.
                /*
                 * Access for write is interpreted as allowing
                 * creation of files in the directory.
@@ -309,9 +322,9 @@ found:
         * Check that directory length properly reflects presence
         * of this entry.
         */
         * Check that directory length properly reflects presence
         * of this entry.
         */
-       if (entryoffsetinblock + ep->d_reclen > dp->i_size) {
+       if (entryoffsetinblock + DIRSIZ(ep) > dp->i_size) {
                dirbad(dp, "i_size too small");
                dirbad(dp, "i_size too small");
-               dp->i_size = entryoffsetinblock + ep->d_reclen;
+               dp->i_size = entryoffsetinblock + DIRSIZ(ep);
                dp->i_flag |= IUPD|ICHG;
        }
 
                dp->i_flag |= IUPD|ICHG;
        }
 
@@ -319,22 +332,24 @@ found:
         * Found component in pathname; save directory
         * entry in u.u_dent, and release directory buffer.
         */
         * Found component in pathname; save directory
         * entry in u.u_dent, and release directory buffer.
         */
-       bcopy((caddr_t)ep, (caddr_t)&u.u_dent, DIRSIZ(ep));
+       bcopy((caddr_t)ep, (caddr_t)&u.u_dent, (u_int)DIRSIZ(ep));
        brelse(bp);
        bp = NULL;
 
        /*
         * If deleting, and at end of pathname, return
         * parameters which can be used to remove file.
        brelse(bp);
        bp = NULL;
 
        /*
         * If deleting, and at end of pathname, return
         * parameters which can be used to remove file.
-        * Note that in this case we return the directory
-        * inode, not the inode of the file being deleted.
+        * If the lockparent flag isn't set, we return only
+        * the directory (in u.u_pdir), otherwise we go
+        * on and lock the inode, being careful with ".".
         */
         */
-       if (flag == 2 && *cp == 0) {
+       if (flag == DELETE && *cp == 0) {
                /*
                 * Write access to directory required to delete files.
                 */
                if (access(dp, IWRITE))
                        goto bad;
                /*
                 * Write access to directory required to delete files.
                 */
                if (access(dp, IWRITE))
                        goto bad;
+               u.u_pdir = dp;          /* for dirremove() */
                /*
                 * Return pointer to current entry in u.u_offset,
                 * and distance past previous entry (if there
                /*
                 * Return pointer to current entry in u.u_offset,
                 * and distance past previous entry (if there
@@ -345,8 +360,18 @@ found:
                        u.u_count = 0;
                else
                        u.u_count = u.u_offset - prevoff;
                        u.u_count = 0;
                else
                        u.u_count = u.u_offset - prevoff;
+               if (lockparent) {
+                       if (dp->i_number == u.u_dent.d_ino)
+                               dp->i_count++;
+                       else {
+                               dp = iget(dp->i_dev, fs, u.u_dent.d_ino);
+                               if (dp == NULL) {
+                                       iput(u.u_pdir);
+                                       goto bad;
+                               }
+                       }
+               }
                brelse(nbp);
                brelse(nbp);
-               u.u_pdir = dp;          /* for dirremove() */
                return (dp);
        }
 
                return (dp);
        }
 
@@ -375,6 +400,33 @@ found:
                }
        }
 
                }
        }
 
+       /*
+        * If rewriting (rename), return the inode and the
+        * information required to rewrite the present directory
+        * Must get inode of directory entry to verify it's a
+        * regular file, or empty directory.  
+        */
+       if ((flag == CREATE && lockparent) && *cp == 0) {
+               if (access(dp, IWRITE))
+                       goto bad;
+               u.u_pdir = dp;          /* for dirrewrite() */
+               /*
+                * Careful about locking second inode. 
+                * This can only occur if the target is ".". 
+                */
+               if (dp->i_number == u.u_dent.d_ino) {
+                       u.u_error = EISDIR;             /* XXX */
+                       goto bad;
+               }
+               dp = iget(dp->i_dev, fs, u.u_dent.d_ino);
+               if (dp == NULL) {
+                       iput(u.u_pdir);
+                       goto bad;
+               }
+               brelse(nbp);
+               return (dp);
+       }
+
        /*
         * Check for symbolic link, which may require us
         * to massage the name before we continue translation.
        /*
         * Check for symbolic link, which may require us
         * to massage the name before we continue translation.
@@ -394,19 +446,17 @@ found:
         * Check for symbolic link
         */
        if ((dp->i_mode & IFMT) == IFLNK && (follow || *cp == '/')) {
         * Check for symbolic link
         */
        if ((dp->i_mode & IFMT) == IFLNK && (follow || *cp == '/')) {
-               int pathlen = strlen(cp) + 1;
-               int bn;
+               u_int pathlen = strlen(cp) + 1;
 
                if (dp->i_size + pathlen >= MAXPATHLEN - 1 ||
                    ++nlink > MAXSYMLINKS) {
                        u.u_error = ELOOP;
                        goto bad2;
                }
 
                if (dp->i_size + pathlen >= MAXPATHLEN - 1 ||
                    ++nlink > MAXSYMLINKS) {
                        u.u_error = ELOOP;
                        goto bad2;
                }
-               bcopy(cp, nbp->b_un.b_addr + dp->i_size, pathlen);
-               u.u_segflg = 1;
-               u.u_base = nbp->b_un.b_addr;
-               u.u_count = dp->i_size;
-               readi(dp);
+               ovbcopy(cp, nbp->b_un.b_addr + dp->i_size, pathlen);
+               u.u_error =
+                   rdwri(UIO_READ, dp, nbp->b_un.b_addr, (int)dp->i_size,
+                       0, 1, (int *)0);
                if (u.u_error)
                        goto bad2;
                cp = nbp->b_un.b_addr;
                if (u.u_error)
                        goto bad2;
                cp = nbp->b_un.b_addr;
@@ -426,7 +476,6 @@ found:
                fs = dp->i_fs;
                goto dirloop;
        }
                fs = dp->i_fs;
                goto dirloop;
        }
-       irele(pdp);
 
        /*
         * Not a symbolic link.  If more pathname,
 
        /*
         * Not a symbolic link.  If more pathname,
@@ -435,9 +484,14 @@ found:
        if (*cp == '/') {
                while (*cp == '/')
                        cp++;
        if (*cp == '/') {
                while (*cp == '/')
                        cp++;
+               irele(pdp);
                goto dirloop;
        }
        brelse(nbp);
                goto dirloop;
        }
        brelse(nbp);
+       if (lockparent)
+               u.u_pdir = pdp;
+       else
+               irele(pdp);
        return (dp);
 bad2:
        irele(pdp);
        return (dp);
 bad2:
        irele(pdp);
@@ -462,7 +516,6 @@ dirbad(ip, how)
 dirbadname(ep)
        register struct direct *ep;
 {
 dirbadname(ep)
        register struct direct *ep;
 {
-       register char *cp;
        register int i;
 
        for (i = 0; i < ep->d_namlen; i++)
        register int i;
 
        for (i = 0; i < ep->d_namlen; i++)
@@ -471,32 +524,6 @@ dirbadname(ep)
        return (ep->d_name[i]);
 }
 
        return (ep->d_name[i]);
 }
 
-/*
- * Return the next character from the
- * kernel string pointed at by dirp.
- */
-schar()
-{
-
-       return (*u.u_dirp++ & 0377);
-}
-
-/*
- * Return the next character from the
- * user string pointed at by dirp.
- */
-uchar()
-{
-       register c;
-
-       c = fubyte(u.u_dirp++);
-       if (c == -1) {
-               u.u_error = EFAULT;
-               c = 0;
-       }
-       return (c);
-}
-
 /*
  * Write a directory entry after a call to namei, using the parameters
  * which it left in the u. area.  The argument ip is the inode which
 /*
  * Write a directory entry after a call to namei, using the parameters
  * which it left in the u. area.  The argument ip is the inode which
@@ -509,9 +536,10 @@ direnter(ip)
        struct inode *ip;
 {
        register struct direct *ep, *nep;
        struct inode *ip;
 {
        register struct direct *ep, *nep;
-       struct fs *fs;
        struct buf *bp;
        struct buf *bp;
-       int loc, dsize, freespace, newentrysize;
+       int loc, freespace;
+       u_int dsize;
+       int newentrysize;
        char *dirbuf;
 
        u.u_dent.d_ino = ip->i_number;
        char *dirbuf;
 
        u.u_dent.d_ino = ip->i_number;
@@ -527,10 +555,8 @@ direnter(ip)
                if (u.u_offset&(DIRBLKSIZ-1))
                        panic("wdir: newblk");
                u.u_dent.d_reclen = DIRBLKSIZ;
                if (u.u_offset&(DIRBLKSIZ-1))
                        panic("wdir: newblk");
                u.u_dent.d_reclen = DIRBLKSIZ;
-               u.u_count = newentrysize;
-               u.u_base = (caddr_t)&u.u_dent;
-               u.u_segflg = 1;
-               writei(u.u_pdir);
+               (void) rdwri(UIO_WRITE, u.u_pdir, (caddr_t)&u.u_dent,
+                   newentrysize, u.u_offset, 1, (int *)0);
                iput(u.u_pdir);
                return;
        }
                iput(u.u_pdir);
                return;
        }
@@ -549,26 +575,18 @@ direnter(ip)
         * This should never push the size past a new multiple of
         * DIRBLKSIZE.
         */
         * This should never push the size past a new multiple of
         * DIRBLKSIZE.
         */
-       if (u.u_offset+u.u_count > u.u_pdir->i_size) {
-               if (((u.u_offset+u.u_count-1)&~(DIRBLKSIZ-1)) !=
-                   ((u.u_pdir->i_size-1)&~(DIRBLKSIZ-1))) {
-printf("wdir i_size dir %s/%d (of=%d,cnt=%d,psz=%d))\n",
-u.u_pdir->i_fs->fs_fsmnt,u.u_pdir->i_number,u.u_offset,
-u.u_count,u.u_pdir->i_size);
-                       panic("wdir: span");
-               }
+       if (u.u_offset + u.u_count > u.u_pdir->i_size)
                u.u_pdir->i_size = u.u_offset + u.u_count;
                u.u_pdir->i_size = u.u_offset + u.u_count;
-       }
 
        /*
         * Get the block containing the space for the new directory
         * entry.
         */
 
        /*
         * Get the block containing the space for the new directory
         * entry.
         */
-       bp = batoffset(u.u_pdir, u.u_offset, (char **)&dirbuf);
-       if (bp == 0)
+       bp = blkatoff(u.u_pdir, u.u_offset, (char **)&dirbuf);
+       if (bp == 0) {
+               iput(u.u_pdir);
                return;
                return;
-printf("direnter u.u_offset %d u.u_count %d, bpaddr %x, dirbuf %x\n",
-    u.u_offset, u.u_count, bp->b_un.b_addr, dirbuf);
+       }
 
        /*
         * Find space for the new entry.  In the simple case, the
 
        /*
         * Find space for the new entry.  In the simple case, the
@@ -592,10 +610,7 @@ printf("direnter u.u_offset %d u.u_count %d, bpaddr %x, dirbuf %x\n",
                dsize = DIRSIZ(nep);
                freespace += nep->d_reclen - dsize;
                loc += nep->d_reclen;
                dsize = DIRSIZ(nep);
                freespace += nep->d_reclen - dsize;
                loc += nep->d_reclen;
-/*ZZ*/if((loc&~0x1ff)!=(loc+nep->d_reclen-1&~0x1ff))
-/*ZZ*/printf("wdir: compact loc %d reclen %d (dir %s/%d)\n",loc,nep->d_reclen,
-/*ZZ*/u.u_pdir->i_fs->fs_fsmnt,u.u_pdir->i_number);
-               bcopy(nep, ep, dsize);
+               bcopy((caddr_t)nep, (caddr_t)ep, dsize);
        }
        /*
         * Update the pointer fields in the previous entry (if any),
        }
        /*
         * Update the pointer fields in the previous entry (if any),
@@ -604,68 +619,91 @@ printf("direnter u.u_offset %d u.u_count %d, bpaddr %x, dirbuf %x\n",
        if (ep->d_ino == 0) {
                if (freespace + dsize < newentrysize)
                        panic("wdir: compact1");
        if (ep->d_ino == 0) {
                if (freespace + dsize < newentrysize)
                        panic("wdir: compact1");
-/*ZZ*/if(freespace+dsize>512)panic("wdir: compact screwup");
                u.u_dent.d_reclen = freespace + dsize;
        } else {
                if (freespace < newentrysize)
                        panic("wdir: compact2");
                u.u_dent.d_reclen = freespace;
                u.u_dent.d_reclen = freespace + dsize;
        } else {
                if (freespace < newentrysize)
                        panic("wdir: compact2");
                u.u_dent.d_reclen = freespace;
-/*ZZ*/if ((((char *)ep-bp->b_un.b_addr)&0x1ff)+dsize>512) panic("wdir: reclen");
                ep->d_reclen = dsize;
                ep = (struct direct *)((char *)ep + dsize);
        }
                ep->d_reclen = dsize;
                ep = (struct direct *)((char *)ep + dsize);
        }
-/*ZZ*/if((((char*)ep-bp->b_un.b_addr)&0x1ff)+u.u_dent.d_reclen>512)panic("wdir: botch");
-       bcopy(&u.u_dent, ep, newentrysize);
+       bcopy((caddr_t)&u.u_dent, (caddr_t)ep, (u_int)newentrysize);
        bwrite(bp);
        u.u_pdir->i_flag |= IUPD|ICHG;
        iput(u.u_pdir);
 }
 
        bwrite(bp);
        u.u_pdir->i_flag |= IUPD|ICHG;
        iput(u.u_pdir);
 }
 
+/*
+ * Remove a directory entry after a call to namei, using the
+ * parameters which it left in the u. area.  The u. entry
+ * u_offset contains the offset into the directory of the
+ * entry to be eliminated.  The u_count field contains the
+ * size of the previous record in the directory.  If this
+ * is 0, the first entry is being deleted, so we need only
+ * zero the inode number to mark the entry as free.  If the
+ * entry isn't the first in the directory, we must reclaim
+ * the space of the now empty record by adding the record size
+ * to the size of the previous entry.
+ */
 dirremove()
 {
        register struct inode *dp = u.u_pdir;
 dirremove()
 {
        register struct inode *dp = u.u_pdir;
-       register struct fs *fs = dp->i_fs;
        register struct buf *bp;
        struct direct *ep;
 
        register struct buf *bp;
        struct direct *ep;
 
-printf("dirremove u.u_offset %d u.u_count %d\n", u.u_offset, u.u_count);
        if (u.u_count == 0) {
                /*
                 * First entry in block: set d_ino to zero.
                 */
        if (u.u_count == 0) {
                /*
                 * First entry in block: set d_ino to zero.
                 */
-/*ZZ*/if(u.u_offset&0x1ff)printf("missed dir compact dir %s/%d off %d file %s\n"
-/*ZZ*/,dp->i_fs->fs_fsmnt,dp->i_number,u.u_offset,u.u_dent.d_name);
-               u.u_base = (caddr_t)&u.u_dent;
-               u.u_count = DIRSIZ(&u.u_dent);
                u.u_dent.d_ino = 0;
                u.u_dent.d_ino = 0;
-               writei(dp);
+               (void) rdwri(UIO_WRITE, dp, (caddr_t)&u.u_dent,
+                   (int)DIRSIZ(&u.u_dent), u.u_offset, 1, (int *)0);
        } else {
                /*
                 * Collapse new free space into previous entry.
                 */
        } else {
                /*
                 * Collapse new free space into previous entry.
                 */
-               bp = batoffset(dp, u.u_offset - u.u_count, (char **)&ep);
+               bp = blkatoff(dp, (int)(u.u_offset - u.u_count), (char **)&ep);
                if (bp == 0)
                        return (0);
                ep->d_reclen += u.u_dent.d_reclen;
                if (bp == 0)
                        return (0);
                ep->d_reclen += u.u_dent.d_reclen;
-/*ZZ*/if((((char *)ep - bp->b_un.b_addr)&0x1ff)+u.u_dent.d_reclen > 512)
-/*ZZ*/ panic("unlink: reclen");
                bwrite(bp);
                dp->i_flag |= IUPD|ICHG;
        }
        return (1);
 }
 
                bwrite(bp);
                dp->i_flag |= IUPD|ICHG;
        }
        return (1);
 }
 
+/*
+ * 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.
+ */
+dirrewrite(dp, ip)
+       struct inode *dp, *ip;
+{
+
+       u.u_dent.d_ino = ip->i_number;
+       u.u_error = rdwri(UIO_WRITE, dp, (caddr_t)&u.u_dent,
+               (int)DIRSIZ(&u.u_dent), u.u_offset, 1, (int *)0);
+       iput(dp);
+}
+
+/*
+ * Return buffer with contents of block "offset"
+ * from the beginning of directory "ip".  If "res"
+ * is non-zero, fill it in with a pointer to the
+ * remaining space in the directory.
+ */
 struct buf *
 struct buf *
-batoffset(ip, offset, res)
+blkatoff(ip, offset, res)
        struct inode *ip;
        off_t offset;
        char **res;
 {
        register struct fs *fs = ip->i_fs;
        struct inode *ip;
        off_t offset;
        char **res;
 {
        register struct fs *fs = ip->i_fs;
-       int lbn = lblkno(fs, offset);
+       daddr_t lbn = lblkno(fs, offset);
        int base = blkoff(fs, offset);
        int bsize = blksize(fs, ip, lbn);
        int base = blkoff(fs, offset);
        int bsize = blksize(fs, ip, lbn);
-       int bn = fsbtodb(fs, bmap(ip, lbn, B_WRITE, base, bsize));
+       daddr_t bn = fsbtodb(fs, bmap(ip, lbn, B_WRITE, base, bsize));
        register struct buf *bp;
 
        if (u.u_error)
        register struct buf *bp;
 
        if (u.u_error)
@@ -677,6 +715,36 @@ batoffset(ip, offset, res)
        }
        if (res)
                *res = bp->b_un.b_addr + base;
        }
        if (res)
                *res = bp->b_un.b_addr + base;
-printf("b_addr %x res pointer %x\n", bp->b_un.b_addr, *res);
        return (bp);
 }
        return (bp);
 }
+
+/*
+ * Check if a directory is empty or not.
+ * Inode supplied must be locked.
+ */
+dirempty(ip)
+       register struct inode *ip;
+{
+       register off_t off;
+       struct direct dbuf;
+       register struct direct *dp = &dbuf;
+       int error, count;
+
+       for (off = 0; off < ip->i_size; off += dp->d_reclen) {
+               error = rdwri(UIO_READ, ip, (caddr_t)dp,
+                       sizeof (struct direct), off, 1, &count);
+               count = sizeof (struct direct) - count;
+#define        MINDIRSIZ (sizeof (struct direct) - (MAXNAMLEN + 1))
+               if (error || count < MINDIRSIZ || count < DIRSIZ(dp))
+                       return (0);
+               if (dp->d_ino == 0)
+                       continue;
+               if (dp->d_name[0] != '.')
+                       return (0);
+               if (dp->d_namlen == 1 ||
+                   (dp->d_namlen == 2 && dp->d_name[1] == '.'))
+                       continue;
+               return (0);
+       }
+       return (1);
+}