+static struct dirtemplate mastertemplate = {
+ 0, 12, 1, ".",
+ 0, DIRBLKSIZ - 12, 2, ".."
+};
+
+/*
+ * Mkdir system call
+ */
+int
+ufs_mkdir(ndp, vap, p)
+ struct nameidata *ndp;
+ struct vattr *vap;
+ struct proc *p;
+{
+ register struct inode *ip, *dp;
+ struct vnode *tvp;
+ struct vnode *dvp;
+ struct dirtemplate dirtemplate;
+ int error;
+ int dmode;
+
+#ifdef DIANOSTIC
+ if ((ndp->ni_nameiop & HASBUF) == 0)
+ panic("ufs_mkdir: no name");
+#endif
+ dvp = ndp->ni_dvp;
+ dp = VTOI(dvp);
+ if ((unsigned short)dp->i_nlink >= LINK_MAX) {
+ free(ndp->ni_pnbuf, M_NAMEI);
+ ufs_iput(dp);
+ return (EMLINK);
+ }
+ dmode = vap->va_mode&0777;
+ dmode |= IFDIR;
+ /*
+ * Must simulate part of maknode here to acquire the inode, but
+ * not have it entered in the parent directory. The entry is made
+ * later after writing "." and ".." entries.
+ */
+ if (error = VOP_VALLOC(dvp, dmode, ndp->ni_cred, &tvp)) {
+ free(ndp->ni_pnbuf, M_NAMEI);
+ ufs_iput(dp);
+ return (error);
+ }
+ ip = VTOI(tvp);
+ ip->i_uid = ndp->ni_cred->cr_uid;
+ ip->i_gid = dp->i_gid;
+#ifdef QUOTA
+ if ((error = getinoquota(ip)) ||
+ (error = chkiq(ip, 1, ndp->ni_cred, 0))) {
+ free(ndp->ni_pnbuf, M_NAMEI);
+ VOP_VFREE(tvp, ip->i_number, dmode);
+ ufs_iput(ip);
+ ufs_iput(dp);
+ return (error);
+ }
+#endif
+ ip->i_flag |= IACC|IUPD|ICHG;
+ ip->i_mode = dmode;
+ ITOV(ip)->v_type = VDIR; /* Rest init'd in iget() */
+ ip->i_nlink = 2;
+ error = VOP_UPDATE(ITOV(ip), &time, &time, 1);
+
+ /*
+ * Bump link count in parent directory
+ * to reflect work done below. Should
+ * be done before reference is created
+ * so reparation is possible if we crash.
+ */
+ dp->i_nlink++;
+ dp->i_flag |= ICHG;
+ if (error = VOP_UPDATE(ITOV(dp), &time, &time, 1))
+ goto bad;
+
+ /* Initialize directory with "." and ".." from static template. */
+ dirtemplate = mastertemplate;
+ dirtemplate.dot_ino = ip->i_number;
+ dirtemplate.dotdot_ino = dp->i_number;
+ error = vn_rdwr(UIO_WRITE, ITOV(ip), (caddr_t)&dirtemplate,
+ sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE,
+ IO_NODELOCKED|IO_SYNC, ndp->ni_cred, (int *)0, (struct proc *)0);
+ if (error) {
+ dp->i_nlink--;
+ dp->i_flag |= ICHG;
+ goto bad;
+ }
+ if (DIRBLKSIZ > VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize)
+ panic("ufs_mkdir: blksize"); /* XXX should grow with balloc() */
+ else {
+ ip->i_size = DIRBLKSIZ;
+ ip->i_flag |= ICHG;
+ }
+
+ /* Directory set up, now install it's entry in the parent directory. */
+ if (error = ufs_direnter(ip, ndp)) {
+ dp->i_nlink--;
+ dp->i_flag |= ICHG;
+ }
+bad:
+ /*
+ * No need to do an explicit VOP_TRUNCATE here, vrele will do this
+ * for us because we set the link count to 0.
+ */
+ if (error) {
+ ip->i_nlink = 0;
+ ip->i_flag |= ICHG;
+ ufs_iput(ip);
+ } else
+ ndp->ni_vp = ITOV(ip);
+ FREE(ndp->ni_pnbuf, M_NAMEI);
+ ufs_iput(dp);
+ return (error);
+}
+
+/*
+ * Rmdir system call.
+ */
+int
+ufs_rmdir(ndp, p)
+ register struct nameidata *ndp;
+ struct proc *p;
+{
+ register struct inode *ip, *dp;
+ int error;
+
+ ip = VTOI(ndp->ni_vp);
+ dp = VTOI(ndp->ni_dvp);
+ /*
+ * No rmdir "." please.
+ */
+ if (dp == ip) {
+ vrele(ndp->ni_dvp);
+ ufs_iput(ip);
+ return (EINVAL);
+ }
+ /*
+ * Verify the directory is empty (and valid).
+ * (Rmdir ".." won't be valid since
+ * ".." will contain a reference to
+ * the current directory and thus be
+ * non-empty.)
+ */
+ error = 0;
+ if (ip->i_nlink != 2 ||
+ !ufs_dirempty(ip, dp->i_number, ndp->ni_cred)) {
+ error = ENOTEMPTY;
+ goto out;
+ }
+ /*
+ * Delete reference to directory before purging
+ * inode. If we crash in between, the directory
+ * will be reattached to lost+found,
+ */
+ if (error = ufs_dirremove(ndp))
+ goto out;
+ dp->i_nlink--;
+ dp->i_flag |= ICHG;
+ cache_purge(ndp->ni_dvp);
+ ufs_iput(dp);
+ ndp->ni_dvp = NULL;
+ /*
+ * Truncate inode. The only stuff left
+ * in the directory is "." and "..". The
+ * "." reference is inconsequential since
+ * we're quashing it. The ".." reference
+ * has already been adjusted above. We've
+ * removed the "." reference and the reference
+ * in the parent directory, but there may be
+ * other hard links so decrement by 2 and
+ * worry about them later.
+ */
+ ip->i_nlink -= 2;
+ error = VOP_TRUNCATE(ndp->ni_vp, (u_long)0, IO_SYNC);
+ cache_purge(ITOV(ip));
+out:
+ if (ndp->ni_dvp)
+ ufs_iput(dp);
+ ufs_iput(ip);
+ return (error);
+}
+
+/*
+ * symlink -- make a symbolic link
+ */
+int
+ufs_symlink(ndp, vap, target, p)
+ struct nameidata *ndp;
+ struct vattr *vap;
+ char *target;
+ struct proc *p;
+{
+ struct vnode *vp;
+ int error;
+
+ if (error = ufs_makeinode(IFLNK | vap->va_mode, ndp, &vp))
+ return (error);
+ error = vn_rdwr(UIO_WRITE, vp, target, strlen(target), (off_t)0,
+ UIO_SYSSPACE, IO_NODELOCKED, ndp->ni_cred, (int *)0,
+ (struct proc *)0);
+ vput(vp);
+ return (error);
+}
+
+/*
+ * Vnode op for read and write
+ */
+int
+ufs_readdir(vp, uio, cred, eofflagp)
+ struct vnode *vp;
+ register struct uio *uio;
+ struct ucred *cred;
+ int *eofflagp;
+{
+ int count, lost, error;
+
+ count = uio->uio_resid;
+ count &= ~(DIRBLKSIZ - 1);
+ lost = uio->uio_resid - count;
+ if (count < DIRBLKSIZ || (uio->uio_offset & (DIRBLKSIZ -1)))
+ return (EINVAL);
+ uio->uio_resid = count;
+ uio->uio_iov->iov_len = count;
+ error = VOP_READ(vp, uio, 0, cred);
+ uio->uio_resid += lost;
+ if ((VTOI(vp)->i_size - uio->uio_offset) <= 0)
+ *eofflagp = 1;
+ else
+ *eofflagp = 0;
+ return (error);
+}
+
+/*
+ * Return target name of a symbolic link
+ */
+int
+ufs_readlink(vp, uiop, cred)
+ struct vnode *vp;
+ struct uio *uiop;
+ struct ucred *cred;
+{
+
+ return (VOP_READ(vp, uiop, 0, cred));
+}
+
+/*
+ * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually
+ * done. If a buffer has been saved in anticipation of a CREATE, delete it.
+ */
+/* ARGSUSED */
+int
+ufs_abortop(ndp)
+ struct nameidata *ndp;
+{
+
+ if ((ndp->ni_nameiop & (HASBUF | SAVESTART)) == HASBUF)
+ FREE(ndp->ni_pnbuf, M_NAMEI);
+ return (0);
+}
+
+/*
+ * Lock an inode.
+ */
+int
+ufs_lock(vp)
+ struct vnode *vp;
+{
+ register struct inode *ip = VTOI(vp);
+
+ ILOCK(ip);
+ return (0);
+}
+
+/*
+ * Unlock an inode.
+ */
+int
+ufs_unlock(vp)
+ struct vnode *vp;
+{
+ register struct inode *ip = VTOI(vp);
+
+ if (!(ip->i_flag & ILOCKED))
+ panic("ufs_unlock NOT LOCKED");
+ IUNLOCK(ip);
+ return (0);
+}
+
+/*
+ * Check for a locked inode.
+ */
+int
+ufs_islocked(vp)
+ struct vnode *vp;
+{
+
+ if (VTOI(vp)->i_flag & ILOCKED)
+ return (1);
+ return (0);
+}
+
+/*
+ * Calculate the logical to physical mapping if not done already,
+ * then call the device strategy routine.
+ */
+int checkoverlap = 0;
+
+int
+ufs_strategy(bp)
+ register struct buf *bp;