-/* vfs_syscalls.c 4.32 82/08/10 */
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#)vfs_syscalls.c 7.14 (Berkeley) %G%
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "syscontext.h"
+#include "kernel.h"
+#include "file.h"
+#include "stat.h"
+#include "vnode.h"
+#include "../ufs/inode.h"
+#include "mount.h"
+#include "proc.h"
+#include "uio.h"
+#include "malloc.h"
-#include "../h/param.h"
-#include "../h/systm.h"
-#include "../h/dir.h"
-#include "../h/user.h"
-#include "../h/file.h"
-#include "../h/stat.h"
-#include "../h/inode.h"
-#include "../h/fs.h"
-#include "../h/buf.h"
-#include "../h/proc.h"
-#include "../h/inline.h"
-/* no reason to inline expand these guys here */
-#undef ilock
-#undef iunlock
-#include "../h/quota.h"
-#include "../h/descrip.h"
+/*
+ * Virtual File System System Calls
+ */
-chdir()
+/*
+ * mount system call
+ */
+mount(scp)
+ register struct syscontext *scp;
{
+ register struct a {
+ int type;
+ char *dir;
+ int flags;
+ caddr_t data;
+ } *uap = (struct a *)scp->sc_ap;
+ register struct nameidata *ndp = &scp->sc_nd;
+ struct vnode *vp;
+ struct mount *mp;
+ int error;
- chdirec(&u.u_cdir);
+ /*
+ * Must be super user
+ */
+ if (error = suser(scp->sc_cred, &scp->sc_acflag))
+ RETURN (error);
+ /*
+ * Get vnode to be covered
+ */
+ ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
+ ndp->ni_segflg = UIO_USERSPACE;
+ ndp->ni_dirp = uap->dir;
+ if (error = namei(ndp))
+ RETURN (error);
+ vp = ndp->ni_vp;
+ if (vp->v_count != 1) {
+ vput(vp);
+ RETURN (EBUSY);
+ }
+ if (vp->v_type != VDIR) {
+ vput(vp);
+ RETURN (ENOTDIR);
+ }
+ if (uap->type > MOUNT_MAXTYPE ||
+ vfssw[uap->type] == (struct vfsops *)0) {
+ vput(vp);
+ RETURN (ENODEV);
+ }
+
+ /*
+ * Mount the filesystem.
+ */
+ mp = (struct mount *)malloc((u_long)sizeof(struct mount),
+ M_MOUNT, M_WAITOK);
+ mp->m_op = vfssw[uap->type];
+ mp->m_flag = 0;
+ mp->m_exroot = 0;
+ error = vfs_add(vp, mp, uap->flags);
+ if (!error)
+ error = VFS_MOUNT(mp, uap->dir, uap->data, ndp);
+ cache_purge(vp);
+ VOP_UNLOCK(vp);
+ if (!error) {
+ vfs_unlock(mp);
+ } else {
+ vfs_remove(mp);
+ free((caddr_t)mp, M_MOUNT);
+ vrele(vp);
+ }
+ RETURN (error);
}
-chroot()
+/*
+ * Unmount system call.
+ *
+ * Note: unmount takes a path to the vnode mounted on as argument,
+ * not special file (as before).
+ */
+unmount(scp)
+ register struct syscontext *scp;
{
+ struct a {
+ char *pathp;
+ int flags;
+ } *uap = (struct a *)scp->sc_ap;
+ register struct vnode *vp;
+ register struct mount *mp;
+ register struct nameidata *ndp = &scp->sc_nd;
+ struct vnode *coveredvp;
+ int error;
- if (suser())
- chdirec(&u.u_rdir);
+ /*
+ * Must be super user
+ */
+ if (error = suser(scp->sc_cred, &scp->sc_acflag))
+ RETURN (error);
+
+ ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
+ ndp->ni_segflg = UIO_USERSPACE;
+ ndp->ni_dirp = uap->pathp;
+ if (error = namei(ndp))
+ RETURN (error);
+ vp = ndp->ni_vp;
+ /*
+ * Must be the root of the filesystem
+ */
+ if ((vp->v_flag & VROOT) == 0) {
+ vput(vp);
+ RETURN (EINVAL);
+ }
+ mp = vp->v_mount;
+ vput(vp);
+ /*
+ * Do the unmount.
+ */
+ coveredvp = mp->m_vnodecovered;
+ if (error = vfs_lock(mp))
+ RETURN (error);
+
+ xumount(mp); /* remove unused sticky files from text table */
+ cache_purgevfs(mp); /* remove cache entries for this file sys */
+ VFS_SYNC(mp, MNT_WAIT);
+
+ error = VFS_UNMOUNT(mp, uap->flags);
+ if (error) {
+ vfs_unlock(mp);
+ } else {
+ vrele(coveredvp);
+ vfs_remove(mp);
+ free((caddr_t)mp, M_MOUNT);
+ }
+ RETURN (error);
}
-chdirec(ipp)
- register struct inode **ipp;
+/*
+ * Sync system call.
+ * Sync each mounted filesystem.
+ */
+sync(scp)
+ register struct syscontext *scp;
+{
+ register struct mount *mp;
+
+ mp = rootfs;
+ do {
+ if ((mp->m_flag & M_RDONLY) == 0)
+ VFS_SYNC(mp, MNT_NOWAIT);
+ mp = mp->m_next;
+ } while (mp != rootfs);
+}
+
+/*
+ * get filesystem statistics
+ */
+statfs(scp)
+ register struct syscontext *scp;
+{
+ struct a {
+ char *path;
+ struct statfs *buf;
+ } *uap = (struct a *)scp->sc_ap;
+ register struct vnode *vp;
+ register struct nameidata *ndp = &scp->sc_nd;
+ struct statfs sb;
+ int error;
+
+ ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
+ ndp->ni_segflg = UIO_USERSPACE;
+ ndp->ni_dirp = uap->path;
+ if (error = namei(ndp))
+ RETURN (error);
+ vp = ndp->ni_vp;
+ if (error = VFS_STATFS(vp->v_mount, &sb))
+ goto out;
+ error = copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb));
+out:
+ vput(vp);
+ RETURN (error);
+}
+
+fstatfs(scp)
+ register struct syscontext *scp;
+{
+ struct a {
+ int fd;
+ struct statfs *buf;
+ } *uap = (struct a *)scp->sc_ap;
+ struct file *fp;
+ struct statfs sb;
+ int error;
+
+ if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
+ RETURN (error);
+ if (error = VFS_STATFS(((struct vnode *)fp->f_data)->v_mount, &sb))
+ RETURN (error);
+ RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb)));
+}
+
+/*
+ * get statistics on all filesystems
+ */
+getfsstat(scp)
+ register struct syscontext *scp;
+{
+ struct a {
+ struct statfs *buf;
+ long bufsize;
+ } *uap = (struct a *)scp->sc_ap;
+ register struct mount *mp;
+ register struct statfs *sfsp;
+ long count, maxcount, error;
+
+ maxcount = uap->bufsize / sizeof(struct statfs);
+ sfsp = uap->buf;
+ mp = rootfs;
+ count = 0;
+ do {
+ count++;
+ if (sfsp && count <= maxcount) {
+ if (error = VFS_STATFS(mp, sfsp))
+ RETURN (error);
+ sfsp++;
+ }
+ mp = mp->m_prev;
+ } while (mp != rootfs);
+ if (sfsp && count > maxcount)
+ scp->sc_retval1 = maxcount;
+ else
+ scp->sc_retval1 = count;
+ RETURN (0);
+}
+
+/*
+ * Change current working directory to a given file descriptor.
+ */
+fchdir(scp)
+ register struct syscontext *scp;
+{
+ struct a {
+ int fd;
+ } *uap = (struct a *)scp->sc_ap;
+ register struct vnode *vp;
+ struct file *fp;
+ int error;
+
+ if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
+ RETURN (error);
+ vp = (struct vnode *)fp->f_data;
+ VOP_LOCK(vp);
+ if (vp->v_type != VDIR)
+ error = ENOTDIR;
+ else
+ error = VOP_ACCESS(vp, VEXEC, scp->sc_cred);
+ VOP_UNLOCK(vp);
+ vrele(scp->sc_cdir);
+ scp->sc_cdir = vp;
+ RETURN (error);
+}
+
+/*
+ * Change current working directory (``.'').
+ */
+chdir(scp)
+ register struct syscontext *scp;
{
- register struct inode *ip;
struct a {
char *fname;
- };
-
- ip = namei(uchar, 0, 1);
- if(ip == NULL)
- return;
- if((ip->i_mode&IFMT) != IFDIR) {
- u.u_error = ENOTDIR;
- goto bad;
- }
- if(access(ip, IEXEC))
- goto bad;
- iunlock(ip);
- if (*ipp)
- irele(*ipp);
- *ipp = ip;
- return;
+ } *uap = (struct a *)scp->sc_ap;
+ register struct nameidata *ndp = &scp->sc_nd;
+ int error;
+
+ ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
+ ndp->ni_segflg = UIO_USERSPACE;
+ ndp->ni_dirp = uap->fname;
+ if (error = chdirec(ndp))
+ RETURN (error);
+ vrele(scp->sc_cdir);
+ scp->sc_cdir = ndp->ni_vp;
+ RETURN (0);
+}
-bad:
- iput(ip);
+/*
+ * Change notion of root (``/'') directory.
+ */
+chroot(scp)
+ register struct syscontext *scp;
+{
+ struct a {
+ char *fname;
+ } *uap = (struct a *)scp->sc_ap;
+ register struct nameidata *ndp = &scp->sc_nd;
+ int error;
+
+ if (error = suser(scp->sc_cred, &scp->sc_acflag))
+ RETURN (error);
+ ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
+ ndp->ni_segflg = UIO_USERSPACE;
+ ndp->ni_dirp = uap->fname;
+ if (error = chdirec(ndp))
+ RETURN (error);
+ vrele(scp->sc_rdir);
+ scp->sc_rdir = ndp->ni_vp;
+ RETURN (0);
+}
+
+/*
+ * Common routine for chroot and chdir.
+ */
+chdirec(ndp)
+ register struct nameidata *ndp;
+{
+ struct vnode *vp;
+ int error;
+
+ if (error = namei(ndp))
+ return (error);
+ vp = ndp->ni_vp;
+ if (vp->v_type != VDIR)
+ error = ENOTDIR;
+ else
+ error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred);
+ VOP_UNLOCK(vp);
+ if (error)
+ vrele(vp);
+ return (error);
}
/*
* Open system call.
*/
-open()
+open(scp)
+ register struct syscontext *scp;
{
- register struct inode *ip;
- register struct a {
+ struct a {
char *fname;
- int flags;
int mode;
- } *uap;
- int checkpermissions = 1;
-
- uap = (struct a *)u.u_ap;
- if (uap->flags&FCREATE) {
- ip = namei(uchar, 1, 1);
- if (ip == NULL) {
- if (u.u_error)
- return;
- ip = maknode(uap->mode&07777&(~ISVTX));
- checkpermissions = 0;
- uap->flags &= ~FTRUNCATE;
- }
- } else
- ip = namei(uchar, 0, 1);
- if (ip == NULL)
- return;
- open1(ip, ++uap->flags, checkpermissions);
+ int crtmode;
+ } *uap = (struct a *) scp->sc_ap;
+ struct nameidata *ndp = &scp->sc_nd;
+
+ ndp->ni_segflg = UIO_USERSPACE;
+ ndp->ni_dirp = uap->fname;
+ RETURN (copen(scp, uap->mode-FOPEN, uap->crtmode &~ scp->sc_cmask, ndp,
+ &scp->sc_retval1));
}
-#ifndef NOCOMPAT
/*
* Creat system call.
*/
-ocreat()
+creat(scp)
+ register struct syscontext *scp;
{
- register struct inode *ip;
- register struct a {
+ struct a {
char *fname;
int fmode;
- } *uap;
+ } *uap = (struct a *)scp->sc_ap;
+ struct nameidata *ndp = &scp->sc_nd;
- uap = (struct a *)u.u_ap;
- ip = namei(uchar, 1, 1);
- if (ip == NULL) {
- if (u.u_error)
- return;
- ip = maknode(uap->fmode&07777&(~ISVTX));
- if (ip == NULL)
- return;
- open1(ip, FWRITE, 0);
- } else
- open1(ip, FWRITE|FTRUNCATE, 0);
+ ndp->ni_segflg = UIO_USERSPACE;
+ ndp->ni_dirp = uap->fname;
+ RETURN (copen(scp, FWRITE|FCREAT|FTRUNC, uap->fmode &~ scp->sc_cmask,
+ ndp, &scp->sc_retval1));
}
-#endif
/*
* Common code for open and creat.
- * Check permissions (if we haven't done so already),
- * allocate an open file structure, and call
- * the device open routine, if any.
+ * Check permissions, allocate an open file structure,
+ * and call the device open routine if any.
*/
-open1(ip, mode, checkpermissions)
- register struct inode *ip;
- register mode;
+copen(scp, fmode, cmode, ndp, resultfd)
+ register struct syscontext *scp;
+ int fmode, cmode;
+ struct nameidata *ndp;
+ int *resultfd;
{
register struct file *fp;
- int i, flags;
-
- if (checkpermissions) {
- if (mode&FREAD)
- if (access(ip, IREAD))
- goto bad;
- if (mode&FWRITE) {
- if (access(ip, IWRITE))
- goto bad;
- if ((ip->i_mode&IFMT) == IFDIR) {
- u.u_error = EISDIR;
- goto bad;
- }
- }
+ struct file *nfp;
+ int indx, error;
+ extern struct fileops vnops;
+
+ if (error = falloc(&nfp, &indx))
+ return (error);
+ fp = nfp;
+ scp->sc_retval1 = indx; /* XXX for fdopen() */
+ if (error = vn_open(ndp, fmode, (cmode & 07777) &~ ISVTX)) {
+ scp->sc_ofile[indx] = NULL;
+ crfree(fp->f_cred);
+ fp->f_count--;
+ return (error);
}
-
- /*
- * Check locking on inode. Release "inode lock"
- * while doing so in case we block inside flocki.
- */
- flags = 0;
- if (mode&(FRDLOCK|FWRLOCK)) {
- iunlock(ip);
- flags = flocki(ip, 0, mode);
- ilock(ip);
- if (u.u_error)
- goto bad;
- }
- if (mode&FTRUNCATE)
- itrunc(ip, 0);
- iunlock(ip);
- if ((fp = falloc()) == NULL)
- goto out;
- fp->f_flag = mode & FMODES;
- fp->f_type = DTYPE_FILE;
- i = u.u_r.r_val1;
- fp->f_inode = ip;
- openi(ip, mode);
- if (u.u_error == 0) {
- u.u_pofile[i] = flags;
- return;
- }
- u.u_ofile[i] = NULL;
- fp->f_count--;
-out:
- irele(ip);
- return;
-bad:
- iput(ip);
+ fp->f_flag = fmode & FMASK;
+ fp->f_type = DTYPE_VNODE;
+ fp->f_ops = &vnops;
+ fp->f_data = (caddr_t)ndp->ni_vp;
+ if (resultfd)
+ *resultfd = indx;
+ return (0);
}
/*
* Mknod system call
*/
-mknod()
+mknod(scp)
+ register struct syscontext *scp;
{
- register struct inode *ip;
register struct a {
char *fname;
int fmode;
int dev;
- } *uap;
-
- uap = (struct a *)u.u_ap;
- if (suser()) {
- ip = namei(uchar, 1, 0);
- if (ip != NULL) {
- u.u_error = EEXIST;
- goto out;
- }
+ } *uap = (struct a *)scp->sc_ap;
+ register struct nameidata *ndp = &scp->sc_nd;
+ register struct vnode *vp;
+ struct vattr vattr;
+ int error;
+
+ if (error = suser(scp->sc_cred, &scp->sc_acflag))
+ RETURN (error);
+ ndp->ni_nameiop = CREATE | LOCKPARENT;
+ ndp->ni_segflg = UIO_USERSPACE;
+ ndp->ni_dirp = uap->fname;
+ if (error = namei(ndp))
+ RETURN (error);
+ vp = ndp->ni_vp;
+ if (vp != NULL) {
+ error = EEXIST;
+ goto out;
}
- if (u.u_error)
- return;
- ip = maknode(uap->fmode);
- if (ip == NULL)
- return;
- if (uap->dev) {
- /*
- * Want to be able to use this to make badblock
- * inodes, so don't truncate the dev number.
- */
- ip->i_rdev = uap->dev;
- ip->i_flag |= IACC|IUPD|ICHG;
+ vattr_null(&vattr);
+ switch (uap->fmode & IFMT) {
+
+ case IFMT: /* used by badsect to flag bad sectors */
+ vattr.va_type = VBAD;
+ break;
+ case IFCHR:
+ vattr.va_type = VCHR;
+ break;
+ case IFBLK:
+ vattr.va_type = VBLK;
+ break;
+ default:
+ error = EINVAL;
+ goto out;
}
-
+ vattr.va_mode = (uap->fmode & 07777) &~ scp->sc_cmask;
+ vattr.va_rdev = uap->dev;
out:
- iput(ip);
+ if (error)
+ VOP_ABORTOP(ndp);
+ else
+ error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred);
+ RETURN (error);
}
/*
* link system call
*/
-link()
+link(scp)
+ register struct syscontext *scp;
{
- register struct inode *ip, *xp;
register struct a {
char *target;
char *linkname;
- } *uap;
-
- uap = (struct a *)u.u_ap;
- ip = namei(uchar, 0, 1); /* well, this routine is doomed anyhow */
- if (ip == NULL)
- return;
- if ((ip->i_mode&IFMT)==IFDIR && !suser()) {
- iput(ip);
- return;
- }
- ip->i_nlink++;
- ip->i_flag |= ICHG;
- iupdat(ip, &time, &time, 1);
- iunlock(ip);
- u.u_dirp = (caddr_t)uap->linkname;
- xp = namei(uchar, 1, 0);
+ } *uap = (struct a *)scp->sc_ap;
+ register struct nameidata *ndp = &scp->sc_nd;
+ register struct vnode *vp, *xp;
+ int error;
+
+ ndp->ni_nameiop = LOOKUP | FOLLOW;
+ ndp->ni_segflg = UIO_USERSPACE;
+ ndp->ni_dirp = uap->target;
+ if (error = namei(ndp))
+ RETURN (error);
+ vp = ndp->ni_vp;
+ if (vp->v_type == VDIR &&
+ (error = suser(scp->sc_cred, &scp->sc_acflag)))
+ goto out1;
+ ndp->ni_nameiop = CREATE | LOCKPARENT;
+ ndp->ni_dirp = (caddr_t)uap->linkname;
+ if (error = namei(ndp))
+ goto out1;
+ xp = ndp->ni_vp;
if (xp != NULL) {
- u.u_error = EEXIST;
- iput(xp);
- goto out;
- }
- if (u.u_error)
- goto out;
- if (u.u_pdir->i_dev != ip->i_dev) {
- iput(u.u_pdir);
- u.u_error = EXDEV;
+ error = EEXIST;
goto out;
}
- direnter(ip);
+ xp = ndp->ni_dvp;
+ if (vp->v_mount != xp->v_mount)
+ error = EXDEV;
out:
- if (u.u_error) {
- ip->i_nlink--;
- ip->i_flag |= ICHG;
- }
+ if (error)
+ VOP_ABORTOP(ndp);
+ else
+ error = VOP_LINK(vp, ndp);
out1:
- irele(ip);
+ vrele(vp);
+ RETURN (error);
}
/*
* symlink -- make a symbolic link
*/
-symlink()
+symlink(scp)
+ register struct syscontext *scp;
{
- register struct a {
+ struct a {
char *target;
char *linkname;
- } *uap;
- register struct inode *ip;
- register char *tp;
- register c, nc;
-
- uap = (struct a *)u.u_ap;
- tp = uap->target;
- nc = 0;
- while (c = fubyte(tp)) {
- if (c < 0) {
- u.u_error = EFAULT;
- return;
- }
- tp++;
- nc++;
- }
- u.u_dirp = uap->linkname;
- ip = namei(uchar, 1, 0);
- if (ip) {
- iput(ip);
- u.u_error = EEXIST;
- return;
+ } *uap = (struct a *)scp->sc_ap;
+ register struct nameidata *ndp = &scp->sc_nd;
+ register struct vnode *vp;
+ struct vattr vattr;
+ char *target;
+ int error;
+
+ ndp->ni_segflg = UIO_USERSPACE;
+ ndp->ni_dirp = uap->linkname;
+ MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
+ if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
+ goto out1;
+ ndp->ni_nameiop = CREATE | LOCKPARENT;
+ if (error = namei(ndp))
+ goto out1;
+ vp = ndp->ni_vp;
+ if (vp) {
+ error = EEXIST;
+ goto out;
}
- if (u.u_error)
- return;
- ip = maknode(IFLNK | 0777);
- if (ip == NULL)
- return;
- u.u_base = uap->target;
- u.u_count = nc;
- u.u_offset = 0;
- u.u_segflg = 0;
- writei(ip);
- iput(ip);
+ vp = ndp->ni_dvp;
+ vattr_null(&vattr);
+ vattr.va_mode = 0777 &~ scp->sc_cmask;
+out:
+ if (error)
+ VOP_ABORTOP(ndp);
+ else
+ error = VOP_SYMLINK(ndp, &vattr, target);
+out1:
+ FREE(target, M_NAMEI);
+ RETURN (error);
}
/*
* Hard to avoid races here, especially
* in unlinking directories.
*/
-unlink()
+unlink(scp)
+ register struct syscontext *scp;
{
- register struct inode *ip, *pp;
struct a {
char *fname;
- };
- struct fs *fs;
- struct buf *bp;
- int lbn, bn, base;
- int unlinkingdot = 0;
-
- pp = namei(uchar, 2, 0);
- if (pp == NULL)
- return;
-
- /*
- * Check for unlink(".")
- * to avoid hanging on the iget
- */
- if (pp->i_number == u.u_dent.d_ino) {
- ip = pp;
- ip->i_count++;
- unlinkingdot++;
- } else
- ip = iget(pp->i_dev, pp->i_fs, u.u_dent.d_ino);
- if(ip == NULL)
- goto out1;
- if((ip->i_mode&IFMT)==IFDIR && !suser())
+ } *uap = (struct a *)scp->sc_ap;
+ register struct nameidata *ndp = &scp->sc_nd;
+ register struct vnode *vp;
+ int error;
+
+ ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
+ ndp->ni_segflg = UIO_USERSPACE;
+ ndp->ni_dirp = uap->fname;
+ if (error = namei(ndp))
+ RETURN (error);
+ vp = ndp->ni_vp;
+ if (vp->v_type == VDIR &&
+ (error = suser(scp->sc_cred, &scp->sc_acflag)))
goto out;
/*
* Don't unlink a mounted file.
*/
- if (ip->i_dev != pp->i_dev) {
- u.u_error = EBUSY;
+ if (vp->v_flag & VROOT) {
+ error = EBUSY;
goto out;
}
- if (ip->i_flag&ITEXT)
- xrele(ip); /* try once to free text */
- if (dirremove()) {
- ip->i_nlink--;
- ip->i_flag |= ICHG;
- }
+ if (vp->v_flag & VTEXT)
+ xrele(vp); /* try once to free text */
out:
- if (unlinkingdot)
- irele(ip);
+ if (error)
+ VOP_ABORTOP(ndp);
else
- iput(ip);
-out1:
- iput(pp);
+ error = VOP_REMOVE(ndp);
+ RETURN (error);
}
/*
* Seek system call
*/
-seek()
+lseek(scp)
+ register struct syscontext *scp;
{
register struct file *fp;
register struct a {
- int fd;
+ int fdes;
off_t off;
int sbase;
- } *uap;
-
- uap = (struct a *)u.u_ap;
- fp = getf(uap->fd);
- if (fp == NULL)
- return;
- if (fp->f_type == DTYPE_SOCKET) {
- u.u_error = ESPIPE;
- return;
+ } *uap = (struct a *)scp->sc_ap;
+ struct vattr vattr;
+ int error;
+
+ if ((unsigned)uap->fdes >= NOFILE ||
+ (fp = scp->sc_ofile[uap->fdes]) == NULL)
+ RETURN (EBADF);
+ if (fp->f_type != DTYPE_VNODE)
+ RETURN (ESPIPE);
+ switch (uap->sbase) {
+
+ case L_INCR:
+ fp->f_offset += uap->off;
+ break;
+
+ case L_XTND:
+ if (error = VOP_GETATTR((struct vnode *)fp->f_data,
+ &vattr, scp->sc_cred))
+ RETURN (error);
+ fp->f_offset = uap->off + vattr.va_size;
+ break;
+
+ case L_SET:
+ fp->f_offset = uap->off;
+ break;
+
+ default:
+ RETURN (EINVAL);
}
- if (uap->sbase == FSEEK_RELATIVE)
- uap->off += fp->f_offset;
- else if (uap->sbase == FSEEK_EOF)
- uap->off += fp->f_inode->i_size;
- fp->f_offset = uap->off;
- u.u_r.r_off = uap->off;
+ scp->sc_offset = fp->f_offset;
+ RETURN (0);
}
/*
* Access system call
*/
-saccess()
+saccess(scp)
+ register struct syscontext *scp;
{
- register svuid, svgid;
- register struct inode *ip;
register struct a {
char *fname;
int fmode;
- } *uap;
-
- uap = (struct a *)u.u_ap;
- svuid = u.u_uid;
- svgid = u.u_gid;
- u.u_uid = u.u_ruid;
- u.u_gid = u.u_rgid;
- ip = namei(uchar, 0, 1);
- if (ip != NULL) {
- if (uap->fmode&FACCESS_READ && access(ip, IREAD))
- goto done;
- if (uap->fmode&FACCESS_WRITE && access(ip, IWRITE))
- goto done;
- if (uap->fmode&FACCESS_EXECUTE && access(ip, IEXEC))
- goto done;
-done:
- iput(ip);
+ } *uap = (struct a *)scp->sc_ap;
+ register struct nameidata *ndp = &scp->sc_nd;
+ register struct vnode *vp;
+ int error, mode, svuid, svgid;
+
+ svuid = scp->sc_uid;
+ svgid = scp->sc_gid;
+ scp->sc_uid = scp->sc_ruid;
+ scp->sc_gid = scp->sc_rgid;
+ ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
+ ndp->ni_segflg = UIO_USERSPACE;
+ ndp->ni_dirp = uap->fname;
+ if (error = namei(ndp))
+ goto out1;
+ vp = ndp->ni_vp;
+ /*
+ * fmode == 0 means only check for exist
+ */
+ if (uap->fmode) {
+ mode = 0;
+ if (uap->fmode & R_OK)
+ mode |= VREAD;
+ if (uap->fmode & W_OK)
+ mode |= VWRITE;
+ if (uap->fmode & X_OK)
+ mode |= VEXEC;
+ if ((error = vn_writechk(vp)) == 0)
+ error = VOP_ACCESS(vp, mode, ndp->ni_cred);
}
- u.u_uid = svuid;
- u.u_gid = svgid;
-}
-
-/*
- * the fstat system call.
- */
-fstat()
-{
- register struct file *fp;
- register struct a {
- int fd;
- struct stat *sb;
- } *uap;
-
- uap = (struct a *)u.u_ap;
- fp = getf(uap->fd);
- if (fp == NULL)
- return;
- if (fp->f_type == DTYPE_SOCKET)
- u.u_error = sostat(fp->f_socket, uap->sb);
- else
- stat1(fp->f_inode, uap->sb);
+ vput(vp);
+out1:
+ scp->sc_uid = svuid;
+ scp->sc_gid = svgid;
+ RETURN (error);
}
/*
* Stat system call. This version follows links.
*/
-stat()
+stat(scp)
+ struct syscontext *scp;
{
- register struct inode *ip;
- register struct a {
- char *fname;
- struct stat *sb;
- } *uap;
- uap = (struct a *)u.u_ap;
- ip = namei(uchar, 0, 1);
- if (ip == NULL)
- return;
- stat1(ip, uap->sb);
- iput(ip);
+ stat1(scp, FOLLOW);
}
/*
* Lstat system call. This version does not follow links.
*/
-lstat()
+lstat(scp)
+ struct syscontext *scp;
{
- register struct inode *ip;
- register struct a {
- char *fname;
- struct stat *sb;
- } *uap;
- uap = (struct a *)u.u_ap;
- ip = namei(uchar, 0, 0);
- if (ip == NULL)
- return;
- stat1(ip, uap->sb);
- iput(ip);
+ stat1(scp, NOFOLLOW);
}
-/*
- * The basic routine for fstat and stat:
- * get the inode and pass appropriate parts back.
- */
-stat1(ip, ub)
- register struct inode *ip;
- struct stat *ub;
+stat1(scp, follow)
+ register struct syscontext *scp;
+ int follow;
{
- struct stat ds;
-
- IUPDAT(ip, &time, &time, 0);
- /*
- * Copy from inode table
- */
- ds.st_dev = ip->i_dev;
- ds.st_ino = ip->i_number;
- ds.st_mode = ip->i_mode;
- ds.st_nlink = ip->i_nlink;
- ds.st_uid = ip->i_uid;
- ds.st_gid = ip->i_gid;
- ds.st_rdev = (dev_t)ip->i_rdev;
- ds.st_size = ip->i_size;
- ds.st_atime = ip->i_atime;
- ds.st_mtime = ip->i_mtime;
- ds.st_ctime = ip->i_ctime;
- /* this doesn't belong here */
- if ((ip->i_mode&IFMT) == IFBLK)
- ds.st_blksize = BLKDEV_IOSIZE;
- else if ((ip->i_mode&IFMT) == IFCHR)
- ds.st_blksize = MAXBSIZE;
- else
- ds.st_blksize = ip->i_fs->fs_bsize;
- if (copyout((caddr_t)&ds, (caddr_t)ub, sizeof(ds)) < 0)
- u.u_error = EFAULT;
+ register struct a {
+ char *fname;
+ struct stat *ub;
+ } *uap = (struct a *)scp->sc_ap;
+ register struct nameidata *ndp = &scp->sc_nd;
+ struct stat sb;
+ int error;
+
+ ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow;
+ ndp->ni_segflg = UIO_USERSPACE;
+ ndp->ni_dirp = uap->fname;
+ if (error = namei(ndp))
+ RETURN (error);
+ error = vn_stat(ndp->ni_vp, &sb);
+ vput(ndp->ni_vp);
+ if (error)
+ RETURN (error);
+ error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
+ RETURN (error);
}
/*
* Return target name of a symbolic link
*/
-readlink()
+readlink(scp)
+ register struct syscontext *scp;
{
- register struct inode *ip;
register struct a {
char *name;
char *buf;
int count;
- } *uap;
+ } *uap = (struct a *)scp->sc_ap;
+ register struct nameidata *ndp = &scp->sc_nd;
+ register struct vnode *vp;
+ struct iovec aiov;
+ struct uio auio;
+ int error;
+
+ ndp->ni_nameiop = LOOKUP | LOCKLEAF;
+ ndp->ni_segflg = UIO_USERSPACE;
+ ndp->ni_dirp = uap->name;
+ if (error = namei(ndp))
+ RETURN (error);
+ vp = ndp->ni_vp;
+ if (vp->v_type != VLNK) {
+ error = EINVAL;
+ goto out;
+ }
+ aiov.iov_base = uap->buf;
+ aiov.iov_len = uap->count;
+ auio.uio_iov = &aiov;
+ auio.uio_iovcnt = 1;
+ auio.uio_offset = 0;
+ auio.uio_rw = UIO_READ;
+ auio.uio_segflg = UIO_USERSPACE;
+ auio.uio_resid = uap->count;
+ error = VOP_READLINK(vp, &auio, ndp->ni_cred);
+out:
+ vput(vp);
+ scp->sc_retval1 = uap->count - auio.uio_resid;
+ RETURN (error);
+}
- ip = namei(uchar, 0, 0);
- if (ip == NULL)
- return;
- if ((ip->i_mode&IFMT) != IFLNK) {
- u.u_error = ENXIO;
+/*
+ * Change flags of a file given path name.
+ */
+chflags(scp)
+ register struct syscontext *scp;
+{
+ struct a {
+ char *fname;
+ int flags;
+ } *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_flags = uap->flags;
+ if (error = namei(ndp))
+ RETURN (error);
+ vp = ndp->ni_vp;
+ if (vp->v_mount->m_flag & M_RDONLY) {
+ error = EROFS;
goto out;
}
- uap = (struct a *)u.u_ap;
- u.u_offset = 0;
- u.u_base = uap->buf;
- u.u_count = uap->count;
- u.u_segflg = 0;
- readi(ip);
+ error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
out:
- iput(ip);
- u.u_r.r_val1 = uap->count - u.u_count;
+ vput(vp);
+ RETURN (error);
}
-chmod()
+/*
+ * Change flags of a file given a file descriptor.
+ */
+fchflags(scp)
+ register struct syscontext *scp;
+{
+ struct a {
+ int fd;
+ int flags;
+ } *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);
+ vattr_null(&vattr);
+ vattr.va_flags = uap->flags;
+ vp = (struct vnode *)fp->f_data;
+ VOP_LOCK(vp);
+ if (vp->v_mount->m_flag & M_RDONLY) {
+ error = EROFS;
+ goto out;
+ }
+ error = VOP_SETATTR(vp, &vattr, fp->f_cred);
+out:
+ VOP_UNLOCK(vp);
+ RETURN (error);
+}
+
+/*
+ * Change mode of a file given path name.
+ */
+chmod(scp)
+ register struct syscontext *scp;
{
- struct inode *ip;
struct a {
char *fname;
int fmode;
- } *uap;
-
- uap = (struct a *)u.u_ap;
- if ((ip = owner(1)) == NULL)
- return;
- chmod1(ip, uap->fmode);
+ } *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_mode = uap->fmode & 07777;
+ 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);
}
-fchmod()
+/*
+ * Change mode of a file given a file descriptor.
+ */
+fchmod(scp)
+ register struct syscontext *scp;
{
struct a {
int fd;
int fmode;
- } *uap;
- register struct inode *ip;
- register struct file *fp;
-
- uap = (struct a *)u.u_ap;
- fp = getf(uap->fd);
- if (fp == NULL)
- return;
- if (fp->f_type == DTYPE_SOCKET) {
- u.u_error = EINVAL;
- return;
- }
- ip = fp->f_inode;
- ilock(ip);
- if (u.u_uid != ip->i_uid && !suser()) {
- iunlock(ip);
- return;
- }
- chmod1(ip, uap->fmode);
-}
-
-chmod1(ip, mode)
- register struct inode *ip;
- register int mode;
-{
- ip->i_mode &= ~07777;
- if (u.u_uid) {
- mode &= ~ISVTX;
- if (ip->i_gid >= NGRPS ||
- (u.u_grps[ip->i_gid/(sizeof(int)*8)] &
- (1 << ip->i_gid%(sizeof(int)*8))) == 0)
- mode &= ~ISGID;
-#ifdef MUSH
- if (u.u_quota->q_syflags & QF_UMASK && u.u_uid != 0 &&
- (ip->i_mode & IFMT) != IFCHR)
- mode &= ~u.u_cmask;
-#endif
+ } *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);
+ vattr_null(&vattr);
+ vattr.va_mode = uap->fmode & 07777;
+ vp = (struct vnode *)fp->f_data;
+ VOP_LOCK(vp);
+ if (vp->v_mount->m_flag & M_RDONLY) {
+ error = EROFS;
+ goto out;
}
- ip->i_mode |= mode&07777;
- ip->i_flag |= ICHG;
- if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0)
- xrele(ip);
- iput(ip);
+ error = VOP_SETATTR(vp, &vattr, fp->f_cred);
+out:
+ VOP_UNLOCK(vp);
+ RETURN (error);
}
-chown()
+/*
+ * Set ownership given a path name.
+ */
+chown(scp)
+ register struct syscontext *scp;
{
- struct inode *ip;
struct a {
char *fname;
int uid;
int gid;
- } *uap;
-
- uap = (struct a *)u.u_ap;
- if (!suser() || (ip = owner(0)) == NULL)
- return;
- chown1(ip, uap->uid, uap->gid);
+ } *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 | NOFOLLOW | LOCKLEAF;
+ ndp->ni_segflg = UIO_USERSPACE;
+ ndp->ni_dirp = uap->fname;
+ vattr_null(&vattr);
+ vattr.va_uid = uap->uid;
+ vattr.va_gid = uap->gid;
+ 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);
}
-fchown()
+/*
+ * Set ownership given a file descriptor.
+ */
+fchown(scp)
+ register struct syscontext *scp;
{
struct a {
int fd;
int uid;
int gid;
- } *uap;
- register struct inode *ip;
- register struct file *fp;
-
- uap = (struct a *)u.u_ap;
- fp = getf(uap->fd);
- if (fp == NULL)
- return;
- if (fp->f_type == DTYPE_SOCKET) {
- u.u_error = EINVAL;
- return;
+ } *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);
+ vattr_null(&vattr);
+ vattr.va_uid = uap->uid;
+ vattr.va_gid = uap->gid;
+ vp = (struct vnode *)fp->f_data;
+ VOP_LOCK(vp);
+ if (vp->v_mount->m_flag & M_RDONLY) {
+ error = EROFS;
+ goto out;
}
- ip = fp->f_inode;
- ilock(ip);
- if (!suser()) {
- iunlock(ip);
- return;
+ error = VOP_SETATTR(vp, &vattr, fp->f_cred);
+out:
+ VOP_UNLOCK(vp);
+ RETURN (error);
+}
+
+utimes(scp)
+ register struct syscontext *scp;
+{
+ register struct a {
+ char *fname;
+ 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;
}
- chown1(ip, uap->uid, uap->gid);
+ error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
+out:
+ vput(vp);
+ RETURN (error);
}
/*
- * Perform chown operation on inode ip;
- * inode must be locked prior to call.
+ * Truncate a file given its path name.
*/
-chown1(ip, uid, gid)
- register struct inode *ip;
- int uid, gid;
+truncate(scp)
+ register struct syscontext *scp;
{
-#ifdef QUOTA
- register long change;
-
- /*
- * This doesn't allow for holes in files (which hopefully don't
- * happen often in files that we chown), and is not accurate anyway
- * (eg: it totally ignores 3 level indir blk files - but hopefully
- * noone who can make a file that big will have a quota)
- */
- if (ip->i_uid == uid)
- change = 0;
- else {
- register struct fs *fs = ip->i_fs;
-
- if (ip->i_size > (change = NDADDR * fs->fs_bsize)) {
- register off_t size;
-
- size = blkroundup(fs, ip->i_size) - change;
- change += size;
- change += fs->fs_bsize;
- /* this assumes NIADDR <= 2 */
- if (size > NINDIR(fs) * fs->fs_bsize)
- change += fs->fs_bsize;
- } else
- change = fragroundup(fs, ip->i_size);
- change /= DEV_BSIZE;
+ 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;
}
- chkdq(ip, -change, 1);
- chkiq(ip->i_dev, ip, ip->i_uid, 1);
- dqrele(ip->i_dquot);
-#endif
- /*
- * keep uid/gid's in sane range -- no err,
- * so chown(file, uid, -1) will do something useful
- */
- if (uid >= 0 && uid <= 32767) /* should have a constant */
- ip->i_uid = uid;
- if (gid >= 0 && gid <= 32767) /* same here */
- ip->i_gid = gid;
- ip->i_flag |= ICHG;
- if (u.u_ruid != 0)
- ip->i_mode &= ~(ISUID|ISGID);
-#ifdef QUOTA
- ip->i_dquot = inoquota(ip);
- chkdq(ip, change, 1);
- chkiq(ip->i_dev, NULL, uid, 1);
-#endif
- iput(ip);
+ 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);
}
/*
- * Set IUPD and IACC times on file.
- * Can't set ICHG.
+ * Truncate a file given a file descriptor.
*/
-utime()
+ftruncate(scp)
+ register struct syscontext *scp;
{
- register struct a {
- char *fname;
- time_t *tptr;
- } *uap;
- register struct inode *ip;
- time_t tv[2];
-
- uap = (struct a *)u.u_ap;
- if ((ip = owner(1)) == NULL)
- return;
- if (copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof(tv))) {
- u.u_error = EFAULT;
- } else {
- ip->i_flag |= IACC|IUPD|ICHG;
- iupdat(ip, &tv[0], &tv[1], 0);
+ 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;
}
- iput(ip);
+ if (error = vn_writechk(vp))
+ goto out;
+ error = VOP_SETATTR(vp, &vattr, fp->f_cred);
+out:
+ VOP_UNLOCK(vp);
+ RETURN (error);
}
-sync()
+/*
+ * 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;
- update(0);
+ 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);
}
-flock()
+/*
+ * 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 {
- int fd;
- int how;
- } *uap;
- register struct file *fp;
- register int cmd, flags;
-
- uap = (struct a *)u.u_ap;
- fp = getf(uap->fd);
- if (fp == NULL)
- return;
- if (fp->f_type == DTYPE_SOCKET) { /* XXX */
- u.u_error = EINVAL;
- return;
- }
- cmd = uap->how;
- flags = u.u_pofile[uap->fd] & (RDLOCK|WRLOCK);
- if (cmd&FUNLOCK) {
- if (flags == 0) {
- u.u_error = EINVAL;
- return;
+ 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;
}
- funlocki(fp->f_inode, flags);
- u.u_pofile[uap->fd] &= ~(RDLOCK|WRLOCK);
- return;
}
- /*
- * No reason to write lock a file we've already
- * write locked, similarly with a read lock.
- */
- if ((flags&WRLOCK) && (cmd&FWRLOCK) ||
- (flags&RDLOCK) && (cmd&FRDLOCK))
- return;
- u.u_pofile[uap->fd] = flocki(fp->f_inode, u.u_pofile[uap->fd], cmd);
+ 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);
+ } else {
+ error = VOP_RENAME(ndp, &tond);
+ }
+out1:
+ ndrele(&tond);
+ RETURN (error);
}
-truncate()
+/*
+ * Mkdir system call
+ */
+mkdir(scp)
+ register struct syscontext *scp;
{
struct a {
- char *fname;
- int length;
- } *uap;
- struct inode *ip;
-
- ip = namei(uchar, 0, 1);
- if (ip == NULL)
- return;
- if (access(ip, IWRITE))
- goto bad;
- if ((ip->i_mode&IFMT) == IFDIR) {
- u.u_error = EISDIR;
- goto bad;
+ char *name;
+ int dmode;
+ } *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 = CREATE | LOCKPARENT;
+ ndp->ni_segflg = UIO_USERSPACE;
+ ndp->ni_dirp = uap->name;
+ if (error = namei(ndp))
+ RETURN (error);
+ vp = ndp->ni_vp;
+ if (vp != NULL) {
+ VOP_ABORTOP(ndp);
+ RETURN (EEXIST);
}
- itrunc(ip, uap->length);
- return;
-bad:
- iput(ip);
+ vattr_null(&vattr);
+ vattr.va_type = VDIR;
+ vattr.va_mode = (uap->dmode & 0777) &~ scp->sc_cmask;
+ error = VOP_MKDIR(ndp, &vattr);
+ if (!error)
+ vput(ndp->ni_vp);
+ RETURN (error);
}
-ftruncate()
+/*
+ * Rmdir system call.
+ */
+rmdir(scp)
+ register struct syscontext *scp;
{
struct a {
- int fd;
- int length;
- } *uap;
- struct inode *ip;
- struct file *fp;
-
- fp = getf(uap->fd);
- if (fp == NULL)
- return;
- if (fp->f_type == DTYPE_SOCKET) {
- u.u_error = EINVAL;
- return;
+ char *name;
+ } *uap = (struct a *)scp->sc_ap;
+ register struct nameidata *ndp = &scp->sc_nd;
+ register struct vnode *vp;
+ int error;
+
+ ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
+ ndp->ni_segflg = UIO_USERSPACE;
+ ndp->ni_dirp = uap->name;
+ if (error = namei(ndp))
+ RETURN (error);
+ vp = ndp->ni_vp;
+ if (vp->v_type != VDIR) {
+ error = ENOTDIR;
+ goto out;
}
- if ((fp->f_flag&FWRITE) == 0) {
- u.u_error = EINVAL;
- return;
+ /*
+ * No rmdir "." please.
+ */
+ if (ndp->ni_dvp == vp) {
+ error = EINVAL;
+ goto out;
}
- ip = fp->f_inode;
- ilock(ip);
- itrunc(ip, uap->length);
+ /*
+ * Don't unlink a mounted file.
+ */
+ if (vp->v_flag & VROOT)
+ error = EBUSY;
+out:
+ if (error)
+ VOP_ABORTOP(ndp);
+ else
+ error = VOP_RMDIR(ndp);
+ RETURN (error);
}
-rename()
+/*
+ * Read a block of directory entries in a file system independent format
+ */
+getdirentries(scp)
+ register struct syscontext *scp;
{
- struct a {
- char *from;
- char *to;
- } *uap;
-
+ register struct a {
+ int fd;
+ char *buf;
+ unsigned count;
+ long *basep;
+ } *uap = (struct a *)scp->sc_ap;
+ struct file *fp;
+ struct uio auio;
+ struct iovec aiov;
+ off_t off;
+ int error;
+
+ if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
+ RETURN (error);
+ if ((fp->f_flag & FREAD) == 0)
+ RETURN (EBADF);
+ aiov.iov_base = uap->buf;
+ aiov.iov_len = uap->count;
+ auio.uio_iov = &aiov;
+ auio.uio_iovcnt = 1;
+ auio.uio_rw = UIO_READ;
+ auio.uio_segflg = UIO_USERSPACE;
+ auio.uio_resid = uap->count;
+ off = fp->f_offset;
+ if (error = VOP_READDIR((struct vnode *)fp->f_data, &auio,
+ &(fp->f_offset), fp->f_cred))
+ RETURN (error);
+ error = copyout((caddr_t)&off, (caddr_t)uap->basep,
+ sizeof(long));
+ scp->sc_retval1 = uap->count - auio.uio_resid;
+ RETURN (error);
}
/*
- * Make a new file.
+ * mode mask for creation of files
*/
-struct inode *
-maknode(mode)
- int mode;
+umask(scp)
+ register struct syscontext *scp;
{
- register struct inode *ip;
- ino_t ipref;
+ register struct a {
+ int mask;
+ } *uap = (struct a *)scp->sc_ap;
- if ((mode & IFMT) == IFDIR)
- ipref = dirpref(u.u_pdir->i_fs);
- else
- ipref = u.u_pdir->i_number;
- ip = ialloc(u.u_pdir, ipref, mode);
- if (ip == NULL) {
- iput(u.u_pdir);
- return (NULL);
- }
-#ifdef QUOTA
- if (ip->i_dquot != NODQUOT)
- panic("maknode: dquot");
-#endif
- ip->i_flag |= IACC|IUPD|ICHG;
- if ((mode & IFMT) == 0)
- mode |= IFREG;
- ip->i_mode = mode & ~u.u_cmask;
- ip->i_nlink = 1;
- ip->i_uid = u.u_uid;
- ip->i_gid = u.u_pdir->i_gid;
-#ifdef QUOTA
- ip->i_dquot = inoquota(ip);
-#endif
+ scp->sc_retval1 = scp->sc_cmask;
+ scp->sc_cmask = uap->mask & 07777;
+ RETURN (0);
+}
- /*
- * Make sure inode goes to disk before directory entry.
- */
- iupdat(ip, &time, &time, 1);
- direnter(ip);
- if (u.u_error) {
- /*
- * write error occurred trying to update directory
- * so must deallocate the inode
- */
- ip->i_nlink = 0;
- ip->i_flag |= ICHG;
- iput(ip);
- return (NULL);
- }
- return (ip);
+getvnode(ofile, fdes, fpp)
+ struct file *ofile[];
+ struct file **fpp;
+ int fdes;
+{
+ struct file *fp;
+
+ if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL)
+ return (EBADF);
+ if (fp->f_type != DTYPE_VNODE)
+ return (EINVAL);
+ *fpp = fp;
+ return (0);
}