예제 #1
0
static int
_xfs_deleteextattr(struct vop_deleteextattr_args *ap)
/*
vop_deleteextattr {
	IN struct vnode *a_vp;
	IN int a_attrnamespace;
	IN const char *a_name;
	IN struct ucred *a_cred;
	IN struct thread *a_td;
};
*/
{
	int error, xfs_flags;

	if (ap->a_vp->v_type == VCHR)
		return (EOPNOTSUPP);

	if (ap->a_name[0] == '\0')
		return (EINVAL);

	error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
	    ap->a_cred, ap->a_td, VWRITE);
	if (error)
		return (error);

	xfs_flags = 0;
	if (ap->a_attrnamespace & EXTATTR_NAMESPACE_USER)
		xfs_flags |= ATTR_KERNORMALS;
	if (ap->a_attrnamespace & EXTATTR_NAMESPACE_SYSTEM)
		xfs_flags |= ATTR_KERNROOTLS;

	XVOP_ATTR_REMOVE(VPTOXFSVP(ap->a_vp), ap->a_name, xfs_flags,
	    ap->a_cred, error);
	return (error);
}
예제 #2
0
/*
 * Vnode operation to retrieve a named extended attribute.
 */
int
ffs_ea_get(void *v)
{
	struct vop_getextattr_args *ap = v;
	struct inode *ip;
	struct fs *fs;
	unsigned char *p;
	int error, ealen;

	ip = VTOI(ap->a_vp);
	fs = ip->i_fs;

	/*
	 * Validate the vnode. It has to be a FFS2 file, directory, or symlink.
	 */
	if (ip->i_fs->fs_magic != FS_UFS2_MAGIC)
		return (EOPNOTSUPP);

	if (ap->a_vp->v_type != VREG &&
	    ap->a_vp->v_type != VDIR &&
	    ap->a_vp->v_type != VLNK)
		return (EOPNOTSUPP);

	/*
	 * Validate credentials, read in the inode's extended attributes area,
	 * and make sure there is no attribute with the same name.
	 */

	error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace, ap->a_cred,
	    ap->a_p, IREAD);
	if (error)
		return (error);

	error = ffs_ea_iget(ap->a_vp, ap->a_cred, ap->a_p);
	if (error)
		return (error);

	/* Call ffs_ea_find() to do the real job. */
	ealen = ffs_ea_find(ip, ap->a_attrnamespace, ap->a_name, NULL, &p);
	if (ealen >= 0) {
		error = 0;
		if (ap->a_size != NULL)
			*ap->a_size = ealen;
		else if (ap->a_uio != NULL)
			error = uiomove(p, ealen, ap->a_uio);
	} else
		error = ENOATTR;

	
	(void) ffs_ea_iput(ap->a_vp, 0, ap->a_cred, ap->a_p);

	return (error);
}
예제 #3
0
static int
_xfs_setextattr(struct vop_setextattr_args *ap)
/*
vop_setextattr {
	IN struct vnode *a_vp;
	IN int a_attrnamespace;
	IN const char *a_name;
	INOUT struct uio *a_uio;
	IN struct ucred *a_cred;
	IN struct thread *a_td;
};
*/
{
	char *val;
	size_t vallen;
	int error, xfs_flags;

	if (ap->a_vp->v_type == VCHR)
		return (EOPNOTSUPP);

	if (ap->a_uio == NULL)
		return (EINVAL);
	vallen = ap->a_uio->uio_resid;
	if (vallen > ATTR_MAX_VALUELEN)
		return (EOVERFLOW);

	if (ap->a_name[0] == '\0')
		return (EINVAL);

	error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
	    ap->a_cred, ap->a_td, VWRITE);
	if (error)
		return (error);

	xfs_flags = 0;
	if (ap->a_attrnamespace & EXTATTR_NAMESPACE_USER)
		xfs_flags |= ATTR_KERNORMALS;
	if (ap->a_attrnamespace & EXTATTR_NAMESPACE_SYSTEM)
		xfs_flags |= ATTR_KERNROOTLS;

	val = (char *)kmem_zalloc(vallen, KM_SLEEP);
	if (val == NULL)
		return (ENOMEM);
	error = uiomove(val, (int)vallen, ap->a_uio);
	if (error)
		goto err_out;

	XVOP_ATTR_SET(VPTOXFSVP(ap->a_vp), ap->a_name, val, vallen, xfs_flags,
	    ap->a_cred, error);
