+ struct timeval *tptr;
+ } *uap = (struct a *)scp->sc_ap;
+ register struct nameidata *ndp = &scp->sc_nd;
+ register struct vnode *vp;
+ struct timeval tv[2];
+ struct vattr vattr;
+ int error;
+
+ if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
+ RETURN (error);
+ ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
+ ndp->ni_segflg = UIO_USERSPACE;
+ ndp->ni_dirp = uap->fname;
+ vattr_null(&vattr);
+ vattr.va_atime = tv[0];
+ vattr.va_mtime = tv[1];
+ if (error = namei(ndp))
+ RETURN (error);
+ vp = ndp->ni_vp;
+ if (vp->v_mount->m_flag & M_RDONLY) {
+ error = EROFS;
+ goto out;
+ }
+ error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
+out:
+ vput(vp);
+ RETURN (error);
+}
+
+/*
+ * Truncate a file given its path name.
+ */
+truncate(scp)
+ register struct syscontext *scp;
+{
+ struct a {
+ char *fname;
+ off_t length;
+ } *uap = (struct a *)scp->sc_ap;
+ register struct nameidata *ndp = &scp->sc_nd;
+ register struct vnode *vp;
+ struct vattr vattr;
+ int error;
+
+ ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
+ ndp->ni_segflg = UIO_USERSPACE;
+ ndp->ni_dirp = uap->fname;
+ vattr_null(&vattr);
+ vattr.va_size = uap->length;
+ if (error = namei(ndp))
+ RETURN (error);
+ vp = ndp->ni_vp;
+ if (vp->v_type == VDIR) {
+ error = EISDIR;
+ goto out;
+ }
+ if ((error = vn_writechk(vp)) ||
+ (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred)))
+ goto out;
+ error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
+out:
+ vput(vp);
+ RETURN (error);
+}
+
+/*
+ * Truncate a file given a file descriptor.
+ */
+ftruncate(scp)
+ register struct syscontext *scp;
+{
+ struct a {
+ int fd;
+ off_t length;
+ } *uap = (struct a *)scp->sc_ap;
+ struct vattr vattr;
+ struct vnode *vp;
+ struct file *fp;
+ int error;
+
+ if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
+ RETURN (error);
+ if ((fp->f_flag & FWRITE) == 0)
+ RETURN (EINVAL);
+ vattr_null(&vattr);
+ vattr.va_size = uap->length;
+ vp = (struct vnode *)fp->f_data;
+ VOP_LOCK(vp);
+ if (vp->v_type == VDIR) {
+ error = EISDIR;
+ goto out;
+ }
+ if (error = vn_writechk(vp))
+ goto out;
+ error = VOP_SETATTR(vp, &vattr, fp->f_cred);
+out:
+ VOP_UNLOCK(vp);
+ RETURN (error);
+}
+
+/*
+ * Synch an open file.
+ */
+fsync(scp)
+ register struct syscontext *scp;
+{
+ struct a {
+ int fd;
+ } *uap = (struct a *)scp->sc_ap;
+ struct file *fp;
+ int error;
+
+ if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
+ RETURN (error);
+ error = VOP_FSYNC((struct vnode *)fp->f_data, fp->f_flag, fp->f_cred);
+ RETURN (error);
+}
+
+/*
+ * Rename system call.
+ *
+ * Source and destination must either both be directories, or both
+ * not be directories. If target is a directory, it must be empty.
+ */
+rename(scp)
+ register struct syscontext *scp;
+{
+ struct a {
+ char *from;
+ char *to;
+ } *uap = (struct a *)scp->sc_ap;
+ register struct vnode *tvp, *fvp, *tdvp;
+ register struct nameidata *ndp = &scp->sc_nd;
+ struct nameidata tond;
+ int error;
+
+ ndp->ni_nameiop = DELETE | WANTPARENT;
+ ndp->ni_segflg = UIO_USERSPACE;
+ ndp->ni_dirp = uap->from;
+ if (error = namei(ndp))
+ RETURN (error);
+ fvp = ndp->ni_vp;
+ nddup(ndp, &tond);
+ tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
+ tond.ni_segflg = UIO_USERSPACE;
+ tond.ni_dirp = uap->to;
+ error = namei(&tond);
+ tdvp = tond.ni_dvp;
+ tvp = tond.ni_vp;
+ if (tvp != NULL) {
+ if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
+ error = EISDIR;
+ goto out;
+ } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
+ error = ENOTDIR;
+ goto out;
+ }
+ }
+ if (error) {
+ VOP_ABORTOP(ndp);
+ goto out1;
+ }
+ if (fvp->v_mount != tdvp->v_mount) {
+ error = EXDEV;
+ goto out;
+ }
+ if (fvp == tdvp || fvp == tvp)
+ error = EINVAL;
+out:
+ if (error) {
+ VOP_ABORTOP(&tond);
+ VOP_ABORTOP(ndp);