o Introduce extattr_{delete,get,set}_fd() to allow extended attribute

operations on file descriptors, which complement the existing set of
  calls, extattr_{delete,get,set}_file() which act on paths.  In doing
  so, restructure the system call implementation such that the two sets
  of functions share most of the relevant code, rather than duplicating
  it.  This pushes the vnode locking into the shared code, but keeps
  the copying in of some arguments in the system call code.  Allowing
  access via file descriptors reduces the opportunity for race
  conditions when managing extended attributes.

Obtained from:	TrustedBSD Project
This commit is contained in:
Robert Watson 2001-03-31 16:20:05 +00:00
parent 333ec30d71
commit fec605c882
4 changed files with 487 additions and 196 deletions

View File

@ -533,3 +533,11 @@
368 STD BSD { int __cap_set_fd(int fd, struct cap *cap_p); }
369 STD BSD { int __cap_set_file(const char *path_p, struct cap *cap_p); }
370 NODEF NOHIDE lkmressys lkmressys nosys_args int
371 STD BSD { int extattr_set_fd(int fd, int attrnamespace, \
const char *attrname, struct iovec *iovp, \
int iovcnt); }
372 STD BSD { int extattr_get_fd(int fd, int attrnamespace, \
const char *attrname, struct iovec *iovp, \
int iovcnt); }
373 STD BSD { int extattr_delete_fd(int fd, int attrnamespace, \
const char *attrname); }

View File

