- u.u_dent.d_ino = 0;
- (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.
- */
- 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;
- 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 *
-blkatoff(ip, offset, res)
- struct inode *ip;
- off_t offset;
- char **res;
-{
- register struct fs *fs = ip->i_fs;
- daddr_t lbn = lblkno(fs, offset);
- int base = blkoff(fs, offset);
- int bsize = blksize(fs, ip, lbn);
- daddr_t bn = fsbtodb(fs, bmap(ip, lbn, B_WRITE, base, bsize));
- register struct buf *bp;
-
- if (u.u_error)
- return (0);
- bp = bread(ip->i_dev, bn, bsize);
- if (bp->b_flags & B_ERROR) {
- brelse(bp);
- return (0);
- }
- if (res)
- *res = bp->b_un.b_addr + base;
- return (bp);
-}
-
-/*
- * 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.
- */
-dirempty(ip)
- register struct inode *ip;
-{
- 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 = rdwri(UIO_READ, ip, (caddr_t)dp, MINDIRSIZ,
- off, 1, &count);
- /*
- * Since we read MINDIRSIZ, residual must
- * be 0 unless we're at end of file.
- */
- if (error || count != 0)
- return (0);
- /* skip empty entries */
- if (dp->d_ino == 0)
- continue;
- /* accept only "." and ".." */
- if (dp->d_namlen > 2)
- return (0);
- if (dp->d_name[0] != '.')
- return (0);
- /*
- * At this point d_namlen must be 1 or 2.
- * 1 implies ".", 2 implies ".." if second
- * char is also "."
- */
- if (dp->d_namlen == 1 || dp->d_name[1] == '.')
- continue;
- return (0);
- }
- return (1);
-}
-
-/*
- * Check if source directory is in the path of the target directory.
- * Target is supplied locked, source is unlocked.
- * The target is always iput() before returning.
- */
-checkpath(source, target)
- struct inode *source, *target;
-{
- struct dirtemplate dirbuf;
- register struct inode *ip;
- int error = 0;
-
- ip = target;
- if (ip->i_number == source->i_number) {
- error = EEXIST;
- goto out;
- }
- if (ip->i_number == ROOTINO)
- goto out;
-
- for (;;) {
- if ((ip->i_mode&IFMT) != IFDIR) {
- error = ENOTDIR;
- break;
- }
- error = rdwri(UIO_READ, ip, (caddr_t)&dirbuf,
- sizeof (struct dirtemplate), (off_t)0, 1, (int *)0);
- if (error != 0)
- break;
- if (dirbuf.dotdot_namlen != 2 ||
- bcmp(dirbuf.dotdot_name, "..", 3) != 0) {
- error = ENOTDIR;
- break;
- }
- if (dirbuf.dotdot_ino == source->i_number) {
- error = EINVAL;
- break;
- }
- if (dirbuf.dotdot_ino == ROOTINO)
- break;
- iput(ip);
- ip = iget(ip->i_dev, ip->i_fs, dirbuf.dotdot_ino);
- if (ip == NULL) {
- error = u.u_error;
- break;