err_out:
	kmem_free(val, vallen);
	return(error);
}
예제 #4
0
static int
_xfs_getextattr(
	struct vop_getextattr_args /* {
		struct vnode *a_vp;
		int a_attrnamespace;
		const char *a_name;
		struct uio *a_uio;
		size_t *a_size;
		struct ucred *a_cred;
		struct thread *a_td;
	} */ *ap)
{
	int error;
	char *value;
	int size;

	error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
	    ap->a_cred, ap->a_td, VREAD);
        if (error)
		return (error);

	size = ATTR_MAX_VALUELEN;
	value = (char *)kmem_zalloc(size, KM_SLEEP);
	if (value == NULL)
		return (ENOMEM);

	XVOP_ATTR_GET(VPTOXFSVP(ap->a_vp), ap->a_name, value, &size, 1,
	    ap->a_cred, error);

	if (ap->a_uio != NULL) {
		if (ap->a_uio->uio_iov->iov_len < size)
			error = ERANGE;
		else
			uiomove(value, size, ap->a_uio);
	}

	if (ap->a_size != NULL)
		*ap->a_size = size;

	kmem_free(value, ATTR_MAX_VALUELEN);
	return (error);
}		
예제 #5
0
/*
 * Real work associated with retrieving a named attribute--assumes that
 * the attribute lock has already been grabbed.
 */
static int
ufs_extattr_get(struct vnode *vp, int attrnamespace, const char *name,
    struct uio *uio, size_t *size, struct ucred *cred, struct thread *td)
{
	struct ufs_extattr_list_entry *attribute;
	struct ufs_extattr_header ueh;
	struct iovec local_aiov;
	struct uio local_aio;
	struct mount *mp = vp->v_mount;
	struct ufsmount *ump = VFSTOUFS(mp);
	struct inode *ip = VTOI(vp);
	off_t base_offset;
	size_t len, old_len;
	int error = 0;

	if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED))
		return (EOPNOTSUPP);

	if (strlen(name) == 0)
		return (EINVAL);

	error = extattr_check_cred(vp, attrnamespace, cred, td, VREAD);
	if (error)
		return (error);

	attribute = ufs_extattr_find_attr(ump, attrnamespace, name);
	if (!attribute)
		return (ENOATTR);

	/*
	 * Allow only offsets of zero to encourage the read/replace
	 * extended attribute semantic.  Otherwise we can't guarantee
	 * atomicity, as we don't provide locks for extended attributes.
	 */
	if (uio != NULL && uio->uio_offset != 0)
		return (ENXIO);

	/*
	 * Find base offset of header in file based on file header size, and
	 * data header size + maximum data size, indexed by inode number.
	 */
	base_offset = sizeof(struct ufs_extattr_fileheader) +
	    ip->i_number * (sizeof(struct ufs_extattr_header) +
	    attribute->uele_fileheader.uef_size);

	/*
	 * Read in the data header to see if the data is defined, and if so
	 * how much.
	 */
	bzero(&ueh, sizeof(struct ufs_extattr_header));
	local_aiov.iov_base = (caddr_t) &ueh;
	local_aiov.iov_len = sizeof(struct ufs_extattr_header);
	local_aio.uio_iov = &local_aiov;
	local_aio.uio_iovcnt = 1;
	local_aio.uio_rw = UIO_READ;
	local_aio.uio_segflg = UIO_SYSSPACE;
	local_aio.uio_td = td;
	local_aio.uio_offset = base_offset;
	local_aio.uio_resid = sizeof(struct ufs_extattr_header);
	
	/*
	 * Acquire locks.
	 *
	 * Don't need to get a lock on the backing file if the getattr is
	 * being applied to the backing file, as the lock is already held.
	 */
	if (attribute->uele_backing_vnode != vp)
		vn_lock(attribute->uele_backing_vnode, LK_SHARED | LK_RETRY);

	error = VOP_READ(attribute->uele_backing_vnode, &local_aio,
	    IO_NODELOCKED, ump->um_extattr.uepm_ucred);
	if (error)
		goto vopunlock_exit;

	/* Defined? */
	if ((ueh.ueh_flags & UFS_EXTATTR_ATTR_FLAG_INUSE) == 0) {
		error = ENOATTR;
		goto vopunlock_exit;
	}

	/* Valid for the current inode generation? */
	if (ueh.ueh_i_gen != ip->i_gen) {
		/*
		 * The inode itself has a different generation number
		 * than the attribute data.  For now, the best solution
		 * is to coerce this to undefined, and let it get cleaned
		 * up by the next write or extattrctl clean.
		 */
		printf("ufs_extattr_get (%s): inode number inconsistency (%d, %ju)\n",
		    mp->mnt_stat.f_mntonname, ueh.ueh_i_gen, (uintmax_t)ip->i_gen);
		error = ENOATTR;
		goto vopunlock_exit;
	}

	/* Local size consistency check. */
	if (ueh.ueh_len > attribute->uele_fileheader.uef_size) {
		error = ENXIO;
		goto vopunlock_exit;
	}

	/* Return full data size if caller requested it. */
	if (size != NULL)
		*size = ueh.ueh_len;

	/* Return data if the caller requested it. */
	if (uio != NULL) {
		/* Allow for offset into the attribute data. */
		uio->uio_offset = base_offset + sizeof(struct
		    ufs_extattr_header);

		/*
		 * Figure out maximum to transfer -- use buffer size and
		 * local data limit.
		 */
		len = MIN(uio->uio_resid, ueh.ueh_len);
		old_len = uio->uio_resid;
		uio->uio_resid = len;

		error = VOP_READ(attribute->uele_backing_vnode, uio,
		    IO_NODELOCKED, ump->um_extattr.uepm_ucred);
		if (error)
			goto vopunlock_exit;

		uio->uio_resid = old_len - (len - uio->uio_resid);
	}