@ -3745,38 +3745,34 @@ extattrctl(p, uap)
}
/*
* Syscall to set a named extended attribute on a file or directory.
* Accepts attribute name, and a uio structure pointing to the data to set.
* The uio is consumed in the style of writev(). The real work happens
* in VOP_SETEXTATTR().
* extattr_set_vp(): Set a named extended attribute on a file or directory
*
* Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
* kernelspace string pointer "attrname",
* userspace iovec array pointer "iovp", unsigned int iovcnt
* proc "p"
* Returns: 0 on success, an error number otherwise
* Locks: none
* References: vp must be a valid reference for the duration of the call
*/
int
extattr_set_file(p, uap)
struct proc *p;
struct extattr_set_file_args *uap;
static int
extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname,
struct iovec *iovp, unsigned iovcnt, struct proc *p)
{
struct nameidata nd;
struct mount *mp;
struct uio auio;
struct iovec *iov, *needfree = NULL, aiov[UIO_SMALLIOV];
char attrname[EXTATTR_MAXNAMELEN];
u_int iovlen, cnt;
int error, i;
error = copyin(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN);
if (error)
if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
return (error);
NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
SCARG(uap, path), p);
if ((error = namei(&nd)) != 0)
return(error);
if ((error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH)) != 0) {
NDFREE(&nd, 0);
return (error);
}
iovlen = uap->iovcnt * sizeof(struct iovec);
if (uap->iovcnt > UIO_SMALLIOV) {
if (uap->iovcnt > UIO_MAXIOV) {
VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
iovlen = iovcnt * sizeof(struct iovec);
if (iovcnt > UIO_SMALLIOV) {
if (iovcnt > UIO_MAXIOV) {
error = EINVAL;
goto done;
}
@ -3785,15 +3781,15 @@ extattr_set_file(p, uap)
} else
iov = aiov;
auio.uio_iov = iov;
auio.uio_iovcnt = uap->iovcnt;
auio.uio_iovcnt = iovcnt;
auio.uio_rw = UIO_WRITE;
auio.uio_segflg = UIO_USERSPACE;
auio.uio_procp = p;
auio.uio_offset = 0;
if ((error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen)))
if ((error = copyin((caddr_t)iovp, (caddr_t)iov, iovlen)))
goto done;
auio.uio_resid = 0;
for (i = 0; i < uap->iovcnt; i++) {
for (i = 0; i < iovcnt; i++) {
if (iov->iov_len > INT_MAX - auio.uio_resid) {
error = EINVAL;
goto done;
@ -3802,112 +3798,255 @@ extattr_set_file(p, uap)
iov++;
}
cnt = auio.uio_resid;
error = VOP_SETEXTATTR(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
&auio, p->p_cred->pc_ucred, p);
error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio,
p->p_cred->pc_ucred, p);
cnt -= auio.uio_resid;
p->p_retval[0] = cnt;
done:
if (needfree)
FREE(needfree, M_IOV);
NDFREE(&nd, 0);
VOP_UNLOCK(vp, 0, p);
vn_finished_write(mp);
return (error);
}
int
extattr_set_file(p, uap)
struct proc *p;
struct extattr_set_file_args *uap;
{
struct nameidata nd;
char attrname[EXTATTR_MAXNAMELEN];
int error;
error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
NULL);
if (error)
return (error);
NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
if ((error = namei(&nd)) != 0)
return (error);
NDFREE(&nd, NDF_ONLY_PNBUF);
error = extattr_set_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
SCARG(uap, iovp), SCARG(uap, iovcnt), p);
vrele(nd.ni_vp);
return (error);
}
int
extattr_set_fd(p, uap)
struct proc *p;
struct extattr_set_fd_args *uap;
{
struct file *fp;
char attrname[EXTATTR_MAXNAMELEN];
int error;
error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
NULL);
if (error)
return (error);
if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
return (error);
error = extattr_set_vp((struct vnode *)fp->f_data,
SCARG(uap, attrnamespace), attrname, SCARG(uap, iovp),
SCARG(uap, iovcnt), p);
return (error);
}
/*
* Syscall to get a named extended attribute on a file or directory.
* Accepts attribute name, and a uio structure pointing to a buffer for the
* data. The uio is consumed in the style of readv(). The real work
* happens in VOP_GETEXTATTR();
* extattr_get_vp(): Get a named extended attribute on a file or directory
*
* Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
* kernelspace string pointer "attrname",
* userspace iovec array pointer "iovp", unsigned int iovcnt,
* proc "p"
* Returns: 0 on success, an error number otherwise
* Locks: none
* References: vp must be a valid reference for the duration of the call
*/
static int
extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname,
struct iovec *iovp, unsigned iovcnt, struct proc *p)
{
struct uio auio;
struct iovec *iov, *needfree = NULL, aiov[UIO_SMALLIOV];
u_int iovlen, cnt;
int error, i;
VOP_LEASE(vp, p, p->p_ucred, LEASE_READ);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
iovlen = iovcnt * sizeof (struct iovec);
if (iovcnt > UIO_SMALLIOV) {
if (iovcnt > UIO_MAXIOV) {
error = EINVAL;
goto done;
}
MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
needfree = iov;
} else
iov = aiov;
auio.uio_iov = iov;
auio.uio_iovcnt = iovcnt;
auio.uio_rw = UIO_READ;
auio.uio_segflg = UIO_USERSPACE;
auio.uio_procp = p;
auio.uio_offset = 0;
if ((error = copyin((caddr_t)iovp, (caddr_t)iov, iovlen)))
goto done;
auio.uio_resid = 0;
for (i = 0; i < iovcnt; i++) {
if (iov->iov_len > INT_MAX - auio.uio_resid) {
error = EINVAL;
goto done;
}
auio.uio_resid += iov->iov_len;
iov++;
}
cnt = auio.uio_resid;
error = VOP_GETEXTATTR(vp, attrnamespace, attrname, &auio,
p->p_cred->pc_ucred, p);
cnt -= auio.uio_resid;
p->p_retval[0] = cnt;
done:
if (needfree)
FREE(needfree, M_IOV);
VOP_UNLOCK(vp, 0, p);
return (error);
}
int
extattr_get_file(p, uap)
struct proc *p;
struct extattr_get_file_args *uap;
{
struct nameidata nd;
struct uio auio;
struct iovec *iov, *needfree, aiov[UIO_SMALLIOV];
char attrname[EXTATTR_MAXNAMELEN];
u_int iovlen, cnt;
int error, i;
int error;
error = copyin(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN);
error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
NULL);
if (error)
return (error);
NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
SCARG(uap, path), p);
NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
if ((error = namei(&nd)) != 0)
return (error);
iovlen = uap->iovcnt * sizeof (struct iovec);
if (uap->iovcnt > UIO_SMALLIOV) {
if (uap->iovcnt > UIO_MAXIOV) {
NDFREE(&nd, 0);
return (EINVAL);
}
MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
needfree = iov;
} else {
iov = aiov;
needfree = NULL;
}
auio.uio_iov = iov;
auio.uio_iovcnt = uap->iovcnt;
auio.uio_rw = UIO_READ;
auio.uio_segflg = UIO_USERSPACE;
auio.uio_procp = p;
auio.uio_offset = 0;
if ((error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen)))
goto done;
auio.uio_resid = 0;
for (i = 0; i < uap->iovcnt; i++) {
if (iov->iov_len > INT_MAX - auio.uio_resid) {
error = EINVAL;
goto done;
}
auio.uio_resid += iov->iov_len;
iov++;
}
cnt = auio.uio_resid;
error = VOP_GETEXTATTR(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
&auio, p->p_cred->pc_ucred, p);
cnt -= auio.uio_resid;
p->p_retval[0] = cnt;
done:
if (needfree)
FREE(needfree, M_IOV);
NDFREE(&nd, 0);
return(error);
NDFREE(&nd, NDF_ONLY_PNBUF);
error = extattr_get_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
SCARG(uap, iovp), SCARG(uap, iovcnt), p);
vrele(nd.ni_vp);
return (error);
}
int
extattr_get_fd(p, uap)
struct proc *p;
struct extattr_get_fd_args *uap;
{
struct file *fp;
char attrname[EXTATTR_MAXNAMELEN];
int error;
error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
NULL);
if (error)
return (error);
if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
return (error);
error = extattr_get_vp((struct vnode *)fp->f_data,
SCARG(uap, attrnamespace), attrname, SCARG(uap, iovp),
SCARG(uap, iovcnt), p);
return (error);
}
/*
* Syscall to delete a named extended attribute from a file or directory.
* Accepts attribute name. The real work happens in VOP_SETEXTATTR().
* extattr_delete_vp(): Delete a named extended attribute on a file or
* directory
*
* Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
* kernelspace string pointer "attrname", proc "p"
* Returns: 0 on success, an error number otherwise
* Locks: none
* References: vp must be a valid reference for the duration of the call
*/
static int
extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname,
struct proc *p)
{
struct mount *mp;
int error;
if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
return (error);
VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL,
p->p_cred->pc_ucred, p);
VOP_UNLOCK(vp, 0, p);
vn_finished_write(mp);
return (error);
}
int
extattr_delete_file(p, uap)
struct proc *p;
struct extattr_delete_file_args *uap;
{
struct mount *mp;
struct nameidata nd;
char attrname[EXTATTR_MAXNAMELEN];
int error;
int error;
error = copyin(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN);
error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
NULL);
if (error)
return(error);
NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
SCARG(uap, path), p);
NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
if ((error = namei(&nd)) != 0)
return(error);
if ((error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH)) != 0) {
NDFREE(&nd, 0);
return (error);
}
error = VOP_SETEXTATTR(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
NULL, p->p_cred->pc_ucred, p);
NDFREE(&nd, 0);
vn_finished_write(mp);
NDFREE(&nd, NDF_ONLY_PNBUF);
error = extattr_delete_vp(nd.ni_vp, SCARG(uap, attrnamespace),
attrname, p);
vrele(nd.ni_vp);
return(error);
}
int
extattr_delete_fd(p, uap)
struct proc *p;
struct extattr_delete_fd_args *uap;
{
struct file *fp;
char attrname[EXTATTR_MAXNAMELEN];
int error;
error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
NULL);
if (error)
return (error);
if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
return (error);
error = extattr_delete_vp((struct vnode *)fp->f_data,
SCARG(uap, attrnamespace), attrname, p);
return (error);
}

