diff options
Diffstat (limited to 'sys/kern/vfs_syscalls.c')
-rw-r--r-- | sys/kern/vfs_syscalls.c | 247 |
1 files changed, 246 insertions, 1 deletions
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index dca9f9033d6..caec7dbdf3f 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vfs_syscalls.c,v 1.61 2000/02/01 04:03:14 assar Exp $ */ +/* $OpenBSD: vfs_syscalls.c,v 1.62 2000/02/07 04:55:19 assar Exp $ */ /* $NetBSD: vfs_syscalls.c,v 1.71 1996/04/23 10:29:02 mycroft Exp $ */ /* @@ -948,6 +948,251 @@ sys_open(p, v, retval) } /* + * Get file handle system call + */ +int +sys_getfh(p, v, retval) + struct proc *p; + register void *v; + register_t *retval; +{ + register struct sys_getfh_args /* { + syscallarg(char *) fname; + syscallarg(fhandle_t *) fhp; + } */ *uap = v; + register struct vnode *vp; + fhandle_t fh; + int error; + struct nameidata nd; + + /* + * Must be super user + */ + error = suser(p->p_ucred, &p->p_acflag); + if(error) + return (error); + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, + SCARG(uap, fname), p); + error = namei(&nd); + if (error) + return (error); + vp = nd.ni_vp; + bzero((caddr_t)&fh, sizeof(fh)); + fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid; + error = VFS_VPTOFH(vp, &fh.fh_fid); + vput(vp); + if (error) + return (error); + error = copyout((caddr_t)&fh, (caddr_t)SCARG(uap, fhp), sizeof (fh)); + return (error); +} + +/* + * Open a file given a file handle. + * + * Check permissions, allocate an open file structure, + * and call the device open routine if any. + */ +int +sys_fhopen(p, v, retval) + struct proc *p; + void *v; + register_t *retval; +{ + register struct sys_fhopen_args /* { + syscallarg(const fhandle_t *) fhp; + syscallarg(int) flags; + } */ *uap = v; + struct filedesc *fdp = p->p_fd; + struct file *fp; + struct vnode *vp = NULL; + struct mount *mp; + struct ucred *cred = p->p_ucred; + int flags; + struct file *nfp; + int type, indx, error=0; + struct flock lf; + struct vattr va; + fhandle_t fh; + + /* + * Must be super user + */ + if ((error = suser(p->p_ucred, &p->p_acflag))) + return (error); + + flags = FFLAGS(SCARG(uap, flags)); + if ((flags & (FREAD | FWRITE)) == 0) + return (EINVAL); + if ((flags & O_CREAT)) + return (EINVAL); + + if ((error = falloc(p, &nfp, &indx)) != 0) + return (error); + fp = nfp; + if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0) + goto bad; + + if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) { + error = ESTALE; + goto bad; + } + + if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)) != 0) { + vp = NULL; /* most likely unnecessary sanity for bad: */ + goto bad; + } + + /* Now do an effective vn_open */ + + if (vp->v_type == VSOCK) { + error = EOPNOTSUPP; + goto bad; + } + if (flags & FREAD) { + if ((error = VOP_ACCESS(vp, VREAD, cred, p)) != 0) + goto bad; + } + if (flags & (FWRITE | O_TRUNC)) { + if (vp->v_type == VDIR) { + error = EISDIR; + goto bad; + } + if ((error = vn_writechk(vp)) != 0 || + (error = VOP_ACCESS(vp, VWRITE, cred, p)) != 0) + goto bad; + } + if (flags & O_TRUNC) { + VOP_UNLOCK(vp, 0, p); /* XXX */ + VOP_LEASE(vp, p, cred, LEASE_WRITE); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); /* XXX */ + VATTR_NULL(&va); + va.va_size = 0; + if ((error = VOP_SETATTR(vp, &va, cred, p)) != 0) + goto bad; + } + if ((error = VOP_OPEN(vp, flags, cred, p)) != 0) + goto bad; + if (flags & FWRITE) + vp->v_writecount++; + + /* done with modified vn_open, now finish what sys_open does. */ + + fp->f_flag = flags & FMASK; + fp->f_type = DTYPE_VNODE; + fp->f_ops = &vnops; + fp->f_data = (caddr_t)vp; + if (flags & (O_EXLOCK | O_SHLOCK)) { + lf.l_whence = SEEK_SET; + lf.l_start = 0; + lf.l_len = 0; + if (flags & O_EXLOCK) + lf.l_type = F_WRLCK; + else + lf.l_type = F_RDLCK; + type = F_FLOCK; + if ((flags & FNONBLOCK) == 0) + type |= F_WAIT; + VOP_UNLOCK(vp, 0, p); + error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type); + if (error) { + (void) vn_close(vp, fp->f_flag, fp->f_cred, p); + ffree(fp); + fdremove(fdp, indx); + return (error); + } + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); + fp->f_flag |= FHASLOCK; + } + VOP_UNLOCK(vp, 0, p); + *retval = indx; + return (0); + +bad: + ffree(fp); + fdremove(fdp, indx); + if (vp != NULL) + vput(vp); + return (error); +} + +/* ARGSUSED */ +int +sys_fhstat(p, v, retval) + struct proc *p; + void *v; + register_t *retval; +{ + register struct sys_fhstat_args /* { + syscallarg(const fhandle_t *) fhp; + syscallarg(struct stat *) sb; + } */ *uap = v; + struct stat sb; + int error; + fhandle_t fh; + struct mount *mp; + struct vnode *vp; + + /* + * Must be super user + */ + if ((error = suser(p->p_ucred, &p->p_acflag))) + return (error); + + if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0) + return (error); + + if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) + return (ESTALE); + if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp))) + return (error); + error = vn_stat(vp, &sb, p); + vput(vp); + if (error) + return (error); + error = copyout(&sb, SCARG(uap, sb), sizeof(sb)); + return (error); +} + +/* ARGSUSED */ +int +sys_fhstatfs(p, v, retval) + struct proc *p; + void *v; + register_t *retval; +{ + register struct sys_fhstatfs_args /* + syscallarg(const fhandle_t *) fhp; + syscallarg(struct statfs *) buf; + } */ *uap = v; + struct statfs sp; + fhandle_t fh; + struct mount *mp; + struct vnode *vp; + int error; + + /* + * Must be super user + */ + if ((error = suser(p->p_ucred, &p->p_acflag))) + return (error); + + if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0) + return (error); + + if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) + return (ESTALE); + if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp))) + return (error); + mp = vp->v_mount; + vput(vp); + if ((error = VFS_STATFS(mp, &sp, p)) != 0) + return (error); + sp.f_flags = mp->mnt_flag & MNT_VISFLAGMASK; + return (copyout(&sp, SCARG(uap, buf), sizeof(sp))); +} + +/* * Create a special file. */ /* ARGSUSED */ |