vopunlock_exit:

	if (uio != NULL)
		uio->uio_offset = 0;

	if (attribute->uele_backing_vnode != vp)
		VOP_UNLOCK(attribute->uele_backing_vnode, 0);

	return (error);
}
예제 #6
0
/*
 * Real work associated with removing an extended attribute from a vnode.
 * Assumes the attribute lock has already been grabbed.
 */
static int
ufs_extattr_rm(struct vnode *vp, int attrnamespace, const char *name,
    struct ucred *cred, struct thread *td)
{
	struct ufs_extattr_list_entry *attribute;
	struct ufs_extattr_header ueh;
	struct iovec local_aiov;
	struct uio local_aio;
	struct mount *mp = vp->v_mount;
	struct ufsmount *ump = VFSTOUFS(mp);
	struct inode *ip = VTOI(vp);
	off_t base_offset;
	int error = 0, ioflag;

	if (vp->v_mount->mnt_flag & MNT_RDONLY)  
		return (EROFS);
	if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED))
		return (EOPNOTSUPP);
	if (!ufs_extattr_valid_attrname(attrnamespace, name))
		return (EINVAL);

	error = extattr_check_cred(vp, attrnamespace, cred, td, VWRITE);
	if (error)
		return (error);

	attribute = ufs_extattr_find_attr(ump, attrnamespace, name);
	if (!attribute)
		return (ENOATTR);

	/*
	 * Find base offset of header in file based on file header size, and
	 * data header size + maximum data size, indexed by inode number.
	 */
	base_offset = sizeof(struct ufs_extattr_fileheader) +
	    ip->i_number * (sizeof(struct ufs_extattr_header) +
	    attribute->uele_fileheader.uef_size);

	/*
	 * Check to see if currently defined.
	 */
	bzero(&ueh, sizeof(struct ufs_extattr_header));

	local_aiov.iov_base = (caddr_t) &ueh;
	local_aiov.iov_len = sizeof(struct ufs_extattr_header);
	local_aio.uio_iov = &local_aiov;
	local_aio.uio_iovcnt = 1;
	local_aio.uio_rw = UIO_READ;
	local_aio.uio_segflg = UIO_SYSSPACE;
	local_aio.uio_td = td;
	local_aio.uio_offset = base_offset;
	local_aio.uio_resid = sizeof(struct ufs_extattr_header);

	/*
	 * Don't need to get the lock on the backing vnode if the vnode we're
	 * modifying is it, as we already hold the lock.
	 */
	if (attribute->uele_backing_vnode != vp)
		vn_lock(attribute->uele_backing_vnode, LK_EXCLUSIVE | LK_RETRY);

	error = VOP_READ(attribute->uele_backing_vnode, &local_aio,
	    IO_NODELOCKED, ump->um_extattr.uepm_ucred);
	if (error)
		goto vopunlock_exit;

	/* Defined? */
	if ((ueh.ueh_flags & UFS_EXTATTR_ATTR_FLAG_INUSE) == 0) {
		error = ENOATTR;
		goto vopunlock_exit;
	}

	/* Valid for the current inode generation? */
	if (ueh.ueh_i_gen != ip->i_gen) {
		/*
		 * The inode itself has a different generation number than
		 * the attribute data.  For now, the best solution is to
		 * coerce this to undefined, and let it get cleaned up by
		 * the next write or extattrctl clean.
		 */
		printf("ufs_extattr_rm (%s): inode number inconsistency (%d, %jd)\n",
		    mp->mnt_stat.f_mntonname, ueh.ueh_i_gen, (intmax_t)ip->i_gen);
		error = ENOATTR;
		goto vopunlock_exit;
	}

	/* Flag it as not in use. */
	ueh.ueh_flags = 0;
	ueh.ueh_len = 0;

	local_aiov.iov_base = (caddr_t) &ueh;
	local_aiov.iov_len = sizeof(struct ufs_extattr_header);
	local_aio.uio_iov = &local_aiov;
	local_aio.uio_iovcnt = 1;
	local_aio.uio_rw = UIO_WRITE;
	local_aio.uio_segflg = UIO_SYSSPACE;
	local_aio.uio_td = td;
	local_aio.uio_offset = base_offset;
	local_aio.uio_resid = sizeof(struct ufs_extattr_header);

	ioflag = IO_NODELOCKED;
	if (ufs_extattr_sync)
		ioflag |= IO_SYNC;
	error = VOP_WRITE(attribute->uele_backing_vnode, &local_aio, ioflag,
	    ump->um_extattr.uepm_ucred);
	if (error)
		goto vopunlock_exit;

	if (local_aio.uio_resid != 0)
		error = ENXIO;

