/* * ext2fs_rename_replace_dotdot: Change the target of the `..' entry of * the directory vp from fdvp to tdvp. */ static int ext2fs_rename_replace_dotdot(struct vnode *vp, struct vnode *fdvp, struct vnode *tdvp, kauth_cred_t cred) { struct ext2fs_dirtemplate dirbuf; int error; /* XXX Does it make sense to do this before the sanity checks below? */ KASSERT(0 < VTOI(fdvp)->i_e2fs_nlink); VTOI(fdvp)->i_e2fs_nlink--; VTOI(fdvp)->i_flag |= IN_CHANGE; error = ufs_bufio(UIO_READ, vp, &dirbuf, sizeof dirbuf, (off_t)0, IO_NODELOCKED, cred, NULL, NULL); if (error) return error; if (dirbuf.dotdot_namlen != 2 || dirbuf.dotdot_name[0] != '.' || dirbuf.dotdot_name[1] != '.') { ufs_dirbad(VTOI(vp), (doff_t)12, "bad `..' entry"); return 0; } if (fs2h32(dirbuf.dotdot_ino) != VTOI(fdvp)->i_number) { ufs_dirbad(VTOI(vp), (doff_t)12, "`..' does not point at parent"); return 0; } dirbuf.dotdot_ino = h2fs32(VTOI(tdvp)->i_number); /* XXX WTF? Why not check error? */ (void)ufs_bufio(UIO_WRITE, vp, &dirbuf, sizeof dirbuf, (off_t)0, (IO_NODELOCKED | IO_SYNC), cred, NULL, NULL); return 0; }
/* * 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 ext2fs_direct. * * NB: does not handle corrupted directories. */ int ext2fs_dirempty(struct inode *ip, ino_t parentino, kauth_cred_t cred) { off_t off; struct ext2fs_dirtemplate dbuf; struct ext2fs_direct *dp = (struct ext2fs_direct *)&dbuf; int error, namlen; size_t count; #define MINDIRSIZ (sizeof (struct ext2fs_dirtemplate) / 2) for (off = 0; off < ext2fs_size(ip); off += fs2h16(dp->e2d_reclen)) { error = ufs_bufio(UIO_READ, ITOV(ip), (void *)dp, MINDIRSIZ, off, IO_NODELOCKED, cred, &count, NULL); /* * Since we read MINDIRSIZ, residual must * be 0 unless we're at end of file. */ if (error || count != 0) return (0); /* avoid infinite loops */ if (dp->e2d_reclen == 0) return (0); /* skip empty entries */ if (dp->e2d_ino == 0) continue; /* accept only "." and ".." */ namlen = dp->e2d_namlen; if (namlen > 2) return (0); if (dp->e2d_name[0] != '.') return (0); /* * At this point namlen must be 1 or 2. * 1 implies ".", 2 implies ".." if second * char is also "." */ if (namlen == 1) continue; if (dp->e2d_name[1] == '.' && fs2h32(dp->e2d_ino) == parentino) continue; return (0); } return (1); }
/* * ext2fs_read_dotdot: Store in *ino_ret the inode number of the parent * of the directory vp. */ static int ext2fs_read_dotdot(struct vnode *vp, kauth_cred_t cred, ino_t *ino_ret) { struct ext2fs_dirtemplate dirbuf; int error; KASSERT(vp != NULL); KASSERT(ino_ret != NULL); KASSERT(vp->v_type == VDIR); error = ufs_bufio(UIO_READ, vp, &dirbuf, sizeof dirbuf, (off_t)0, IO_NODELOCKED, cred, NULL, NULL); if (error) return error; if (dirbuf.dotdot_namlen != 2 || dirbuf.dotdot_name[0] != '.' || dirbuf.dotdot_name[1] != '.') /* XXX Panic? Print warning? */ return ENOTDIR; *ino_ret = fs2h32(dirbuf.dotdot_ino); return 0; }