File: [Development] / xfs-linux / Attic / xfs_handle.c (download)
Revision 1.14, Tue Sep 5 00:45:53 1995 UTC (22 years, 1 month ago) by doucette
Branch: MAIN
Changes since 1.13: +6 -6
lines
Use curprocp instead of u.u_procp, curprocp->p_cred instead of
u.u_cred, since kthreads don't have a u.
|
/**************************************************************************
* *
* Copyright (C) 1994, Silicon Graphics, Inc. *
* *
* These coded instructions, statements, and computer programs contain *
* unpublished proprietary information of Silicon Graphics, Inc., and *
* are protected by Federal copyright law. They may not be disclosed *
* to third parties or copied or duplicated in any form, in whole or *
* in part, without the prior written consent of Silicon Graphics, Inc. *
* *
**************************************************************************/
#ident "$Revision: 1.14 $"
#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/errno.h>
#include <sys/cred.h>
#include <sys/file.h>
#include <sys/proc.h>
#include <sys/user.h>
#include <sys/vfs.h>
#include <sys/vnode.h>
#include <sys/sat.h>
#include "xfs_handle.h"
#include <sys/kmem.h>
#include <sys/debug.h>
/*
* Ok. This file contains stuff that defines a general handle
* mechanism, except that it's only used by xfs at the moment.
* Imagine that it's in some generic place. The same goes for
* xfs_handle.h; it's would-be generic but xfs-only right now.
*/
int vp_open ( vnode_t *vp, int filemode );
STATIC int
copyout_handle (
handle_t *handle, /* handle data to copy out */
size_t hsize, /* amount of data in handle */
void *hbuf, /* user's data buffer */
size_t *hlen) /* user's data buffer's size */
{
if (copyout (handle, hbuf, (int) hsize))
return EFAULT;
#ifdef _K64U64
if (ABI_IS_64BIT(curprocp->p_abi))
return copyout (&hsize, hlen, sizeof *hlen);
else
#endif
return suword (hlen, (int) hsize);
}
/*
* Return the handle for the object named by path.
*/
int
path_to_handle (
char *path, /* any path name */
void *hbuf, /* user's data buffer */
size_t *hlen) /* set to size of data copied to hbuf */
{
int error;
vnode_t *vp;
handle_t handle;
error = lookupname (path, UIO_USERSPACE, NO_FOLLOW, NULLVPP, &vp);
if (error)
return error;
error = vp_to_handle (vp, &handle);
VN_RELE (vp);
if (error)
return error;
return copyout_handle (&handle, HSIZE (handle), hbuf, hlen);
}
/*
* Return the handle for the file system containing the object named by path.
*/
int
path_to_fshandle (
char *path, /* any path name */
void *hbuf, /* user's data buffer */
size_t *hlen) /* set to size of data copied to hbuf */
{
int error;
vnode_t *vp;
handle_t handle;
error = lookupname (path, UIO_USERSPACE, NO_FOLLOW, NULLVPP, &vp);
if (error)
return error;
error = vp_to_handle (vp, &handle);
VN_RELE (vp);
if (error)
return error;
return copyout_handle (&handle, sizeof (fsid_t), hbuf, hlen);
}
int
fd_to_handle (
int fd, /* any file descriptor */
void *hbuf, /* user's data buffer */
size_t *hlen) /* set to size of data copied to hbuf */
{
int error;
vnode_t *vp;
file_t *fp;
handle_t handle;
error = getf (fd, &fp);
if (error)
return error;
vp = fp->f_vnode;
error = vp_to_handle (vp, &handle);
if (error)
return error;
return copyout_handle (&handle, HSIZE (handle), hbuf, hlen);
}
/*
* Just like readlink, except that it uses a handle instead of a path
* to locate the vnode.
*/
int
readlink_by_handle (
void *hanp, /* handle data */
size_t hlen, /* size of handle data */
void *buf, /* return buffer */
size_t bufsiz, /* size provided */
rval_t *rvp)
{
int error;
handle_t handle;
vnode_t *vp;
struct iovec aiov;
struct uio auio;
error = gethandle (hanp, hlen, &handle);
if (error)
return error;
vp = handle_to_vp (&handle);
if (vp == NULL)
return EINVAL;
if (vp->v_type != VLNK) {
error = EINVAL;
goto out;
}
aiov.iov_base = buf;
aiov.iov_len = bufsiz;
auio.uio_iov = &aiov;
auio.uio_iovcnt = 1;
auio.uio_pio = 0;
auio.uio_pbuf = 0;
auio.uio_fmode = FINVIS; /* not used otherwise */
auio.uio_offset = 0;
auio.uio_segflg = UIO_USERSPACE;
auio.uio_resid = bufsiz;
error = VOP_READLINK (vp, &auio, curprocp->p_cred);
out:
VN_RELE (vp);
rvp->r_val1 = bufsiz - auio.uio_resid;
return error;
}
/*
* Open a file specified by a file handle. Follow the same basic
* algorithm as copen, cutting out some things not needed bacause
* of self-imposed restrictions. The restrictions are that only
* directories and regular files are allowed and none of the funky
* open flags are used.
*
* Always sets the FINVIS flag.
*/
int
open_by_handle (
void *hanp, /* handle data */
size_t hlen, /* size of handle data */
int filemode, /* open mode */
rval_t *rvp)
{
vnode_t *vp;
file_t *fp;
int fd;
int error;
handle_t handle;
int sat_flags = filemode; /* what was requested */
filemode -= FOPEN;
filemode &= (FREAD|FWRITE);
if ((filemode & (FREAD|FWRITE)) == 0)
return EINVAL;
filemode |= FINVIS;
error = gethandle (hanp, hlen, &handle);
if (error)
return error;
vp = handle_to_vp (&handle);
if (vp == NULL)
return EINVAL;
switch (vp->v_type) {
case VDIR:
case VREG:
break;
default:
error = EINVAL;
goto out;
}
error = falloc ((vnode_t *) NULL, filemode, &fp, &fd);
if (error)
goto out;
/*
* a kludge for the usema device - it really needs to know
* the 'fp' for it opening file - we use u_openfp to mark
* this.
*/
u.u_openfp = fp;
if ((filemode & FWRITE) == 0)
_SAT_PNALLOC(SAT_OPEN_RO);
else
_SAT_PNALLOC(SAT_OPEN);
error = vp_open (vp, filemode);
u.u_openfp = NULL;
if (error) {
setf (fd, NULLFP);
unfalloc (fp);
} else {
fp->f_vnode = vp;
rvp->r_val1 = fd;
fready (fp);
}
out:
if (error)
VN_RELE (vp);
_SAT_OPEN (rvp->r_val1, (filemode&FCREAT), sat_flags, error);
return error;
}
/*
* vp_open - based on vn_open. Differences are
* + gets a vp passed to it, instead of using lookupname
* + restricted to FREAD and FWRITE, always has FINVIS
* + restricted to directories and regular files.
*/
int
vp_open (
vnode_t *vp,
int filemode)
{
struct vnode *tvp;
register int mode;
register int error;
tvp = (struct vnode *) NULL;
mode = 0;
filemode &= (FREAD | FWRITE | FINVIS);
if (filemode & FREAD)
mode |= VREAD;
if (filemode & FWRITE)
mode |= VWRITE;
tvp = vp;
VN_HOLD (tvp);
if (error = VOP_SETFL (vp, 0, filemode, curprocp->p_cred))
goto out;
/*
* Can't write directories, active texts, swap files,
* or read-only filesystems.
*/
if (filemode & FWRITE) {
if (vp->v_type == VDIR) {
error = EISDIR;
goto out;
}
if (vp->v_vfsp->vfs_flag & VFS_RDONLY) {
error = EROFS;
goto out;
}
if ((vp->v_flag & VISSWAP) && vp->v_type == VREG) {
error = EBUSY;
goto out;
}
}
/* Check discretionary permissions. */
if (error = VOP_ACCESS (vp, mode, 0, curprocp->p_cred))
goto out;
/*
* Do opening protocol.
*/
if ((error = VOP_OPEN (&vp, filemode, curprocp->p_cred)) == 0) {
if (tvp)
VN_RELE (tvp);
}
out:
if (error) {
if (tvp)
VN_RELE (tvp);
}
return error;
}
/*
* Make a handle from a vnode.
*/
int
vp_to_handle (
vnode_t *vp,
handle_t *handlep)
{
int error;
struct fid *fidp = NULL;
int hsize;
if (vp->v_vfsp->vfs_altfsid == NULL)
return EINVAL;
switch (vp->v_type) {
case VREG:
case VDIR:
case VLNK:
break;
default:
return EBADF;
}
error = VOP_FID (vp, &fidp);
if (error)
return error;
if (fidp == NULL)
return EIO; /* FIX: what real errno? */
bcopy (vp->v_vfsp->vfs_altfsid, &handlep->ha_fsid, sizeof (fsid_t));
/* Copy only the currently used part of the fid struct */
bcopy (fidp, &handlep->ha_fid, fidp->fid_len + sizeof fidp->fid_len);
hsize = HSIZE (*handlep);
bzero ((char *) handlep + hsize, sizeof *handlep - hsize);
freefid (fidp);
return 0;
}
/*
* Get a vnode for the object referenced by handle.
*/
struct vnode *
handle_to_vp (
handle_t *handlep)
{
struct vfs *vfsp;
struct vnode *vp;
int error;
vfsp = altgetvfs (&handlep->ha_fsid);
if (vfsp == NULL)
return NULL;
error = VFS_VGET (vfsp, &vp, &handlep->ha_fid);
if (error)
return NULL;
return vp;
}
/*
* Get a handle of the form (void *, size_t) from user space and
* convert it to a handle_t handle. Do as much validation of the
* result as possible; the content of each fid still has to be
* checked by its consumer.
*/
int
gethandle (
void *hanp, /* input, handle data */
size_t hlen, /* input, size of handle data */
handle_t *hp) /* output, copy of data */
{
if (hlen < sizeof hp->ha_fsid || hlen > sizeof *hp)
return EINVAL;
if (copyin (hanp, hp, hlen))
return EFAULT;
if (hlen < sizeof *hp)
bzero (((char *) hp) + hlen, sizeof *hp - hlen);
if (hlen == sizeof hp->ha_fsid)
return 0; /* FS handle, nothing more to check */
if (hp->ha_fid.fid_len != (hlen - sizeof hp->ha_fsid -
sizeof hp->ha_fid.fid_len) || *((short *) hp->ha_fid.fid_data))
{
return EINVAL;
}
return 0;
}
/*
* An alternate version of getvfs. Needed because handles require
* a file system ID that remains constant for the life of the file
* system. Cloned from getvfs in os/vfs.c, where this might arguably
* belong. It's here because it's only used by things related to
* these handles.
*/
struct vfs *
altgetvfs (fsid_t *fsid)
{
register struct vfs *vfsp;
int s;
s = vfs_spinlock();
for (vfsp = rootvfs; vfsp != NULL; vfsp = vfsp->vfs_next) {
if (vfsp->vfs_altfsid &&
vfsp->vfs_altfsid->val[0] == fsid->val[0] &&
vfsp->vfs_altfsid->val[1] == fsid->val[1] &&
!(vfsp->vfs_flag & VFS_OFFLINE)) {
break;
}
}
vfs_spinunlock(s);
return vfsp;
}