vopunlock_exit:
	VOP_UNLOCK(attribute->uele_backing_vnode, 0);

	return (error);
}
예제 #7
0
/*
 * Real work associated with setting a vnode's extended attributes;
 * assumes that the attribute lock has already been grabbed.
 */
static int
ufs_extattr_set(struct vnode *vp, int attrnamespace, const char *name,
    struct uio *uio, struct ucred *cred, struct thread *td)
{
	struct ufs_extattr_list_entry *attribute;
	struct ufs_extattr_header ueh;
	struct iovec local_aiov;
	struct uio local_aio;
	struct mount *mp = vp->v_mount;
	struct ufsmount *ump = VFSTOUFS(mp);
	struct inode *ip = VTOI(vp);
	off_t base_offset;
	int error = 0, ioflag;

	if (vp->v_mount->mnt_flag & MNT_RDONLY)
		return (EROFS);
	if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED))
		return (EOPNOTSUPP);
	if (!ufs_extattr_valid_attrname(attrnamespace, name))
		return (EINVAL);

	error = extattr_check_cred(vp, attrnamespace, cred, td, VWRITE);
	if (error)
		return (error);

	attribute = ufs_extattr_find_attr(ump, attrnamespace, name);
	if (!attribute)
		return (ENOATTR);

	/*
	 * Early rejection of invalid offsets/length.
	 * Reject: any offset but 0 (replace)
	 *	 Any size greater than attribute size limit
 	 */
	if (uio->uio_offset != 0 ||
	    uio->uio_resid > attribute->uele_fileheader.uef_size)
		return (ENXIO);

	/*
	 * Find base offset of header in file based on file header size, and
	 * data header size + maximum data size, indexed by inode number.
	 */
	base_offset = sizeof(struct ufs_extattr_fileheader) +
	    ip->i_number * (sizeof(struct ufs_extattr_header) +
	    attribute->uele_fileheader.uef_size);

	/*
	 * Write out a data header for the data.
	 */
	ueh.ueh_len = uio->uio_resid;
	ueh.ueh_flags = UFS_EXTATTR_ATTR_FLAG_INUSE;
	ueh.ueh_i_gen = ip->i_gen;
	local_aiov.iov_base = (caddr_t) &ueh;
	local_aiov.iov_len = sizeof(struct ufs_extattr_header);
	local_aio.uio_iov = &local_aiov;
	local_aio.uio_iovcnt = 1;
	local_aio.uio_rw = UIO_WRITE;
	local_aio.uio_segflg = UIO_SYSSPACE;
	local_aio.uio_td = td;
	local_aio.uio_offset = base_offset;
	local_aio.uio_resid = sizeof(struct ufs_extattr_header);

	/*
	 * Acquire locks.
	 *
	 * Don't need to get a lock on the backing file if the setattr is
	 * being applied to the backing file, as the lock is already held.
	 */
	if (attribute->uele_backing_vnode != vp)
		vn_lock(attribute->uele_backing_vnode, LK_EXCLUSIVE | LK_RETRY);

	ioflag = IO_NODELOCKED;
	if (ufs_extattr_sync)
		ioflag |= IO_SYNC;
	error = VOP_WRITE(attribute->uele_backing_vnode, &local_aio, ioflag,
	    ump->um_extattr.uepm_ucred);
	if (error)
		goto vopunlock_exit;

	if (local_aio.uio_resid != 0) {
		error = ENXIO;
		goto vopunlock_exit;
	}

	/*
	 * Write out user data.
	 */
	uio->uio_offset = base_offset + sizeof(struct ufs_extattr_header);

	ioflag = IO_NODELOCKED;
	if (ufs_extattr_sync)
		ioflag |= IO_SYNC;
	error = VOP_WRITE(attribute->uele_backing_vnode, uio, ioflag,
	    ump->um_extattr.uepm_ucred);