View File

@ -3745,38 +3745,34 @@ extattrctl(p, uap)
}
/*
* Syscall to set a named extended attribute on a file or directory.
* Accepts attribute name, and a uio structure pointing to the data to set.
* The uio is consumed in the style of writev(). The real work happens
* in VOP_SETEXTATTR().
* extattr_set_vp(): Set a named extended attribute on a file or directory
*
* Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
* kernelspace string pointer "attrname",
* userspace iovec array pointer "iovp", unsigned int iovcnt
* proc "p"
* Returns: 0 on success, an error number otherwise
* Locks: none
* References: vp must be a valid reference for the duration of the call
*/
int
extattr_set_file(p, uap)
struct proc *p;
struct extattr_set_file_args *uap;
static int
extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname,
struct iovec *iovp, unsigned iovcnt, struct proc *p)
{
struct nameidata nd;
struct mount *mp;
struct uio auio;
struct iovec *iov, *needfree = NULL, aiov[UIO_SMALLIOV];
char attrname[EXTATTR_MAXNAMELEN];
u_int iovlen, cnt;
int error, i;
error = copyin(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN);
if (error)
if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
return (error);
NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
SCARG(uap, path), p);
if ((error = namei(&nd)) != 0)
return(error);
if ((error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH)) != 0) {
NDFREE(&nd, 0);
return (error);
}
iovlen = uap->iovcnt * sizeof(struct iovec);
if (uap->iovcnt > UIO_SMALLIOV) {
if (uap->iovcnt > UIO_MAXIOV) {
VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
iovlen = iovcnt * sizeof(struct iovec);
if (iovcnt > UIO_SMALLIOV) {
if (iovcnt > UIO_MAXIOV) {
error = EINVAL;
goto done;
}
@ -3785,15 +3781,15 @@ extattr_set_file(p, uap)
} else
iov = aiov;
auio.uio_iov = iov;
auio.uio_iovcnt = uap->iovcnt;
auio.uio_iovcnt = iovcnt;
auio.uio_rw = UIO_WRITE;
auio.uio_segflg = UIO_USERSPACE;
auio.uio_procp = p;
auio.uio_offset = 0;
if ((error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen)))
if ((error = copyin((caddr_t)iovp, (caddr_t)iov, iovlen)))
goto done;
auio.uio_resid = 0;
for (i = 0; i < uap->iovcnt; i++) {
for (i = 0; i < iovcnt; i++) {
if (iov->iov_len > INT_MAX - auio.uio_resid) {
error = EINVAL;
goto done;
@ -3802,112 +3798,255 @@ extattr_set_file(p, uap)
iov++;
}
cnt = auio.uio_resid;
error = VOP_SETEXTATTR(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
&auio, p->p_cred->pc_ucred, p);
error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio,
p->p_cred->pc_ucred, p);
cnt -= auio.uio_resid;
p->p_retval[0] = cnt;
done:
if (needfree)
FREE(needfree, M_IOV);
NDFREE(&nd, 0);
VOP_UNLOCK(vp, 0, p);
vn_finished_write(mp);
return (error);
}
int
extattr_set_file(p, uap)
struct proc *p;
struct extattr_set_file_args *uap;
{
struct nameidata nd;
char attrname[EXTATTR_MAXNAMELEN];
int error;
error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
NULL);
if (error)
return (error);
NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
if ((error = namei(&nd)) != 0)
return (error);
NDFREE(&nd, NDF_ONLY_PNBUF);
error = extattr_set_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
SCARG(uap, iovp), SCARG(uap, iovcnt), p);
vrele(nd.ni_vp);
return (error);
}
int
extattr_set_fd(p, uap)
struct proc *p;
struct extattr_set_fd_args *uap;
{
struct file *fp;
char attrname[EXTATTR_MAXNAMELEN];
int error;
error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
NULL);
if (error)
return (error);
if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
return (error);
error = extattr_set_vp((struct vnode *)fp->f_data,
SCARG(uap, attrnamespace), attrname, SCARG(uap, iovp),
SCARG(uap, iovcnt), p);
return (error);
}
/*
* Syscall to get a named extended attribute on a file or directory.
* Accepts attribute name, and a uio structure pointing to a buffer for the
* data. The uio is consumed in the style of readv(). The real work
* happens in VOP_GETEXTATTR();
* extattr_get_vp(): Get a named extended attribute on a file or directory
*
* Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
* kernelspace string pointer "attrname",
* userspace iovec array pointer "iovp", unsigned int iovcnt,
* proc "p"
* Returns: 0 on success, an error number otherwise
* Locks: none
* References: vp must be a valid reference for the duration of the call
*/
static int
extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname,
struct iovec *iovp, unsigned iovcnt, struct proc *p)
{
struct uio auio;
struct iovec *iov, *needfree = NULL, aiov[UIO_SMALLIOV];
u_int iovlen, cnt;
int error, i;
VOP_LEASE(vp, p, p->p_ucred, LEASE_READ);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
iovlen = iovcnt * sizeof (struct iovec);
if (iovcnt > UIO_SMALLIOV) {
if (iovcnt > UIO_MAXIOV) {
error = EINVAL;
goto done;
}
MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
needfree = iov;
} else
iov = aiov;
auio.uio_iov = iov;
auio.uio_iovcnt = iovcnt;
auio.uio_rw = UIO_READ;
auio.uio_segflg = UIO_USERSPACE;
auio.uio_procp = p;
auio.uio_offset = 0;
if ((error = copyin((caddr_t)iovp, (caddr_t)iov, iovlen)))
goto done;
auio.uio_resid = 0;
for (i = 0; i < iovcnt; i++) {
if (iov->iov_len > INT_MAX - auio.uio_resid) {
error = EINVAL;
goto done;
}
auio.uio_resid += iov->iov_len;
iov++;
}
cnt = auio.uio_resid;
error = VOP_GETEXTATTR(vp, attrnamespace, attrname, &auio,
p->p_cred->pc_ucred, p);
cnt -= auio.uio_resid;
p->p_retval[0] = cnt;
done:
if (needfree)
FREE(needfree, M_IOV);
VOP_UNLOCK(vp, 0, p);
return (error);
}
int
extattr_get_file(p, uap)
struct proc *p;
struct extattr_get_file_args *uap;
{
struct nameidata nd;
struct uio auio;
struct iovec *iov, *needfree, aiov[UIO_SMALLIOV];
char attrname[EXTATTR_MAXNAMELEN];
u_int iovlen, cnt;
int error, i;
int error;
error = copyin(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN);
error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
NULL);
if (error)
return (error);
NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
SCARG(uap, path), p);
NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
if ((error = namei(&nd)) != 0)
return (error);
iovlen = uap->iovcnt * sizeof (struct iovec);
if (uap->iovcnt > UIO_SMALLIOV) {
if (uap->iovcnt > UIO_MAXIOV) {
NDFREE(&nd, 0);
return (EINVAL);
}
MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
needfree = iov;
} else {
iov = aiov;
needfree = NULL;
}
auio.uio_iov = iov;
auio.uio_iovcnt = uap->iovcnt;
auio.uio_rw = UIO_READ;
auio.uio_segflg = UIO_USERSPACE;
auio.uio_procp = p;
auio.uio_offset = 0;
if ((error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen)))
goto done;
auio.uio_resid = 0;
for (i = 0; i < uap->iovcnt; i++) {
if (iov->iov_len > INT_MAX - auio.uio_resid) {
error = EINVAL;
goto done;
}
auio.uio_resid += iov->iov_len;
iov++;
}
cnt = auio.uio_resid;
error = VOP_GETEXTATTR(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
&auio, p->p_cred->pc_ucred, p);
cnt -= auio.uio_resid;
p->p_retval[0] = cnt;
done:
if (needfree)
FREE(needfree, M_IOV);
NDFREE(&nd, 0);
return(error);
NDFREE(&nd, NDF_ONLY_PNBUF);
error = extattr_get_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
SCARG(uap, iovp), SCARG(uap, iovcnt), p);
vrele(nd.ni_vp);
return (error);
}
int
extattr_get_fd(p, uap)
struct proc *p;
struct extattr_get_fd_args *uap;
{
struct file *fp;
char attrname[EXTATTR_MAXNAMELEN];
int error;
error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
NULL);
if (error)
return (error);
if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
return (error);
error = extattr_get_vp((struct vnode *)fp->f_data,
SCARG(uap, attrnamespace), attrname, SCARG(uap, iovp),
SCARG(uap, iovcnt), p);
return (error);
}
/*
* Syscall to delete a named extended attribute from a file or directory.
* Accepts attribute name. The real work happens in VOP_SETEXTATTR().
* extattr_delete_vp(): Delete a named extended attribute on a file or
* directory
*
* Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
* kernelspace string pointer "attrname", proc "p"
* Returns: 0 on success, an error number otherwise
* Locks: none
* References: vp must be a valid reference for the duration of the call
*/
static int
extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname,
struct proc *p)
{
struct mount *mp;
int error;
if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
return (error);
VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL,
p->p_cred->pc_ucred, p);
VOP_UNLOCK(vp, 0, p);
vn_finished_write(mp);
return (error);
}
int
extattr_delete_file(p, uap)
struct proc *p;
struct extattr_delete_file_args *uap;
{
struct mount *mp;
struct nameidata nd;
char attrname[EXTATTR_MAXNAMELEN];
int error;
int error;
error = copyin(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN);
error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
NULL);
if (error)
return(error);
NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
SCARG(uap, path), p);
NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
if ((error = namei(&nd)) != 0)
return(error);
if ((error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH)) != 0) {
NDFREE(&nd, 0);
return (error);
}
error = VOP_SETEXTATTR(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
NULL, p->p_cred->pc_ucred, p);
NDFREE(&nd, 0);
vn_finished_write(mp);
NDFREE(&nd, NDF_ONLY_PNBUF);
error = extattr_delete_vp(nd.ni_vp, SCARG(uap, attrnamespace),
attrname, p);
vrele(nd.ni_vp);
return(error);
}
int
extattr_delete_fd(p, uap)
struct proc *p;
struct extattr_delete_fd_args *uap;
{
struct file *fp;
char attrname[EXTATTR_MAXNAMELEN];
int error;
error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
NULL);
if (error)
return (error);
if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
return (error);
error = extattr_delete_vp((struct vnode *)fp->f_data,
SCARG(uap, attrnamespace), attrname, p);
return (error);
}

