-/* vfs_syscalls.c 4.24 82/06/04 */
+/*
+ * 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"
+
+/*
+ * Virtual File System System Calls
+ */
+
+/*
+ * 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;
+
+ /*
+ * 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);
+}
+
+/*
+ * 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;
+
+ /*
+ * 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);
-#ifdef SIMFS
-#include "../h/sysrenam.h"
-#endif
-#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"
+ xumount(mp); /* remove unused sticky files from text table */
+ cache_purgevfs(mp); /* remove cache entries for this file sys */
+ VFS_SYNC(mp, MNT_WAIT);
-chdir()
+ 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);
+}
+
+/*
+ * 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;
- chdirec(&u.u_cdir);
+ 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);
}
-chroot()
+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 (suser())
- chdirec(&u.u_rdir);
+ 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)));
}
-chdirec(ipp)
-register struct inode **ipp;
+/*
+ * 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;
- irele(ip);
- if (*ipp) {
- ilock(*ipp);
- iput(*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 rwmode;
- } *uap;
+ int mode;
+ int crtmode;
+ } *uap = (struct a *) scp->sc_ap;
+ struct nameidata *ndp = &scp->sc_nd;
- uap = (struct a *)u.u_ap;
- ip = namei(uchar, 0, 1);
- if (ip == NULL)
- return;
- open1(ip, ++uap->rwmode, 0);
+ 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));
}
/*
* Creat system call.
*/
-creat()
+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, 2);
- } else
- open1(ip, FWRITE, 1);
+ 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));
}
/*
* Check permissions, allocate an open file structure,
* and call the device open routine if any.
*/
-open1(ip, mode, trf)
- 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;
-
- if (trf != 2) {
- if (mode&FREAD)
- (void) access(ip, IREAD);
- if (mode&FWRITE) {
- (void) access(ip, IWRITE);
- if ((ip->i_mode&IFMT) == IFDIR)
- u.u_error = EISDIR;
- }
+ 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);
}
- if (u.u_error)
- goto out;
- if (trf == 1)
- itrunc(ip);
- irele(ip);
- if ((fp = falloc()) == NULL)
- goto out;
- fp->f_flag = mode&(FREAD|FWRITE);
- i = u.u_r.r_val1;
- fp->f_inode = ip;
- openi(ip, mode&(FREAD|FWRITE));
- if (u.u_error == 0)
- return;
- u.u_ofile[i] = NULL;
- fp->f_count--;
-out:
- if (ip != NULL)
- 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 *)scp->sc_ap;
+ register struct nameidata *ndp = &scp->sc_nd;
+ register struct vnode *vp;
+ struct vattr vattr;
+ int error;
- uap = (struct a *)u.u_ap;
- if (suser()) {
- ip = namei(uchar, 1, 0);
- if (ip != NULL) {
- u.u_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;
+ 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;
}
+ 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 *)scp->sc_ap;
+ register struct nameidata *ndp = &scp->sc_nd;
+ register struct vnode *vp, *xp;
+ int error;
- 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())
+ 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;
- ip->i_nlink++;
- ip->i_flag |= ICHG;
- iupdat(ip, &time, &time, 1);
- irele(ip);
- u.u_dirp = (caddr_t)uap->linkname;
- xp = namei(uchar, 1, 0);
+ xp = ndp->ni_vp;
if (xp != NULL) {
- u.u_error = EEXIST;
- iput(xp);
+ error = EEXIST;
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;
- goto out;
- }
- wdir(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:
- iput(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;
-
- 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++;
- } 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 ((ip->i_flag&ITEXT) && ip->i_nlink==1) {
- u.u_error = ETXTBSY;
- goto out;
- }
-*/
- if (u.u_count == 0) {
- /*
- * first entry in block, so set d_ino to zero.
- */
- u.u_base = (caddr_t)&u.u_dent;
- u.u_count = DIRSIZ(&u.u_dent);
- u.u_dent.d_ino = 0;
- writei(pp);
- } else {
- /*
- * updating preceeding entry to skip over current entry.
- */
- fs = pp->i_fs;
- lbn = lblkno(fs, u.u_offset);
- base = blkoff(fs, u.u_offset);
- bn = fsbtodb(fs, bmap(pp, lbn, B_WRITE, base + u.u_count));
- bp = bread(pp->i_dev, bn, blksize(fs, pp, lbn));
- if (bp->b_flags & B_ERROR) {
- brelse(bp);
- goto out;
- }
- ((struct direct *)(bp->b_un.b_addr + base))->d_reclen +=
- u.u_dent.d_reclen;
- bwrite(bp);
- pp->i_flag |= IUPD|ICHG;
- }
- ip->i_nlink--;
- ip->i_flag |= ICHG;
-
+ if (vp->v_flag & VTEXT)
+ xrele(vp); /* try once to free text */
out:
- iput(ip);
-out1:
- iput(pp);
+ if (error)
+ VOP_ABORTOP(ndp);
+ else
+ error = VOP_REMOVE(ndp);
+ RETURN (error);
}
/*
* Seek system call
*/
-seek()
+lseek(scp)
+ register struct syscontext *scp;
{
register struct file *fp;
register struct a {
int fdes;
off_t off;
int sbase;
- } *uap;
-
- uap = (struct a *)u.u_ap;
- fp = getf(uap->fdes);
- if (fp == NULL)
- return;
- if (fp->f_flag&FSOCKET) {
- 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 == 1)
- uap->off += fp->f_offset;
- else if (uap->sbase == 2)
- 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&(IREAD>>6))
- (void) access(ip, IREAD);
- if (uap->fmode&(IWRITE>>6))
- (void) access(ip, IWRITE);
- if (uap->fmode&(IEXEC>>6))
- (void) access(ip, IEXEC);
- 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;
+ vput(vp);
+out1:
+ scp->sc_uid = svuid;
+ scp->sc_gid = svgid;
+ RETURN (error);
}
/*
- * the fstat system call.
+ * Stat system call. This version follows links.
*/
-fstat()
+stat(scp)
+ struct syscontext *scp;
{
- register struct file *fp;
- register struct a {
- int fdes;
- struct stat *sb;
- } *uap;
-
- uap = (struct a *)u.u_ap;
- fp = getf(uap->fdes);
- if (fp == NULL)
- return;
- if (fp->f_flag & FSOCKET)
- u.u_error = sostat(fp->f_socket, uap->sb);
- else
- stat1(fp->f_inode, uap->sb);
+
+ stat1(scp, FOLLOW);
}
/*
- * Stat system call. This version follows links.
+ * Lstat system call. This version does not follow links.
*/
-stat()
+lstat(scp)
+ struct syscontext *scp;
+{
+
+ stat1(scp, NOFOLLOW);
+}
+
+stat1(scp, follow)
+ register struct syscontext *scp;
+ int follow;
{
- register struct inode *ip;
register struct a {
char *fname;
- struct stat *sb;
- } *uap;
+ struct stat *ub;
+ } *uap = (struct a *)scp->sc_ap;
+ register struct nameidata *ndp = &scp->sc_nd;
+ struct stat sb;
+ int error;
- uap = (struct a *)u.u_ap;
- ip = namei(uchar, 0, 1);
- if (ip == NULL)
- return;
- stat1(ip, uap->sb);
- iput(ip);
+ 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);
}
/*
- * Lstat system call. This version does not follow links.
+ * Return target name of a symbolic link
*/
-lstat()
+readlink(scp)
+ register struct syscontext *scp;
{
- register struct inode *ip;
register struct a {
- char *fname;
- struct stat *sb;
- } *uap;
+ char *name;
+ char *buf;
+ int count;
+ } *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;
- uap = (struct a *)u.u_ap;
- ip = namei(uchar, 0, 0);
- if (ip == NULL)
- return;
- stat1(ip, uap->sb);
- iput(ip);
+ 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);
}
/*
- * The basic routine for fstat and stat:
- * get the inode and pass appropriate parts back.
+ * Change flags of a file given path name.
*/
-stat1(ip, ub)
- register struct inode *ip;
- struct stat *ub;
+chflags(scp)
+ register struct syscontext *scp;
{
- struct stat ds;
+ 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;
- 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;
- ds.st_blksize = ip->i_fs->fs_bsize;
- if (copyout((caddr_t)&ds, (caddr_t)ub, sizeof(ds)) < 0)
- u.u_error = EFAULT;
+ 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;
+ }
+ error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
+out:
+ vput(vp);
+ RETURN (error);
}
/*
- * Return target name of a symbolic link
+ * Change flags of a file given a file descriptor.
*/
-readlink()
+fchflags(scp)
+ register struct syscontext *scp;
{
- register struct inode *ip;
- register struct a {
- char *name;
- char *buf;
- int count;
- } *uap;
+ struct a {
+ int fd;
+ int flags;
+ } *uap = (struct a *)scp->sc_ap;
+ struct vattr vattr;
+ struct vnode *vp;
+ struct file *fp;
+ int error;
- ip = namei(uchar, 0, 0);
- if (ip == NULL)
- return;
- if ((ip->i_mode&IFMT) != IFLNK) {
- u.u_error = ENXIO;
+ 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;
}
- 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, fp->f_cred);
out:
- iput(ip);
- u.u_r.r_val1 = uap->count - u.u_count;
+ VOP_UNLOCK(vp);
+ RETURN (error);
}
-chmod()
+/*
+ * Change mode of a file given path name.
+ */
+chmod(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;
+ register struct nameidata *ndp = &scp->sc_nd;
+ register struct vnode *vp;
+ struct vattr vattr;
+ int error;
- uap = (struct a *)u.u_ap;
- if ((ip = owner(1)) == NULL)
- return;
- ip->i_mode &= ~07777;
- if (u.u_uid)
- uap->fmode &= ~ISVTX;
- ip->i_mode |= uap->fmode&07777;
- ip->i_flag |= ICHG;
- if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0)
- xrele(ip);
- iput(ip);
+ 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);
}
-chown()
+/*
+ * Change mode of a file given a file descriptor.
+ */
+fchmod(scp)
+ register struct syscontext *scp;
{
- register struct inode *ip;
- register struct a {
+ struct a {
+ int fd;
+ int fmode;
+ } *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;
+ }
+ error = VOP_SETATTR(vp, &vattr, fp->f_cred);
+out:
+ VOP_UNLOCK(vp);
+ RETURN (error);
+}
+
+/*
+ * Set ownership given a path name.
+ */
+chown(scp)
+ register struct syscontext *scp;
+{
+ struct a {
char *fname;
int uid;
int gid;
- } *uap;
+ } *uap = (struct a *)scp->sc_ap;
+ register struct nameidata *ndp = &scp->sc_nd;
+ register struct vnode *vp;
+ struct vattr vattr;
+ int error;
- uap = (struct a *)u.u_ap;
- if (!suser() || (ip = owner(0)) == NULL)
- return;
- ip->i_uid = uap->uid;
- ip->i_gid = uap->gid;
- ip->i_flag |= ICHG;
- if (u.u_ruid != 0)
- ip->i_mode &= ~(ISUID|ISGID);
- iput(ip);
+ 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);
}
/*
- * Set IUPD and IACC times on file.
- * Can't set ICHG.
+ * Set ownership given a file descriptor.
*/
-utime()
+fchown(scp)
+ register struct syscontext *scp;
+{
+ struct a {
+ int fd;
+ int uid;
+ int gid;
+ } *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;
+ }
+ 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;
- 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;
+ 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);
} else {
- ip->i_flag |= IACC|IUPD|ICHG;
- iupdat(ip, &tv[0], &tv[1], 0);
+ error = VOP_RENAME(ndp, &tond);
}
- iput(ip);
+out1:
+ ndrele(&tond);
+ RETURN (error);
+}
+
+/*
+ * Mkdir system call
+ */
+mkdir(scp)
+ register struct syscontext *scp;
+{
+ struct a {
+ 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);
+ }
+ 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);
+}
+
+/*
+ * Rmdir system call.
+ */
+rmdir(scp)
+ register struct syscontext *scp;
+{
+ struct a {
+ 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;
+ }
+ /*
+ * No rmdir "." please.
+ */
+ if (ndp->ni_dvp == vp) {
+ error = EINVAL;
+ goto out;
+ }
+ /*
+ * 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);
+}
+
+/*
+ * Read a block of directory entries in a file system independent format
+ */
+getdirentries(scp)
+ register struct syscontext *scp;
+{
+ 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);
+}
+
+/*
+ * mode mask for creation of files
+ */
+umask(scp)
+ register struct syscontext *scp;
+{
+ register struct a {
+ int mask;
+ } *uap = (struct a *)scp->sc_ap;
+
+ scp->sc_retval1 = scp->sc_cmask;
+ scp->sc_cmask = uap->mask & 07777;
+ RETURN (0);
}
-sync()
+getvnode(ofile, fdes, fpp)
+ struct file *ofile[];
+ struct file **fpp;
+ int fdes;
{
+ struct file *fp;
- update(0);
+ if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL)
+ return (EBADF);
+ if (fp->f_type != DTYPE_VNODE)
+ return (EINVAL);
+ *fpp = fp;
+ return (0);
}