vopunlock_exit:
	uio->uio_offset = 0;

	if (attribute->uele_backing_vnode != vp)
		VOP_UNLOCK(attribute->uele_backing_vnode, 0);

	return (error);
}
예제 #8
0
static int
_xfs_listextattr(
	struct vop_listextattr_args /* {
		struct vnode *a_vp;
		int a_attrnamespace;
		struct uio *a_uio;
		size_t *a_size;
		struct ucred *a_cred;
		struct thread *a_td;
	} */ *ap)
{
	int error;
	char *buf = NULL;
	int buf_len = 0;
	attrlist_cursor_kern_t  cursor = { 0 };
	int i;
	char name_len;
	int attrnames_len = 0;
	int xfs_flags = ATTR_KERNAMELS;

	error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
	    ap->a_cred, ap->a_td, VREAD);
        if (error)
		return (error);

	if (ap->a_attrnamespace & EXTATTR_NAMESPACE_USER)
		xfs_flags |= ATTR_KERNORMALS;

	if (ap->a_attrnamespace & EXTATTR_NAMESPACE_SYSTEM)
		xfs_flags |= ATTR_KERNROOTLS;

	if (ap->a_uio == NULL || ap->a_uio->uio_iov[0].iov_base == NULL) {
		xfs_flags |= ATTR_KERNOVAL;
		buf_len = 0;
	} else {
		buf = ap->a_uio->uio_iov[0].iov_base;
		buf_len = ap->a_uio->uio_iov[0].iov_len;
	}

	XVOP_ATTR_LIST(VPTOXFSVP(ap->a_vp), buf, buf_len, xfs_flags,
		    &cursor, ap->a_cred, error);
	if (error < 0) {
		attrnames_len = -error;
		error = 0;
	}
	if (buf == NULL)
		goto done;

	/*
	 * extattr_list expects a list of names.  Each list
	 * entry consists of one byte for the name length, followed
	 * by the name (not null terminated)
	 */
	name_len=0;
	for(i=attrnames_len-1; i > 0 ; --i) {
		buf[i] = buf[i-1];
		if (buf[i])
			++name_len;
		else {
			buf[i] = name_len;
			name_len = 0;
		}
	} 
	buf[0] = name_len;

	if (ap->a_uio != NULL)
		ap->a_uio->uio_resid -= attrnames_len;