View File

@ -57,14 +57,19 @@
struct iovec;
__BEGIN_DECLS
int extattrctl(const char *path, int cmd, const char *filename,
int attrnamespace, const char *attrname);
int extattr_delete_file(const char *path, int attrnamespace,
const char *attrname);
int extattr_get_file(const char *path, int attrnamespace,
const char *attrname, struct iovec *iovp, unsigned iovcnt);
int extattr_set_file(const char *path, int attrnamespace,
const char *attrname, struct iovec *iovp, unsigned iovcnt);
int extattrctl(const char *_path, int _cmd, const char *_filename,
int _attrnamespace, const char *_attrname);
int extattr_delete_fd(int _fd, int _attrnamespace, const char *_attrname);
int extattr_delete_file(const char *_path, int _attrnamespace,
const char *_attrname);
int extattr_get_fd(int _fd, int _attrnamespace, const char *_attrname,
struct iovec *_iovp, unsigned _iovcnt);
int extattr_get_file(const char *_path, int _attrnamespace,
const char *_attrname, struct iovec *_iovp, unsigned _iovcnt);
int extattr_set_fd(int _fd, int _attrnamespace, const char *_attrname,
struct iovec *_iovp, unsigned _iovcnt);
int extattr_set_file(const char *_path, int _attrnamespace,
const char *_attrname, struct iovec *_iovp, unsigned _iovcnt);
__END_DECLS
#endif /* !_KERNEL */