Home | History | Annotate | Line # | Download | only in ffs
ffs_extattr.c revision 1.1
      1  1.1  christos /*	$NetBSD: ffs_extattr.c,v 1.1 2020/04/18 19:18:34 christos Exp $	*/
      2  1.1  christos 
      3  1.1  christos /*-
      4  1.1  christos  * SPDX-License-Identifier: (BSD-2-Clause-FreeBSD AND BSD-3-Clause)
      5  1.1  christos  *
      6  1.1  christos  * Copyright (c) 2002, 2003 Networks Associates Technology, Inc.
      7  1.1  christos  * All rights reserved.
      8  1.1  christos  *
      9  1.1  christos  * This software was developed for the FreeBSD Project by Marshall
     10  1.1  christos  * Kirk McKusick and Network Associates Laboratories, the Security
     11  1.1  christos  * Research Division of Network Associates, Inc. under DARPA/SPAWAR
     12  1.1  christos  * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS
     13  1.1  christos  * research program
     14  1.1  christos  *
     15  1.1  christos  * Redistribution and use in source and binary forms, with or without
     16  1.1  christos  * modification, are permitted provided that the following conditions
     17  1.1  christos  * are met:
     18  1.1  christos  * 1. Redistributions of source code must retain the above copyright
     19  1.1  christos  *    notice, this list of conditions and the following disclaimer.
     20  1.1  christos  * 2. Redistributions in binary form must reproduce the above copyright
     21  1.1  christos  *    notice, this list of conditions and the following disclaimer in the
     22  1.1  christos  *    documentation and/or other materials provided with the distribution.
     23  1.1  christos  *
     24  1.1  christos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     25  1.1  christos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     26  1.1  christos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     27  1.1  christos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     28  1.1  christos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     29  1.1  christos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     30  1.1  christos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     31  1.1  christos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     32  1.1  christos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     33  1.1  christos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     34  1.1  christos  * SUCH DAMAGE.
     35  1.1  christos  *
     36  1.1  christos  * Copyright (c) 1982, 1986, 1989, 1993
     37  1.1  christos  *	The Regents of the University of California.  All rights reserved.
     38  1.1  christos  *
     39  1.1  christos  * Redistribution and use in source and binary forms, with or without
     40  1.1  christos  * modification, are permitted provided that the following conditions
     41  1.1  christos  * are met:
     42  1.1  christos  * 1. Redistributions of source code must retain the above copyright
     43  1.1  christos  *    notice, this list of conditions and the following disclaimer.
     44  1.1  christos  * 2. Redistributions in binary form must reproduce the above copyright
     45  1.1  christos  *    notice, this list of conditions and the following disclaimer in the
     46  1.1  christos  *    documentation and/or other materials provided with the distribution.
     47  1.1  christos  * 3. Neither the name of the University nor the names of its contributors
     48  1.1  christos  *    may be used to endorse or promote products derived from this software
     49  1.1  christos  *    without specific prior written permission.
     50  1.1  christos  *
     51  1.1  christos  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     52  1.1  christos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     53  1.1  christos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     54  1.1  christos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     55  1.1  christos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     56  1.1  christos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     57  1.1  christos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     58  1.1  christos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     59  1.1  christos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     60  1.1  christos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     61  1.1  christos  * SUCH DAMAGE.
     62  1.1  christos  *
     63  1.1  christos  *	from: @(#)ufs_readwrite.c	8.11 (Berkeley) 5/8/95
     64  1.1  christos  * from: $FreeBSD: .../ufs/ufs_readwrite.c,v 1.96 2002/08/12 09:22:11 phk ...
     65  1.1  christos  *	@(#)ffs_vnops.c	8.15 (Berkeley) 5/14/95
     66  1.1  christos  */
     67  1.1  christos 
     68  1.1  christos #include <sys/cdefs.h>
     69  1.1  christos __KERNEL_RCSID(0, "$NetBSD: ffs_extattr.c,v 1.1 2020/04/18 19:18:34 christos Exp $");
     70  1.1  christos 
     71  1.1  christos #if defined(_KERNEL_OPT)
     72  1.1  christos #include "opt_ffs.h"
     73  1.1  christos #include "opt_wapbl.h"
     74  1.1  christos #endif
     75  1.1  christos 
     76  1.1  christos #include <sys/param.h>
     77  1.1  christos #include <sys/systm.h>
     78  1.1  christos #include <sys/resourcevar.h>
     79  1.1  christos #include <sys/kernel.h>
     80  1.1  christos #include <sys/file.h>
     81  1.1  christos #include <sys/stat.h>
     82  1.1  christos #include <sys/buf.h>
     83  1.1  christos #include <sys/event.h>
     84  1.1  christos #include <sys/extattr.h>
     85  1.1  christos #include <sys/kauth.h>
     86  1.1  christos #include <sys/proc.h>
     87  1.1  christos #include <sys/mount.h>
     88  1.1  christos #include <sys/vnode.h>
     89  1.1  christos #include <sys/malloc.h>
     90  1.1  christos #include <sys/pool.h>
     91  1.1  christos #include <sys/signalvar.h>
     92  1.1  christos #include <sys/kauth.h>
     93  1.1  christos #include <sys/wapbl.h>
     94  1.1  christos 
     95  1.1  christos #include <miscfs/fifofs/fifo.h>
     96  1.1  christos #include <miscfs/genfs/genfs.h>
     97  1.1  christos #include <miscfs/specfs/specdev.h>
     98  1.1  christos 
     99  1.1  christos #include <ufs/ufs/inode.h>
    100  1.1  christos #include <ufs/ufs/dir.h>
    101  1.1  christos #include <ufs/ufs/ufs_extern.h>
    102  1.1  christos #include <ufs/ufs/ufsmount.h>
    103  1.1  christos #include <ufs/ufs/ufs_wapbl.h>
    104  1.1  christos 
    105  1.1  christos #include <ufs/ffs/fs.h>
    106  1.1  christos #include <ufs/ffs/ffs_extern.h>
    107  1.1  christos 
    108  1.1  christos #include <uvm/uvm.h>
    109  1.1  christos 
    110  1.1  christos #define ALIGNED_TO(ptr, s)  \
    111  1.1  christos     (((uintptr_t)(ptr) & (_Alignof(s) - 1)) == 0)
    112  1.1  christos #define uoff_t uintmax_t
    113  1.1  christos #define ITOFS(ip) (ip)->i_fs
    114  1.1  christos #define i_din2 i_din.ffs2_din
    115  1.1  christos #define VI_LOCK(vp)		mutex_enter((vp)->v_interlock)
    116  1.1  christos #define VI_UNLOCK(vp)		mutex_exit((vp)->v_interlock)
    117  1.1  christos #define UFS_INODE_SET_FLAG(ip, f)	((ip)->i_flag |= (f))
    118  1.1  christos #define ASSERT_VOP_ELOCKED(vp, m)	KASSERT(VOP_ISLOCKED(vp))
    119  1.1  christos #define I_IS_UFS2(ip)		(ITOFS(ip)->fs_magic == FS_UFS2_MAGIC)
    120  1.1  christos #define	lblktosize(fs, o)	ffs_lblktosize(fs, o)
    121  1.1  christos #define	lblkno(fs, o)		ffs_lblkno(fs, o)
    122  1.1  christos #define	blkoff(fs, o)		ffs_blkoff(fs, o)
    123  1.1  christos #define	sblksize(fs, o, lbn)	ffs_sblksize(fs, o, lbn)
    124  1.1  christos typedef mode_t accmode_t;	/* so that it breaks soon */
    125  1.1  christos typedef daddr_t ufs_lbn_t;
    126  1.1  christos #define msleep(chan, mtx, pri, wmesg, timeo) \
    127  1.1  christos     mtsleep((chan), (pri), (wmesg), (timeo), *(mtx))
    128  1.1  christos #define vm_page_count_severe()		0
    129  1.1  christos #define buf_dirty_count_severe()	0
    130  1.1  christos #define BA_CLRBUF B_CLRBUF
    131  1.1  christos #define IO_ASYNC 0
    132  1.1  christos #define vfs_bio_brelse(bp, ioflag) 	brelse(bp, 0)
    133  1.1  christos #define vfs_bio_clrbuf(bp) 		clrbuf(bp)
    134  1.1  christos #define vfs_bio_set_flags(bp, ioflag) 	__nothing
    135  1.1  christos 
    136  1.1  christos /*
    137  1.1  christos  * Credential check based on process requesting service, and per-attribute
    138  1.1  christos  * permissions.
    139  1.1  christos  */
    140  1.1  christos static int
    141  1.1  christos ffs_extattr_check_cred(struct vnode *vp, int attrnamespace, kauth_cred_t cred,
    142  1.1  christos     accmode_t accmode)
    143  1.1  christos {
    144  1.1  christos 	/*
    145  1.1  christos 	 * Kernel-invoked always succeeds.
    146  1.1  christos 	 */
    147  1.1  christos 	if (cred == NOCRED)
    148  1.1  christos 		return 0;
    149  1.1  christos 
    150  1.1  christos 	/*
    151  1.1  christos 	 * Do not allow privileged processes in jail to directly manipulate
    152  1.1  christos 	 * system attributes.
    153  1.1  christos 	 */
    154  1.1  christos 	switch (attrnamespace) {
    155  1.1  christos 	case EXTATTR_NAMESPACE_SYSTEM:
    156  1.1  christos 		/* Potentially with privs */
    157  1.1  christos 		return EPERM;
    158  1.1  christos 	case EXTATTR_NAMESPACE_USER:
    159  1.1  christos 		return VOP_ACCESS(vp, accmode, cred);
    160  1.1  christos 	default:
    161  1.1  christos 		return EPERM;
    162  1.1  christos 	}
    163  1.1  christos }
    164  1.1  christos /*
    165  1.1  christos  * Extended attribute area reading.
    166  1.1  christos  */
    167  1.1  christos static int
    168  1.1  christos ffs_extread(struct vnode *vp, struct uio *uio, int ioflag)
    169  1.1  christos {
    170  1.1  christos 	struct inode *ip;
    171  1.1  christos 	struct ufs2_dinode *dp;
    172  1.1  christos 	struct fs *fs;
    173  1.1  christos 	struct buf *bp;
    174  1.1  christos 	ufs_lbn_t lbn, nextlbn;
    175  1.1  christos 	off_t bytesinfile;
    176  1.1  christos 	long size, xfersize, blkoffset;
    177  1.1  christos 	ssize_t orig_resid;
    178  1.1  christos 	int error;
    179  1.1  christos 
    180  1.1  christos 	ip = VTOI(vp);
    181  1.1  christos 	fs = ITOFS(ip);
    182  1.1  christos 	dp = ip->i_din2;
    183  1.1  christos 
    184  1.1  christos #ifdef INVARIANTS
    185  1.1  christos 	if (uio->uio_rw != UIO_READ || fs->fs_magic != FS_UFS2_MAGIC)
    186  1.1  christos 		panic("ffs_extread: mode");
    187  1.1  christos 
    188  1.1  christos #endif
    189  1.1  christos 	orig_resid = uio->uio_resid;
    190  1.1  christos 	KASSERT(orig_resid >= 0);
    191  1.1  christos 	if (orig_resid == 0)
    192  1.1  christos 		return (0);
    193  1.1  christos 	KASSERT(uio->uio_offset >= 0);
    194  1.1  christos 
    195  1.1  christos 	for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) {
    196  1.1  christos 		if ((bytesinfile = dp->di_extsize - uio->uio_offset) <= 0)
    197  1.1  christos 			break;
    198  1.1  christos 		lbn = lblkno(fs, uio->uio_offset);
    199  1.1  christos 		nextlbn = lbn + 1;
    200  1.1  christos 
    201  1.1  christos 		/*
    202  1.1  christos 		 * size of buffer.  The buffer representing the
    203  1.1  christos 		 * end of the file is rounded up to the size of
    204  1.1  christos 		 * the block type ( fragment or full block,
    205  1.1  christos 		 * depending ).
    206  1.1  christos 		 */
    207  1.1  christos 		size = sblksize(fs, dp->di_extsize, lbn);
    208  1.1  christos 		blkoffset = blkoff(fs, uio->uio_offset);
    209  1.1  christos 
    210  1.1  christos 		/*
    211  1.1  christos 		 * The amount we want to transfer in this iteration is
    212  1.1  christos 		 * one FS block less the amount of the data before
    213  1.1  christos 		 * our startpoint (duh!)
    214  1.1  christos 		 */
    215  1.1  christos 		xfersize = fs->fs_bsize - blkoffset;
    216  1.1  christos 
    217  1.1  christos 		/*
    218  1.1  christos 		 * But if we actually want less than the block,
    219  1.1  christos 		 * or the file doesn't have a whole block more of data,
    220  1.1  christos 		 * then use the lesser number.
    221  1.1  christos 		 */
    222  1.1  christos 		if (uio->uio_resid < xfersize)
    223  1.1  christos 			xfersize = uio->uio_resid;
    224  1.1  christos 		if (bytesinfile < xfersize)
    225  1.1  christos 			xfersize = bytesinfile;
    226  1.1  christos 
    227  1.1  christos 		if (lblktosize(fs, nextlbn) >= dp->di_extsize) {
    228  1.1  christos 			/*
    229  1.1  christos 			 * Don't do readahead if this is the end of the info.
    230  1.1  christos 			 */
    231  1.1  christos 			error = bread(vp, -1 - lbn, size, 0, &bp);
    232  1.1  christos 		} else {
    233  1.1  christos 			/*
    234  1.1  christos 			 * If we have a second block, then
    235  1.1  christos 			 * fire off a request for a readahead
    236  1.1  christos 			 * as well as a read. Note that the 4th and 5th
    237  1.1  christos 			 * arguments point to arrays of the size specified in
    238  1.1  christos 			 * the 6th argument.
    239  1.1  christos 			 */
    240  1.1  christos 			u_int nextsize = sblksize(fs, dp->di_extsize, nextlbn);
    241  1.1  christos 
    242  1.1  christos 			nextlbn = -1 - nextlbn;
    243  1.1  christos 			error = breadn(vp, -1 - lbn,
    244  1.1  christos 			    size, &nextlbn, &nextsize, 1, 0, &bp);
    245  1.1  christos 		}
    246  1.1  christos 		if (error) {
    247  1.1  christos 			brelse(bp, 0);
    248  1.1  christos 			bp = NULL;
    249  1.1  christos 			break;
    250  1.1  christos 		}
    251  1.1  christos 
    252  1.1  christos 		/*
    253  1.1  christos 		 * We should only get non-zero b_resid when an I/O error
    254  1.1  christos 		 * has occurred, which should cause us to break above.
    255  1.1  christos 		 * However, if the short read did not cause an error,
    256  1.1  christos 		 * then we want to ensure that we do not uiomove bad
    257  1.1  christos 		 * or uninitialized data.
    258  1.1  christos 		 */
    259  1.1  christos 		size -= bp->b_resid;
    260  1.1  christos 		if (size < xfersize) {
    261  1.1  christos 			if (size == 0)
    262  1.1  christos 				break;
    263  1.1  christos 			xfersize = size;
    264  1.1  christos 		}
    265  1.1  christos 
    266  1.1  christos 		error = uiomove((char *)bp->b_data + blkoffset,
    267  1.1  christos 					(int)xfersize, uio);
    268  1.1  christos 		if (error)
    269  1.1  christos 			break;
    270  1.1  christos 		vfs_bio_brelse(bp, ioflag);
    271  1.1  christos 	}
    272  1.1  christos 
    273  1.1  christos 	/*
    274  1.1  christos 	 * This can only happen in the case of an error
    275  1.1  christos 	 * because the loop above resets bp to NULL on each iteration
    276  1.1  christos 	 * and on normal completion has not set a new value into it.
    277  1.1  christos 	 * so it must have come from a 'break' statement
    278  1.1  christos 	 */
    279  1.1  christos 	if (bp != NULL)
    280  1.1  christos 		vfs_bio_brelse(bp, ioflag);
    281  1.1  christos 	return (error);
    282  1.1  christos }
    283  1.1  christos /*
    284  1.1  christos  * Extended attribute area writing.
    285  1.1  christos  */
    286  1.1  christos static int
    287  1.1  christos ffs_extwrite(struct vnode *vp, struct uio *uio, int ioflag, kauth_cred_t ucred)
    288  1.1  christos {
    289  1.1  christos 	struct inode *ip;
    290  1.1  christos 	struct ufs2_dinode *dp;
    291  1.1  christos 	struct fs *fs;
    292  1.1  christos 	struct buf *bp;
    293  1.1  christos 	ufs_lbn_t lbn;
    294  1.1  christos 	off_t osize;
    295  1.1  christos 	ssize_t resid;
    296  1.1  christos 	int blkoffset, error, flags, size, xfersize;
    297  1.1  christos 
    298  1.1  christos 	ip = VTOI(vp);
    299  1.1  christos 	fs = ITOFS(ip);
    300  1.1  christos 	dp = ip->i_din2;
    301  1.1  christos 
    302  1.1  christos #ifdef INVARIANTS
    303  1.1  christos 	if (uio->uio_rw != UIO_WRITE || fs->fs_magic != FS_UFS2_MAGIC)
    304  1.1  christos 		panic("ffs_extwrite: mode");
    305  1.1  christos #endif
    306  1.1  christos 
    307  1.1  christos 	if (ioflag & IO_APPEND)
    308  1.1  christos 		uio->uio_offset = dp->di_extsize;
    309  1.1  christos 	KASSERT(uio->uio_offset >= 0);
    310  1.1  christos 	if ((uoff_t)uio->uio_offset + uio->uio_resid >
    311  1.1  christos 	    UFS_NXADDR * fs->fs_bsize)
    312  1.1  christos 		return (EFBIG);
    313  1.1  christos 
    314  1.1  christos 	resid = uio->uio_resid;
    315  1.1  christos 	osize = dp->di_extsize;
    316  1.1  christos 	flags = IO_EXT;
    317  1.1  christos 	if (ioflag & IO_SYNC)
    318  1.1  christos 		flags |= IO_SYNC;
    319  1.1  christos 
    320  1.1  christos 	if ((error = UFS_WAPBL_BEGIN(vp->v_mount)) != 0)
    321  1.1  christos 		return error;
    322  1.1  christos 
    323  1.1  christos 	for (error = 0; uio->uio_resid > 0;) {
    324  1.1  christos 		lbn = lblkno(fs, uio->uio_offset);
    325  1.1  christos 		blkoffset = blkoff(fs, uio->uio_offset);
    326  1.1  christos 		xfersize = fs->fs_bsize - blkoffset;
    327  1.1  christos 		if (uio->uio_resid < xfersize)
    328  1.1  christos 			xfersize = uio->uio_resid;
    329  1.1  christos 
    330  1.1  christos 		/*
    331  1.1  christos 		 * We must perform a read-before-write if the transfer size
    332  1.1  christos 		 * does not cover the entire buffer.
    333  1.1  christos 		 */
    334  1.1  christos 		if (fs->fs_bsize > xfersize)
    335  1.1  christos 			flags |= BA_CLRBUF;
    336  1.1  christos 		else
    337  1.1  christos 			flags &= ~BA_CLRBUF;
    338  1.1  christos 		error = UFS_BALLOC(vp, uio->uio_offset, xfersize,
    339  1.1  christos 		    ucred, flags, &bp);
    340  1.1  christos 		if (error != 0)
    341  1.1  christos 			break;
    342  1.1  christos 		/*
    343  1.1  christos 		 * If the buffer is not valid we have to clear out any
    344  1.1  christos 		 * garbage data from the pages instantiated for the buffer.
    345  1.1  christos 		 * If we do not, a failed uiomove() during a write can leave
    346  1.1  christos 		 * the prior contents of the pages exposed to a userland
    347  1.1  christos 		 * mmap().  XXX deal with uiomove() errors a better way.
    348  1.1  christos 		 */
    349  1.1  christos 		if ((bp->b_flags & BC_NOCACHE) && fs->fs_bsize <= xfersize)
    350  1.1  christos 			vfs_bio_clrbuf(bp);
    351  1.1  christos 
    352  1.1  christos 		if (uio->uio_offset + xfersize > dp->di_extsize)
    353  1.1  christos 			dp->di_extsize = uio->uio_offset + xfersize;
    354  1.1  christos 
    355  1.1  christos 		size = sblksize(fs, dp->di_extsize, lbn) - bp->b_resid;
    356  1.1  christos 		if (size < xfersize)
    357  1.1  christos 			xfersize = size;
    358  1.1  christos 
    359  1.1  christos 		error =
    360  1.1  christos 		    uiomove((char *)bp->b_data + blkoffset, (int)xfersize, uio);
    361  1.1  christos 
    362  1.1  christos 		vfs_bio_set_flags(bp, ioflag);
    363  1.1  christos 
    364  1.1  christos 		/*
    365  1.1  christos 		 * If IO_SYNC each buffer is written synchronously.  Otherwise
    366  1.1  christos 		 * if we have a severe page deficiency write the buffer
    367  1.1  christos 		 * asynchronously.  Otherwise try to cluster, and if that
    368  1.1  christos 		 * doesn't do it then either do an async write (if O_DIRECT),
    369  1.1  christos 		 * or a delayed write (if not).
    370  1.1  christos 		 */
    371  1.1  christos 		if (ioflag & IO_SYNC) {
    372  1.1  christos 			(void)bwrite(bp);
    373  1.1  christos 		} else if (vm_page_count_severe() ||
    374  1.1  christos 			    buf_dirty_count_severe() ||
    375  1.1  christos 			    xfersize + blkoffset == fs->fs_bsize ||
    376  1.1  christos 			    (ioflag & (IO_ASYNC | IO_DIRECT)))
    377  1.1  christos 			bawrite(bp);
    378  1.1  christos 		else
    379  1.1  christos 			bdwrite(bp);
    380  1.1  christos 		if (error || xfersize == 0)
    381  1.1  christos 			break;
    382  1.1  christos 		UFS_INODE_SET_FLAG(ip, IN_CHANGE);
    383  1.1  christos 	}
    384  1.1  christos 	/*
    385  1.1  christos 	 * If we successfully wrote any data, and we are not the superuser
    386  1.1  christos 	 * we clear the setuid and setgid bits as a precaution against
    387  1.1  christos 	 * tampering.
    388  1.1  christos 	 */
    389  1.1  christos 	if ((ip->i_mode & (ISUID | ISGID)) && resid > uio->uio_resid && ucred) {
    390  1.1  christos 		ip->i_mode &= ~(ISUID | ISGID);
    391  1.1  christos 		dp->di_mode = ip->i_mode;
    392  1.1  christos 	}
    393  1.1  christos 	if (error) {
    394  1.1  christos 		if (ioflag & IO_UNIT) {
    395  1.1  christos 			(void)ffs_truncate(vp, osize,
    396  1.1  christos 			    IO_EXT | (ioflag&IO_SYNC), ucred);
    397  1.1  christos 			uio->uio_offset -= resid - uio->uio_resid;
    398  1.1  christos 			uio->uio_resid = resid;
    399  1.1  christos 		}
    400  1.1  christos 	} else if (resid > uio->uio_resid && (ioflag & IO_SYNC))
    401  1.1  christos 		error = ffs_update(vp, NULL, NULL, UPDATE_WAIT);
    402  1.1  christos 	UFS_WAPBL_END(vp->v_mount);
    403  1.1  christos 	return (error);
    404  1.1  christos }
    405  1.1  christos 
    406  1.1  christos /*
    407  1.1  christos  * Vnode operating to retrieve a named extended attribute.
    408  1.1  christos  *
    409  1.1  christos  * Locate a particular EA (nspace:name) in the area (ptr:length), and return
    410  1.1  christos  * the length of the EA, and possibly the pointer to the entry and to the data.
    411  1.1  christos  */
    412  1.1  christos static int
    413  1.1  christos ffs_findextattr(u_char *ptr, u_int length, int nspace, const char *name,
    414  1.1  christos     struct extattr **eapp, u_char **eac)
    415  1.1  christos {
    416  1.1  christos 	struct extattr *eap, *eaend;
    417  1.1  christos 	size_t nlen;
    418  1.1  christos 
    419  1.1  christos 	nlen = strlen(name);
    420  1.1  christos 	KASSERT(ALIGNED_TO(ptr, struct extattr));
    421  1.1  christos 	eap = (struct extattr *)ptr;
    422  1.1  christos 	eaend = (struct extattr *)(ptr + length);
    423  1.1  christos 	for (; eap < eaend; eap = EXTATTR_NEXT(eap)) {
    424  1.1  christos 		/* make sure this entry is complete */
    425  1.1  christos 		if (EXTATTR_NEXT(eap) > eaend)
    426  1.1  christos 			break;
    427  1.1  christos 		if (eap->ea_namespace != nspace || eap->ea_namelength != nlen
    428  1.1  christos 		    || memcmp(eap->ea_name, name, nlen) != 0)
    429  1.1  christos 			continue;
    430  1.1  christos 		if (eapp != NULL)
    431  1.1  christos 			*eapp = eap;
    432  1.1  christos 		if (eac != NULL)
    433  1.1  christos 			*eac = EXTATTR_CONTENT(eap);
    434  1.1  christos 		return (EXTATTR_CONTENT_SIZE(eap));
    435  1.1  christos 	}
    436  1.1  christos 	return (-1);
    437  1.1  christos }
    438  1.1  christos 
    439  1.1  christos static int
    440  1.1  christos ffs_rdextattr(u_char **p, struct vnode *vp, int extra)
    441  1.1  christos {
    442  1.1  christos 	struct inode *ip;
    443  1.1  christos 	struct ufs2_dinode *dp;
    444  1.1  christos 	struct fs *fs;
    445  1.1  christos 	struct uio luio;
    446  1.1  christos 	struct iovec liovec;
    447  1.1  christos 	u_int easize;
    448  1.1  christos 	int error;
    449  1.1  christos 	u_char *eae;
    450  1.1  christos 
    451  1.1  christos 	ip = VTOI(vp);
    452  1.1  christos 	fs = ITOFS(ip);
    453  1.1  christos 	dp = ip->i_din2;
    454  1.1  christos 	easize = dp->di_extsize;
    455  1.1  christos 	if ((uoff_t)easize + extra > UFS_NXADDR * fs->fs_bsize)
    456  1.1  christos 		return (EFBIG);
    457  1.1  christos 
    458  1.1  christos 	eae = malloc(easize + extra, M_TEMP, M_WAITOK);
    459  1.1  christos 
    460  1.1  christos 	liovec.iov_base = eae;
    461  1.1  christos 	liovec.iov_len = easize;
    462  1.1  christos 	luio.uio_iov = &liovec;
    463  1.1  christos 	luio.uio_iovcnt = 1;
    464  1.1  christos 	luio.uio_offset = 0;
    465  1.1  christos 	luio.uio_resid = easize;
    466  1.1  christos 	luio.uio_vmspace = vmspace_kernel();
    467  1.1  christos 	luio.uio_rw = UIO_READ;
    468  1.1  christos 
    469  1.1  christos 	error = ffs_extread(vp, &luio, IO_EXT | IO_SYNC);
    470  1.1  christos 	if (error) {
    471  1.1  christos 		free(eae, M_TEMP);
    472  1.1  christos 		return(error);
    473  1.1  christos 	}
    474  1.1  christos 	*p = eae;
    475  1.1  christos 	return (0);
    476  1.1  christos }
    477  1.1  christos 
    478  1.1  christos static void
    479  1.1  christos ffs_lock_ea(struct vnode *vp)
    480  1.1  christos {
    481  1.1  christos #if 0
    482  1.1  christos 	struct inode *ip;
    483  1.1  christos 
    484  1.1  christos 	ip = VTOI(vp);
    485  1.1  christos 	VI_LOCK(vp);
    486  1.1  christos 	while (ip->i_flag & IN_EA_LOCKED) {
    487  1.1  christos 		UFS_INODE_SET_FLAG(ip, IN_EA_LOCKWAIT);
    488  1.1  christos 		msleep(&ip->i_ea_refs, &vp->v_interlock, PINOD + 2, "ufs_ea",
    489  1.1  christos 		    0);
    490  1.1  christos 	}
    491  1.1  christos 	UFS_INODE_SET_FLAG(ip, IN_EA_LOCKED);
    492  1.1  christos 	VI_UNLOCK(vp);
    493  1.1  christos #endif
    494  1.1  christos }
    495  1.1  christos 
    496  1.1  christos static void
    497  1.1  christos ffs_unlock_ea(struct vnode *vp)
    498  1.1  christos {
    499  1.1  christos #if 0
    500  1.1  christos 	struct inode *ip;
    501  1.1  christos 
    502  1.1  christos 	ip = VTOI(vp);
    503  1.1  christos 	VI_LOCK(vp);
    504  1.1  christos 	if (ip->i_flag & IN_EA_LOCKWAIT)
    505  1.1  christos 		wakeup(&ip->i_ea_refs);
    506  1.1  christos 	ip->i_flag &= ~(IN_EA_LOCKED | IN_EA_LOCKWAIT);
    507  1.1  christos 	VI_UNLOCK(vp);
    508  1.1  christos #endif
    509  1.1  christos }
    510  1.1  christos 
    511  1.1  christos static int
    512  1.1  christos ffs_open_ea(struct vnode *vp, kauth_cred_t cred)
    513  1.1  christos {
    514  1.1  christos 	struct inode *ip;
    515  1.1  christos 	struct ufs2_dinode *dp;
    516  1.1  christos 	int error;
    517  1.1  christos 
    518  1.1  christos 	ip = VTOI(vp);
    519  1.1  christos 
    520  1.1  christos 	ffs_lock_ea(vp);
    521  1.1  christos 	if (ip->i_ea_area != NULL) {
    522  1.1  christos 		ip->i_ea_refs++;
    523  1.1  christos 		ffs_unlock_ea(vp);
    524  1.1  christos 		return (0);
    525  1.1  christos 	}
    526  1.1  christos 	dp = ip->i_din2;
    527  1.1  christos 	error = ffs_rdextattr(&ip->i_ea_area, vp, 0);
    528  1.1  christos 	if (error) {
    529  1.1  christos 		ffs_unlock_ea(vp);
    530  1.1  christos 		return (error);
    531  1.1  christos 	}
    532  1.1  christos 	ip->i_ea_len = dp->di_extsize;
    533  1.1  christos 	ip->i_ea_error = 0;
    534  1.1  christos 	ip->i_ea_refs++;
    535  1.1  christos 	ffs_unlock_ea(vp);
    536  1.1  christos 	return (0);
    537  1.1  christos }
    538  1.1  christos 
    539  1.1  christos /*
    540  1.1  christos  * Vnode extattr transaction commit/abort
    541  1.1  christos  */
    542  1.1  christos static int
    543  1.1  christos ffs_close_ea(struct vnode *vp, int commit, kauth_cred_t cred)
    544  1.1  christos {
    545  1.1  christos 	struct inode *ip;
    546  1.1  christos 	struct uio luio;
    547  1.1  christos 	struct iovec liovec;
    548  1.1  christos 	int error;
    549  1.1  christos 	struct ufs2_dinode *dp;
    550  1.1  christos 
    551  1.1  christos 	ip = VTOI(vp);
    552  1.1  christos 
    553  1.1  christos 	if (commit)
    554  1.1  christos 		KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
    555  1.1  christos 	else
    556  1.1  christos 		KASSERT(VOP_ISLOCKED(vp));
    557  1.1  christos 	ffs_lock_ea(vp);
    558  1.1  christos 	if (ip->i_ea_area == NULL) {
    559  1.1  christos 		ffs_unlock_ea(vp);
    560  1.1  christos 		return (EINVAL);
    561  1.1  christos 	}
    562  1.1  christos 	dp = ip->i_din2;
    563  1.1  christos 	error = ip->i_ea_error;
    564  1.1  christos 	if (commit && error == 0) {
    565  1.1  christos 		ASSERT_VOP_ELOCKED(vp, "ffs_close_ea commit");
    566  1.1  christos 		if (cred == NOCRED)
    567  1.1  christos 			cred =  lwp0.l_cred;
    568  1.1  christos 		liovec.iov_base = ip->i_ea_area;
    569  1.1  christos 		liovec.iov_len = ip->i_ea_len;
    570  1.1  christos 		luio.uio_iov = &liovec;
    571  1.1  christos 		luio.uio_iovcnt = 1;
    572  1.1  christos 		luio.uio_offset = 0;
    573  1.1  christos 		luio.uio_resid = ip->i_ea_len;
    574  1.1  christos 		luio.uio_vmspace = vmspace_kernel();
    575  1.1  christos 		luio.uio_rw = UIO_WRITE;
    576  1.1  christos 		if ((error = UFS_WAPBL_BEGIN(vp->v_mount)) != 0) {
    577  1.1  christos 			ffs_unlock_ea(vp);
    578  1.1  christos 			return error;
    579  1.1  christos 		}
    580  1.1  christos 
    581  1.1  christos 		/* XXX: I'm not happy about truncating to zero size */
    582  1.1  christos 		if (ip->i_ea_len < dp->di_extsize)
    583  1.1  christos 			error = ffs_truncate(vp, 0, IO_EXT, cred);
    584  1.1  christos 		error = ffs_extwrite(vp, &luio, IO_EXT | IO_SYNC, cred);
    585  1.1  christos 		UFS_WAPBL_END(vp->v_mount);
    586  1.1  christos 	}
    587  1.1  christos 	if (--ip->i_ea_refs == 0) {
    588  1.1  christos 		free(ip->i_ea_area, M_TEMP);
    589  1.1  christos 		ip->i_ea_area = NULL;
    590  1.1  christos 		ip->i_ea_len = 0;
    591  1.1  christos 		ip->i_ea_error = 0;
    592  1.1  christos 	}
    593  1.1  christos 	ffs_unlock_ea(vp);
    594  1.1  christos 	return (error);
    595  1.1  christos }
    596  1.1  christos 
    597  1.1  christos /*
    598  1.1  christos  * Vnode extattr strategy routine for fifos.
    599  1.1  christos  *
    600  1.1  christos  * We need to check for a read or write of the external attributes.
    601  1.1  christos  * Otherwise we just fall through and do the usual thing.
    602  1.1  christos  */
    603  1.1  christos int
    604  1.1  christos ffsext_strategy(void *v)
    605  1.1  christos {
    606  1.1  christos 	struct vop_strategy_args /* {
    607  1.1  christos 		struct vnodeop_desc *a_desc;
    608  1.1  christos 		struct vnode *a_vp;
    609  1.1  christos 		struct buf *a_bp;
    610  1.1  christos 	} */ *ap = v;
    611  1.1  christos 	struct vnode *vp;
    612  1.1  christos 	daddr_t lbn;
    613  1.1  christos 
    614  1.1  christos 	vp = ap->a_vp;
    615  1.1  christos 	lbn = ap->a_bp->b_lblkno;
    616  1.1  christos 	if (I_IS_UFS2(VTOI(vp)) && lbn < 0 && lbn >= -UFS_NXADDR)
    617  1.1  christos 		return ufs_strategy(ap);
    618  1.1  christos 	if (vp->v_type == VFIFO)
    619  1.1  christos 		return vn_fifo_bypass(ap);
    620  1.1  christos 	panic("spec nodes went here");
    621  1.1  christos }
    622  1.1  christos 
    623  1.1  christos /*
    624  1.1  christos  * Vnode extattr transaction commit/abort
    625  1.1  christos  */
    626  1.1  christos int
    627  1.1  christos ffs_openextattr(void *v)
    628  1.1  christos {
    629  1.1  christos 	struct vop_openextattr_args /* {
    630  1.1  christos 		struct vnode *a_vp;
    631  1.1  christos 		kauth_cred_t a_cred;
    632  1.1  christos 		struct proc *a_p;
    633  1.1  christos 	} */ *ap = v;
    634  1.1  christos 	struct inode *ip = VTOI(ap->a_vp);
    635  1.1  christos 	struct fs *fs = ip->i_fs;
    636  1.1  christos 
    637  1.1  christos 	/* Not supported for UFS1 file systems. */
    638  1.1  christos 	if (fs->fs_magic == FS_UFS1_MAGIC)
    639  1.1  christos 		return (EOPNOTSUPP);
    640  1.1  christos 
    641  1.1  christos 	if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK)
    642  1.1  christos 		return (EOPNOTSUPP);
    643  1.1  christos 
    644  1.1  christos 	return (ffs_open_ea(ap->a_vp, ap->a_cred));
    645  1.1  christos }
    646  1.1  christos 
    647  1.1  christos /*
    648  1.1  christos  * Vnode extattr transaction commit/abort
    649  1.1  christos  */
    650  1.1  christos int
    651  1.1  christos ffs_closeextattr(void *v)
    652  1.1  christos {
    653  1.1  christos 	struct vop_closeextattr_args /* {
    654  1.1  christos 		struct vnode *a_vp;
    655  1.1  christos 		int a_commit;
    656  1.1  christos 		kauth_cred_t a_cred;
    657  1.1  christos 		struct proc *a_p;
    658  1.1  christos 	} */ *ap = v;
    659  1.1  christos 	struct inode *ip = VTOI(ap->a_vp);
    660  1.1  christos 	struct fs *fs = ip->i_fs;
    661  1.1  christos 
    662  1.1  christos 	/* Not supported for UFS1 file systems. */
    663  1.1  christos 	if (fs->fs_magic == FS_UFS1_MAGIC)
    664  1.1  christos 		return (EOPNOTSUPP);
    665  1.1  christos 
    666  1.1  christos 	if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK)
    667  1.1  christos 		return (EOPNOTSUPP);
    668  1.1  christos 
    669  1.1  christos 	if (ap->a_commit && (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY))
    670  1.1  christos 		return (EROFS);
    671  1.1  christos 
    672  1.1  christos 	return (ffs_close_ea(ap->a_vp, ap->a_commit, ap->a_cred));
    673  1.1  christos }
    674  1.1  christos 
    675  1.1  christos /*
    676  1.1  christos  * Vnode operation to retrieve a named extended attribute.
    677  1.1  christos  */
    678  1.1  christos int
    679  1.1  christos ffs_getextattr(void *v)
    680  1.1  christos {
    681  1.1  christos 	struct vop_getextattr_args /* {
    682  1.1  christos 		struct vnode *a_vp;
    683  1.1  christos 		int a_attrnamespace;
    684  1.1  christos 		const char *a_name;
    685  1.1  christos 		struct uio *a_uio;
    686  1.1  christos 		size_t *a_size;
    687  1.1  christos 		kauth_cred_t a_cred;
    688  1.1  christos 		struct proc *a_p;
    689  1.1  christos 	} */ *ap = v;
    690  1.1  christos 	struct vnode *vp = ap->a_vp;
    691  1.1  christos 	struct inode *ip = VTOI(vp);
    692  1.1  christos 	struct fs *fs = ip->i_fs;
    693  1.1  christos 
    694  1.1  christos 	KASSERT(VOP_ISLOCKED(vp));
    695  1.1  christos 	if (fs->fs_magic == FS_UFS1_MAGIC) {
    696  1.1  christos 		return ufs_getextattr(ap);
    697  1.1  christos 	}
    698  1.1  christos 
    699  1.1  christos 	u_char *eae, *p;
    700  1.1  christos 	unsigned easize;
    701  1.1  christos 	int error, ealen;
    702  1.1  christos 
    703  1.1  christos 	if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK)
    704  1.1  christos 		return (EOPNOTSUPP);
    705  1.1  christos 
    706  1.1  christos 	error = ffs_extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
    707  1.1  christos 	    ap->a_cred, VREAD);
    708  1.1  christos 	if (error)
    709  1.1  christos 		return (error);
    710  1.1  christos 
    711  1.1  christos 	error = ffs_open_ea(ap->a_vp, ap->a_cred);
    712  1.1  christos 	if (error)
    713  1.1  christos 		return (error);
    714  1.1  christos 
    715  1.1  christos 	eae = ip->i_ea_area;
    716  1.1  christos 	easize = ip->i_ea_len;
    717  1.1  christos 
    718  1.1  christos 	ealen = ffs_findextattr(eae, easize, ap->a_attrnamespace, ap->a_name,
    719  1.1  christos 	    NULL, &p);
    720  1.1  christos 	if (ealen >= 0) {
    721  1.1  christos 		error = 0;
    722  1.1  christos 		if (ap->a_size != NULL)
    723  1.1  christos 			*ap->a_size = ealen;
    724  1.1  christos 		else if (ap->a_uio != NULL)
    725  1.1  christos 			error = uiomove(p, ealen, ap->a_uio);
    726  1.1  christos 	} else
    727  1.1  christos 		error = ENOATTR;
    728  1.1  christos 
    729  1.1  christos 	ffs_close_ea(ap->a_vp, 0, ap->a_cred);
    730  1.1  christos 	return (error);
    731  1.1  christos }
    732  1.1  christos 
    733  1.1  christos /*
    734  1.1  christos  * Vnode operation to set a named attribute.
    735  1.1  christos  */
    736  1.1  christos int
    737  1.1  christos ffs_setextattr(void *v)
    738  1.1  christos {
    739  1.1  christos 	struct vop_setextattr_args /* {
    740  1.1  christos 		struct vnode *a_vp;
    741  1.1  christos 		int a_attrnamespace;
    742  1.1  christos 		const char *a_name;
    743  1.1  christos 		struct uio *a_uio;
    744  1.1  christos 		kauth_cred_t a_cred;
    745  1.1  christos 		struct proc *a_p;
    746  1.1  christos 	} */ *ap = v;
    747  1.1  christos 	struct vnode *vp = ap->a_vp;
    748  1.1  christos 	struct inode *ip = VTOI(vp);
    749  1.1  christos 	struct fs *fs = ip->i_fs;
    750  1.1  christos 
    751  1.1  christos 	KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
    752  1.1  christos 	if (fs->fs_magic == FS_UFS1_MAGIC) {
    753  1.1  christos 		return ufs_setextattr(ap);
    754  1.1  christos 	}
    755  1.1  christos 
    756  1.1  christos 	struct extattr *eap;
    757  1.1  christos 	uint32_t ealength, ul;
    758  1.1  christos 	ssize_t ealen;
    759  1.1  christos 	int olen, eapad1, eapad2, error, i, easize;
    760  1.1  christos 	u_char *eae;
    761  1.1  christos 	void *tmp;
    762  1.1  christos 
    763  1.1  christos 	if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK)
    764  1.1  christos 		return (EOPNOTSUPP);
    765  1.1  christos 
    766  1.1  christos 	if (strlen(ap->a_name) == 0)
    767  1.1  christos 		return (EINVAL);
    768  1.1  christos 
    769  1.1  christos 	/* XXX Now unsupported API to delete EAs using NULL uio. */
    770  1.1  christos 	if (ap->a_uio == NULL)
    771  1.1  christos 		return (EOPNOTSUPP);
    772  1.1  christos 
    773  1.1  christos 	if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
    774  1.1  christos 		return (EROFS);
    775  1.1  christos 
    776  1.1  christos 	ealen = ap->a_uio->uio_resid;
    777  1.1  christos 	if (ealen < 0 || ealen > lblktosize(fs, UFS_NXADDR))
    778  1.1  christos 		return (EINVAL);
    779  1.1  christos 
    780  1.1  christos 	error = ffs_extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
    781  1.1  christos 	    ap->a_cred, VWRITE);
    782  1.1  christos 	if (error) {
    783  1.1  christos 
    784  1.1  christos 		/*
    785  1.1  christos 		 * ffs_lock_ea is not needed there, because the vnode
    786  1.1  christos 		 * must be exclusively locked.
    787  1.1  christos 		 */
    788  1.1  christos 		if (ip->i_ea_area != NULL && ip->i_ea_error == 0)
    789  1.1  christos 			ip->i_ea_error = error;
    790  1.1  christos 		return (error);
    791  1.1  christos 	}
    792  1.1  christos 
    793  1.1  christos 	error = ffs_open_ea(ap->a_vp, ap->a_cred);
    794  1.1  christos 	if (error)
    795  1.1  christos 		return (error);
    796  1.1  christos 
    797  1.1  christos 	ealength = sizeof(uint32_t) + 3 + strlen(ap->a_name);
    798  1.1  christos 	eapad1 = roundup2(ealength, 8) - ealength;
    799  1.1  christos 	eapad2 = roundup2(ealen, 8) - ealen;
    800  1.1  christos 	ealength += eapad1 + ealen + eapad2;
    801  1.1  christos 
    802  1.1  christos 	/*
    803  1.1  christos 	 * CEM: rewrites of the same size or smaller could be done in-place
    804  1.1  christos 	 * instead.  (We don't acquire any fine-grained locks in here either,
    805  1.1  christos 	 * so we could also do bigger writes in-place.)
    806  1.1  christos 	 */
    807  1.1  christos 	eae = malloc(ip->i_ea_len + ealength, M_TEMP, M_WAITOK);
    808  1.1  christos 	bcopy(ip->i_ea_area, eae, ip->i_ea_len);
    809  1.1  christos 	easize = ip->i_ea_len;
    810  1.1  christos 
    811  1.1  christos 	olen = ffs_findextattr(eae, easize, ap->a_attrnamespace, ap->a_name,
    812  1.1  christos 	    &eap, NULL);
    813  1.1  christos         if (olen == -1) {
    814  1.1  christos 		/* new, append at end */
    815  1.1  christos 		KASSERT(ALIGNED_TO(eae + easize, struct extattr));
    816  1.1  christos 		eap = (struct extattr *)(eae + easize);
    817  1.1  christos 		easize += ealength;
    818  1.1  christos 	} else {
    819  1.1  christos 		ul = eap->ea_length;
    820  1.1  christos 		i = (u_char *)EXTATTR_NEXT(eap) - eae;
    821  1.1  christos 		if (ul != ealength) {
    822  1.1  christos 			bcopy(EXTATTR_NEXT(eap), (u_char *)eap + ealength,
    823  1.1  christos 			    easize - i);
    824  1.1  christos 			easize += (ealength - ul);
    825  1.1  christos 		}
    826  1.1  christos 	}
    827  1.1  christos 	if (easize > lblktosize(fs, UFS_NXADDR)) {
    828  1.1  christos 		free(eae, M_TEMP);
    829  1.1  christos 		ffs_close_ea(ap->a_vp, 0, ap->a_cred);
    830  1.1  christos 		if (ip->i_ea_area != NULL && ip->i_ea_error == 0)
    831  1.1  christos 			ip->i_ea_error = ENOSPC;
    832  1.1  christos 		return (ENOSPC);
    833  1.1  christos 	}
    834  1.1  christos 	eap->ea_length = ealength;
    835  1.1  christos 	eap->ea_namespace = ap->a_attrnamespace;
    836  1.1  christos 	eap->ea_contentpadlen = eapad2;
    837  1.1  christos 	eap->ea_namelength = strlen(ap->a_name);
    838  1.1  christos 	memcpy(eap->ea_name, ap->a_name, strlen(ap->a_name));
    839  1.1  christos 	bzero(&eap->ea_name[strlen(ap->a_name)], eapad1);
    840  1.1  christos 	error = uiomove(EXTATTR_CONTENT(eap), ealen, ap->a_uio);
    841  1.1  christos 	if (error) {
    842  1.1  christos 		free(eae, M_TEMP);
    843  1.1  christos 		ffs_close_ea(ap->a_vp, 0, ap->a_cred);
    844  1.1  christos 		if (ip->i_ea_area != NULL && ip->i_ea_error == 0)
    845  1.1  christos 			ip->i_ea_error = error;
    846  1.1  christos 		return (error);
    847  1.1  christos 	}
    848  1.1  christos 	bzero((u_char *)EXTATTR_CONTENT(eap) + ealen, eapad2);
    849  1.1  christos 
    850  1.1  christos 	tmp = ip->i_ea_area;
    851  1.1  christos 	ip->i_ea_area = eae;
    852  1.1  christos 	ip->i_ea_len = easize;
    853  1.1  christos 	free(tmp, M_TEMP);
    854  1.1  christos 	error = ffs_close_ea(ap->a_vp, 1, ap->a_cred);
    855  1.1  christos 	return (error);
    856  1.1  christos }
    857  1.1  christos 
    858  1.1  christos /*
    859  1.1  christos  * Vnode operation to retrieve extended attributes on a vnode.
    860  1.1  christos  */
    861  1.1  christos int
    862  1.1  christos ffs_listextattr(void *v)
    863  1.1  christos {
    864  1.1  christos 	struct vop_listextattr_args /* {
    865  1.1  christos 		struct vnode *a_vp;
    866  1.1  christos 		int a_attrnamespace;
    867  1.1  christos 		struct uio *a_uio;
    868  1.1  christos 		size_t *a_size;
    869  1.1  christos 		kauth_cred_t a_cred;
    870  1.1  christos 		struct proc *a_p;
    871  1.1  christos 	} */ *ap = v;
    872  1.1  christos 	struct inode *ip = VTOI(ap->a_vp);
    873  1.1  christos 	struct fs *fs = ip->i_fs;
    874  1.1  christos 
    875  1.1  christos 	if (fs->fs_magic == FS_UFS1_MAGIC) {
    876  1.1  christos 		return ufs_listextattr(ap);
    877  1.1  christos 	}
    878  1.1  christos 
    879  1.1  christos 	struct extattr *eap, *eaend;
    880  1.1  christos 	int error, ealen;
    881  1.1  christos 
    882  1.1  christos 	if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK)
    883  1.1  christos 		return (EOPNOTSUPP);
    884  1.1  christos 
    885  1.1  christos 	error = ffs_extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
    886  1.1  christos 	    ap->a_cred, VREAD);
    887  1.1  christos 	if (error)
    888  1.1  christos 		return (error);
    889  1.1  christos 
    890  1.1  christos 	error = ffs_open_ea(ap->a_vp, ap->a_cred);
    891  1.1  christos 	if (error)
    892  1.1  christos 		return (error);
    893  1.1  christos 
    894  1.1  christos 	error = 0;
    895  1.1  christos 	if (ap->a_size != NULL)
    896  1.1  christos 		*ap->a_size = 0;
    897  1.1  christos 
    898  1.1  christos 	KASSERT(ALIGNED_TO(ip->i_ea_area, struct extattr));
    899  1.1  christos 	eap = (struct extattr *)ip->i_ea_area;
    900  1.1  christos 	eaend = (struct extattr *)(ip->i_ea_area + ip->i_ea_len);
    901  1.1  christos 	for (; error == 0 && eap < eaend; eap = EXTATTR_NEXT(eap)) {
    902  1.1  christos 		/* make sure this entry is complete */
    903  1.1  christos 		if (EXTATTR_NEXT(eap) > eaend)
    904  1.1  christos 			break;
    905  1.1  christos 		if (eap->ea_namespace != ap->a_attrnamespace)
    906  1.1  christos 			continue;
    907  1.1  christos 
    908  1.1  christos 		ealen = eap->ea_namelength;
    909  1.1  christos 		if (ap->a_size != NULL)
    910  1.1  christos 			*ap->a_size += ealen + 1;
    911  1.1  christos 		else if (ap->a_uio != NULL)
    912  1.1  christos 			error = uiomove(&eap->ea_namelength, ealen + 1,
    913  1.1  christos 			    ap->a_uio);
    914  1.1  christos 	}
    915  1.1  christos 
    916  1.1  christos 	ffs_close_ea(ap->a_vp, 0, ap->a_cred);
    917  1.1  christos 	return (error);
    918  1.1  christos }
    919  1.1  christos 
    920  1.1  christos /*
    921  1.1  christos  * Vnode operation to remove a named attribute.
    922  1.1  christos  */
    923  1.1  christos int
    924  1.1  christos ffs_deleteextattr(void *v)
    925  1.1  christos {
    926  1.1  christos 	struct vop_deleteextattr_args /* {
    927  1.1  christos 		struct vnode *a_vp;
    928  1.1  christos 		int a_attrnamespace;
    929  1.1  christos 		kauth_cred_t a_cred;
    930  1.1  christos 		struct proc *a_p;
    931  1.1  christos 	} */ *ap = v;
    932  1.1  christos 	struct vnode *vp = ap->a_vp;
    933  1.1  christos 	struct inode *ip = VTOI(vp);
    934  1.1  christos 	struct fs *fs = ip->i_fs;
    935  1.1  christos 
    936  1.1  christos 	if (fs->fs_magic == FS_UFS1_MAGIC) {
    937  1.1  christos 		return ufs_deleteextattr(ap);
    938  1.1  christos 	}
    939  1.1  christos 
    940  1.1  christos 	struct extattr *eap;
    941  1.1  christos 	uint32_t ul;
    942  1.1  christos 	int olen, error, i, easize;
    943  1.1  christos 	u_char *eae;
    944  1.1  christos 	void *tmp;
    945  1.1  christos 
    946  1.1  christos 	if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK)
    947  1.1  christos 		return (EOPNOTSUPP);
    948  1.1  christos 
    949  1.1  christos 	if (strlen(ap->a_name) == 0)
    950  1.1  christos 		return (EINVAL);
    951  1.1  christos 
    952  1.1  christos 	if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
    953  1.1  christos 		return (EROFS);
    954  1.1  christos 
    955  1.1  christos 	error = ffs_extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
    956  1.1  christos 	    ap->a_cred, VWRITE);
    957  1.1  christos 	if (error) {
    958  1.1  christos 
    959  1.1  christos 		/*
    960  1.1  christos 		 * ffs_lock_ea is not needed there, because the vnode
    961  1.1  christos 		 * must be exclusively locked.
    962  1.1  christos 		 */
    963  1.1  christos 		if (ip->i_ea_area != NULL && ip->i_ea_error == 0)
    964  1.1  christos 			ip->i_ea_error = error;
    965  1.1  christos 		return (error);
    966  1.1  christos 	}
    967  1.1  christos 
    968  1.1  christos 	error = ffs_open_ea(ap->a_vp, ap->a_cred);
    969  1.1  christos 	if (error)
    970  1.1  christos 		return (error);
    971  1.1  christos 
    972  1.1  christos 	/* CEM: delete could be done in-place instead */
    973  1.1  christos 	eae = malloc(ip->i_ea_len, M_TEMP, M_WAITOK);
    974  1.1  christos 	bcopy(ip->i_ea_area, eae, ip->i_ea_len);
    975  1.1  christos 	easize = ip->i_ea_len;
    976  1.1  christos 
    977  1.1  christos 	olen = ffs_findextattr(eae, easize, ap->a_attrnamespace, ap->a_name,
    978  1.1  christos 	    &eap, NULL);
    979  1.1  christos 	if (olen == -1) {
    980  1.1  christos 		/* delete but nonexistent */
    981  1.1  christos 		free(eae, M_TEMP);
    982  1.1  christos 		ffs_close_ea(ap->a_vp, 0, ap->a_cred);
    983  1.1  christos 		return (ENOATTR);
    984  1.1  christos 	}
    985  1.1  christos 	ul = eap->ea_length;
    986  1.1  christos 	i = (u_char *)EXTATTR_NEXT(eap) - eae;
    987  1.1  christos 	bcopy(EXTATTR_NEXT(eap), eap, easize - i);
    988  1.1  christos 	easize -= ul;
    989  1.1  christos 
    990  1.1  christos 	tmp = ip->i_ea_area;
    991  1.1  christos 	ip->i_ea_area = eae;
    992  1.1  christos 	ip->i_ea_len = easize;
    993  1.1  christos 	free(tmp, M_TEMP);
    994  1.1  christos 	error = ffs_close_ea(ap->a_vp, 1, ap->a_cred);
    995  1.1  christos 	return error;
    996  1.1  christos }
    997