done:
	if (ap->a_size != NULL)
		*ap->a_size = attrnames_len;

	return (error);
}
예제 #9
0
/*
 * Vnode operation to set a named attribute.
 */
int
ffs_ea_set(void *v)
{
	struct vop_setextattr_args *ap = v;
	struct inode *ip;
	struct fs *fs;
	u_int32_t prefixlen, bodylen, entrysize, pad1, pad2, pesize;
	int error;
	unsigned int peoffset;
	unsigned char *eae, *p, *peaddr;

	ip = VTOI(ap->a_vp);
	fs = ip->i_fs;

	/*
	 * Validate the vnode. It has to be a FFS2 file, directory, or symlink,
	 * and must reside in a writable file system.
	 */

	if (ip->i_fs->fs_magic != FS_UFS2_MAGIC)
		return (EOPNOTSUPP);

	if (ap->a_vp->v_type != VREG &&
	    ap->a_vp->v_type != VDIR &&
	    ap->a_vp->v_type != VLNK)
		return (EOPNOTSUPP);

	if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
		return (EROFS);

	/* The attribute name must be at least one byte long. */
	if (strlen(ap->a_name) == 0)
		return (EINVAL);

	/*
	 * Validate credentials, read in the inode's extended attributes area,
	 * and make sure there is no attribute with the same name.
	 */

	error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace, ap->a_cred,
	    ap->a_p, IWRITE);
	if (error)
		return (error);

	error = ffs_ea_iget(ap->a_vp, ap->a_cred, ap->a_p);
	if (error)
		return (error);

	/*
	 * Check whether an entry for the given attribute already exists, and
	 * get its parameters.
	 */
	peaddr = NULL;
	pesize = peoffset = 0;
	(void) ffs_ea_find(ip, ap->a_attrnamespace, ap->a_name, &peaddr, NULL);
	if (peaddr != NULL) {
		/*
		 * Get absolute offset of entry. Make sure it is within the
		 * extended attribute area.
		 */
		peoffset = peaddr - ip->i_ea_area;
		if (peoffset >= ip->i_ea_len) {
			(void) ffs_ea_iput(ap->a_vp, 0, ap->a_cred, ap->a_p);
			return (EINVAL);
		}

		/*
		 * Get size of entry. Make sure it is a sane value.
		 */
		bcopy(peaddr, &pesize, sizeof(pesize));
		if (peoffset + pesize > ip->i_ea_len) {
			(void) ffs_ea_iput(ap->a_vp, 0, ap->a_cred, ap->a_p);
			return (EINVAL);
		}
	}

	/*
	 * Start constructing the extended attribute entry in memory. An entry
	 * is made up of the following fields, laid out in top/bottom order:
	 *
	 *   +-----------------------------+---------+
	 * | | 1. Record size              | 4 bytes |
	 * | | 2. Attribute name space     | 1 byte  |
	 * | | 3. Length of second padding | 1 byte  |
	 * | | 4. Length of attribute name | 1 byte  |
	 * | +-----------------------------+---------+
	 * | | 5. Attribute name           |
	 * | | 6. First padding            |
	 * | | 7. Attribute content        |
	 * V | 8. Second padding           |
	 *   +-----------------------------+
	 *
	 * The first 5 fields have their length computed in 'prefixlen'. Based
	 * on this value, the first padding is calculated. Likewise, the 7th
	 * field (the attribute content) has its length computed in 'bodylen',
	 * based on which the second padding is calculated. The complete entry
	 * length is computed in 'entrysize'.
	 */

	prefixlen = sizeof(u_int32_t) + 3 + strlen(ap->a_name);
	pad1 = 8 - (prefixlen % 8);
	if (pad1 == 8)
		pad1 = 0;

	bodylen = ap->a_uio->uio_resid;
	pad2 = 8 - (bodylen % 8);
	if (pad2 == 8)
		pad2 = 0;

	entrysize = prefixlen + pad1 + bodylen + pad2;

	/*
	 * Make sure we're not crossing the limit for extended attributes.
	 * Account for the released space of previous entries (which will be
	 * removed in favour of the new one).
	 */
	if (ip->i_ea_len + entrysize - pesize > NXADDR * fs->fs_bsize) {
		ffs_ea_iput(ap->a_vp, 0, ap->a_cred, ap->a_p);
		return (ENOSPC);
	}

	eae = malloc(ip->i_ea_len + entrysize - pesize, M_TEMP,
	    M_WAITOK | M_CANFAIL);
	if (eae == NULL) {
		ffs_ea_iput(ap->a_vp, 0, ap->a_cred, ap->a_p);
		return (ENOMEM);
	}

	/* Find out where to store the entry in the extended attribute area. */
	if (peaddr != NULL) {
		if (pesize == entrysize) {
			/* Previous entry of same size. Just overwrite it. */
			bcopy(ip->i_ea_area, eae, ip->i_ea_len);
			p = eae + peoffset;
		} else {
			/*
			 * Previous entry of different size. Skip it when
			 * copying contents, and insert new entry at the end.
			 */
			bcopy(ip->i_ea_area, eae, peoffset);
			bcopy(peaddr + pesize, eae + peoffset,
			    ip->i_ea_len - peoffset - pesize);
			p = eae + ip->i_ea_len - pesize;
		}
	} else {
		/* New entry. Insert at the end. */
		bcopy(ip->i_ea_area, eae, ip->i_ea_len);
		p = eae + ip->i_ea_len;
	}

	/* Prefix (1st-5th fields). */
	bcopy(&entrysize, p, sizeof(entrysize));
	p += sizeof(entrysize);
	*p++ = ap->a_attrnamespace;
	*p++ = pad2;
	*p++ = strlen(ap->a_name);
	bcopy(ap->a_name, p, strlen(ap->a_name));
	p += strlen(ap->a_name);

	/* Paddings and content (6th-8th fields). */
	bzero(p, pad1);
	p += pad1;
	error = uiomove(p, bodylen, ap->a_uio);
	if (error) {
		free(eae, M_TEMP);
		ffs_ea_iput(ap->a_vp, 0, ap->a_cred, ap->a_p);
		return (error);
	}
	p += bodylen;
	bzero(p, pad2);

	/*
	 * Swap old extended attributes area with new one, and write it out.
	 */

	free(ip->i_ea_area, M_TEMP);
	ip->i_ea_area = eae;
	ip->i_ea_len += entrysize - pesize;

	return (ffs_ea_iput(ap->a_vp, 1, ap->a_cred, ap->a_p));
}
예제 #10
0
/*
 * Vnode operation to retrieve extended attributes on a vnode.
 */
