+
+/*
+ * 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.
+ */
+int
+ufs_checkpath(source, target, cred)
+ struct inode *source, *target;
+ struct ucred *cred;
+{
+ struct dirtemplate dirbuf;
+ register struct inode *ip;
+ struct vnode *vp;
+ int error, rootino;
+
+ ip = target;
+ if (ip->i_number == source->i_number) {
+ error = EEXIST;
+ goto out;
+ }
+ rootino = ROOTINO;
+ error = 0;
+ if (ip->i_number == rootino)
+ goto out;
+
+ for (;;) {
+ if ((ip->i_mode&IFMT) != IFDIR) {
+ error = ENOTDIR;
+ break;
+ }
+ vp = ITOV(ip);
+ error = vn_rdwr(UIO_READ, vp, (caddr_t)&dirbuf,
+ sizeof (struct dirtemplate), (off_t)0, UIO_SYSSPACE,
+ IO_NODELOCKED, cred, (int *)0, (struct proc *)0);
+ if (error != 0)
+ break;
+ if (dirbuf.dotdot_namlen != 2 ||
+ dirbuf.dotdot_name[0] != '.' ||
+ dirbuf.dotdot_name[1] != '.') {
+ error = ENOTDIR;
+ break;
+ }
+ if (dirbuf.dotdot_ino == source->i_number) {
+ error = EINVAL;
+ break;
+ }
+ if (dirbuf.dotdot_ino == rootino)
+ break;
+ ufs_iput(ip);
+ if (error = VOP_VGET(vp, dirbuf.dotdot_ino, &vp))
+ break;
+ ip = VTOI(vp);
+ }
+
+out:
+ if (error == ENOTDIR)
+ printf("checkpath: .. not a directory\n");
+ if (ip != NULL)
+ ufs_iput(ip);
+ return (error);
+}