FreeBSD/sys/ufs/ufs/ufs_extattr.c
/*
 * Real work associated with retrieving a named attribute--assumes that
 * the attribute lock has already been grabbed.
 */
Real work associated with retrieving a named attribute--assumes that
the attribute lock has already been grabbed.
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);
	if (uio != NULL && uio->uio_offset != 0)
		return (ENXIO);
	base_offset = sizeof(struct ufs_extattr_fileheader) +
	    ip->i_number * (sizeof(struct ufs_extattr_header) +
	    attribute->uele_fileheader.uef_size);
	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);
	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;
	if ((ueh.ueh_flags & UFS_EXTATTR_ATTR_FLAG_INUSE) == 0) {
		error = ENOATTR;
		goto vopunlock_exit;
	}
	if (ueh.ueh_i_gen != ip->i_gen) {
		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;
	}
	if (ueh.ueh_len > attribute->uele_fileheader.uef_size) {
		error = ENXIO;
		goto vopunlock_exit;
	}
	if (size != NULL)
		*size = ueh.ueh_len;
	if (uio != NULL) {
		uio->uio_offset = base_offset + sizeof(struct
		    ufs_extattr_header);
		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);
}
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 ) ; if ( uio != NULL && uio -> uio_offset != 0 ) return ( ENXIO ) ; base_offset = sizeof ( struct ufs_extattr_fileheader ) + ip -> i_number * ( sizeof ( struct ufs_extattr_header ) + attribute -> uele_fileheader . uef_size ) ; 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 ) ; 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 ; if ( ( ueh . ueh_flags & UFS_EXTATTR_ATTR_FLAG_INUSE ) == 0 ) { error = ENOATTR ; goto vopunlock_exit ; } if ( ueh . ueh_i_gen != ip -> i_gen ) { printf ( " \n " , mp -> mnt_stat . f_mntonname , ueh . ueh_i_gen , ( uintmax_t ) ip -> i_gen ) ; error = ENOATTR ; goto vopunlock_exit ; } if ( ueh . ueh_len > attribute -> uele_fileheader . uef_size ) { error = ENXIO ; goto vopunlock_exit ; } if ( size != NULL ) * size = ueh . ueh_len ; if ( uio != NULL ) { uio -> uio_offset = base_offset + sizeof ( struct ufs_extattr_header ) ; 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 ) ; }
Real work associated with retrieving a named attribute--assumes that
 the attribute lock has already been grabbed.
Real work associated with retrieving a named attribute -- assumes that the attribute lock has already been grabbed .
/*
	 * 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.
	 */ /*
	 * Find base offset of header in file based on file header size, and
	 * data header size + maximum data size, indexed by inode number.
	 */ /*
	 * Read in the data header to see if the data is defined, and if so
	 * how much.
	 */ /*
	 * 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.
	 */ /* Defined? */ /* Valid for the current inode generation? */ /*
		 * 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.
		 */ /* Local size consistency check. */ /* Return full data size if caller requested it. */ /* Return data if the caller requested it. */ /* Allow for offset into the attribute data. */ /*
		 * Figure out maximum to transfer -- use buffer size and
		 * local data limit.
		 */