int
ffs_ea_list(void *v)
{
	struct vop_listextattr_args *ap = v;
	struct inode *ip;
	struct fs *fs;
	unsigned char *p, *pend, *pnext;
	u_int32_t rz;
	int error, attrnamelen;

	ip = VTOI(ap->a_vp);
	fs = ip->i_fs;

	/*
	 * Validate the vnode. It has to be a FFS2 file, directory, or symlink.
	 */
	if (ip->i_fs->fs_magic != FS_UFS2_MAGIC)
		return (EOPNOTSUPP);

	if (ap->a_vp->v_type != VREG &&
	    ap->a_vp->v_type != VDIR &&
	    ap->a_vp->v_type != VLNK)
		return (EOPNOTSUPP);

	/*
	 * Validate credentials and read in the inode's extended attributes
	 * area.
	 */

	error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace, ap->a_cred,
	    ap->a_p, IREAD);
	if (error)
		return (error);

	error = ffs_ea_iget(ap->a_vp, ap->a_cred, ap->a_p);
	if (error)
		return (error);

	error = 0;
	if (ap->a_size != NULL)
		*ap->a_size = 0;

	pend = ip->i_ea_area + ip->i_ea_len;

	/*
	 * See comment in ffs_ea_set() for a detailed description of how
	 * extended attribute entries are laid out.
	 */
	for(p = (unsigned char *)ip->i_ea_area; p < pend; p = pnext) {
		/*
		 * Read in the record size, set pointer to next entry. Make
		 * sure this is an entry belonging to the attribute space we
		 * are interesting in, and copy the attribute name over.
		 */
		bcopy(p, &rz, sizeof(rz));
		pnext = p + rz;
		if (pnext > pend)
			break; /* Stepping out of extended attribute area. */

		p += sizeof(rz);
		if (*p++ != ap->a_attrnamespace)
			continue;

		p++; /* Skip length of second padding. */
		attrnamelen = (int)*p;

		if (ap->a_size != NULL)
			*ap->a_size += attrnamelen + 1;
		else if (ap->a_uio != NULL) {
			error = uiomove(p, attrnamelen + 1, ap->a_uio);
			if (error) {
				ffs_ea_iput(ap->a_vp, 0, ap->a_cred, ap->a_p);
				return (error);
			}
		}
	}

	return (ffs_ea_iput(ap->a_vp, 0, ap->a_cred, ap->a_p));
}
예제 #11
0
/*
 * Vnode operation to remove a named attribute.
 */
int
ffs_ea_del(void *v)
{
	struct vop_deleteextattr_args *ap = v;
	struct inode *ip;
	int error, olen;
	u_int32_t esize;
	unsigned int eoffset;
	unsigned char *eae, *eaddr;

	ip = VTOI(ap->a_vp);

	/*
	 * Validate the vnode. It has to be a FFS2 file, directory, or symlink,
	 * and must reside in a writable file system.
	 */

	if (ip->i_fs->fs_magic != FS_UFS2_MAGIC)
		return (EOPNOTSUPP);

	if (ap->a_vp->v_type != VREG &&
	    ap->a_vp->v_type != VDIR &&
	    ap->a_vp->v_type != VLNK)
		return (EOPNOTSUPP);

	if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
		return (EROFS);

	/* The attribute name must be at least one byte long. */
	if (strlen(ap->a_name) == 0)
		return (EINVAL);

	/*
	 * Validate credentials, read in the inode's extended attributes area,
	 * and make sure there is an attribute with the given name.
	 */

	error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace, ap->a_cred,
	    ap->a_p, IWRITE);
	if (error)
		return (error);

	error = ffs_ea_iget(ap->a_vp, ap->a_cred, ap->a_p);
	if (error)
		return (error);

	olen = ffs_ea_find(ip, ap->a_attrnamespace, ap->a_name, &eaddr, NULL);
	if (olen == -1) {
		/* No such attribute. */
		(void) ffs_ea_iput(ap->a_vp, 0, ap->a_cred, ap->a_p);
		return (ENOATTR);
	}

	/*
	 * Get absolute offset of entry. Make sure it is within the extended
	 * attribute area.
	 */

	eoffset = eaddr - ip->i_ea_area;
	if (eoffset >= ip->i_ea_len) {
		(void) ffs_ea_iput(ap->a_vp, 0, ap->a_cred, ap->a_p);
		return (EINVAL);
	}

	/*
	 * Get size of entry. Make sure it is a sane value.
	 */

	bcopy(eaddr, &esize, sizeof(esize));
	if (eoffset + esize > ip->i_ea_len) {
		(void) ffs_ea_iput(ap->a_vp, 0, ap->a_cred, ap->a_p);
		return (EINVAL);
	}

	/*
	 * Allocate a new extended attribute area and copy the contents over,
	 * skipping the entry found.
	 */

	eae = malloc(ip->i_ea_len - esize, M_TEMP, M_WAITOK | M_CANFAIL);
	if (eae == NULL) {
		(void) ffs_ea_iput(ap->a_vp, 0, ap->a_cred, ap->a_p);
		return (ENOMEM);
	}

	bcopy(ip->i_ea_area, eae, eoffset);
	bcopy(eaddr + esize, eae + eoffset, ip->i_ea_len - eoffset - esize);

	free(ip->i_ea_area, M_TEMP);
	ip->i_ea_area = eae;
	ip->i_ea_len -= esize;

	return (ffs_ea_iput(ap->a_vp, 1, ap->a_cred, ap->a_p));
}