Home | History | Annotate | Line # | Download | only in ffs
      1  1.10       chs /*	$NetBSD: ffs_extattr.c,v 1.10 2022/11/28 04:52:04 chs 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.10       chs __KERNEL_RCSID(0, "$NetBSD: ffs_extattr.c,v 1.10 2022/11/28 04:52:04 chs 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 #define ALIGNED_TO(ptr, s)  \
    109   1.1  christos     (((uintptr_t)(ptr) & (_Alignof(s) - 1)) == 0)
    110   1.1  christos #define uoff_t uintmax_t
    111   1.1  christos #define ITOFS(ip) (ip)->i_fs
    112   1.1  christos #define i_din2 i_din.ffs2_din
    113   1.1  christos #define VI_LOCK(vp)		mutex_enter((vp)->v_interlock)
    114   1.1  christos #define VI_UNLOCK(vp)		mutex_exit((vp)->v_interlock)
    115   1.1  christos #define UFS_INODE_SET_FLAG(ip, f)	((ip)->i_flag |= (f))
    116   1.1  christos #define ASSERT_VOP_ELOCKED(vp, m)	KASSERT(VOP_ISLOCKED(vp))
    117  1.10       chs #define I_IS_UFS2(ip)		((ip)->i_ump->um_fstype == UFS2)
    118   1.1  christos #define	lblktosize(fs, o)	ffs_lblktosize(fs, o)
    119   1.1  christos #define	lblkno(fs, o)		ffs_lblkno(fs, o)
    120   1.1  christos #define	blkoff(fs, o)		ffs_blkoff(fs, o)
    121   1.1  christos #define	sblksize(fs, o, lbn)	ffs_sblksize(fs, o, lbn)
    122   1.1  christos typedef daddr_t ufs_lbn_t;
    123   1.1  christos #define msleep(chan, mtx, pri, wmesg, timeo) \
    124   1.1  christos     mtsleep((chan), (pri), (wmesg), (timeo), *(mtx))
    125   1.1  christos #define vm_page_count_severe()		0
    126   1.1  christos #define buf_dirty_count_severe()	0
    127   1.1  christos #define BA_CLRBUF B_CLRBUF
    128   1.1  christos #define IO_ASYNC 0
    129   1.1  christos #define vfs_bio_brelse(bp, ioflag) 	brelse(bp, 0)
    130   1.1  christos #define vfs_bio_clrbuf(bp) 		clrbuf(bp)
    131   1.1  christos #define vfs_bio_set_flags(bp, ioflag) 	__nothing
    132   1.1  christos 
    133   1.1  christos /*
    134   1.1  christos  * Extended attribute area reading.
    135   1.1  christos  */
    136   1.1  christos static int
    137   1.1  christos ffs_extread(struct vnode *vp, struct uio *uio, int ioflag)
    138   1.1  christos {
    139   1.1  christos 	struct inode *ip;
    140   1.1  christos 	struct ufs2_dinode *dp;
    141   1.1  christos 	struct fs *fs;
    142   1.1  christos 	struct buf *bp;
    143   1.1  christos 	ufs_lbn_t lbn, nextlbn;
    144   1.1  christos 	off_t bytesinfile;
    145   1.1  christos 	long size, xfersize, blkoffset;
    146   1.1  christos 	ssize_t orig_resid;
    147   1.1  christos 	int error;
    148   1.1  christos 
    149   1.1  christos 	ip = VTOI(vp);
    150   1.1  christos 	fs = ITOFS(ip);
    151   1.1  christos 	dp = ip->i_din2;
    152   1.1  christos 
    153   1.1  christos #ifdef INVARIANTS
    154  1.10       chs 	if (uio->uio_rw != UIO_READ || ip->i_ump->um_fstype != UFS2)
    155   1.1  christos 		panic("ffs_extread: mode");
    156   1.1  christos 
    157   1.1  christos #endif
    158   1.1  christos 	orig_resid = uio->uio_resid;
    159   1.1  christos 	KASSERT(orig_resid >= 0);
    160   1.1  christos 	if (orig_resid == 0)
    161   1.1  christos 		return (0);
    162   1.1  christos 	KASSERT(uio->uio_offset >= 0);
    163   1.1  christos 
    164   1.1  christos 	for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) {
    165   1.1  christos 		if ((bytesinfile = dp->di_extsize - uio->uio_offset) <= 0)
    166   1.1  christos 			break;
    167   1.1  christos 		lbn = lblkno(fs, uio->uio_offset);
    168   1.1  christos 		nextlbn = lbn + 1;
    169   1.1  christos 
    170   1.1  christos 		/*
    171   1.1  christos 		 * size of buffer.  The buffer representing the
    172   1.1  christos 		 * end of the file is rounded up to the size of
    173   1.1  christos 		 * the block type ( fragment or full block,
    174   1.1  christos 		 * depending ).
    175   1.1  christos 		 */
    176   1.1  christos 		size = sblksize(fs, dp->di_extsize, lbn);
    177   1.1  christos 		blkoffset = blkoff(fs, uio->uio_offset);
    178   1.1  christos 
    179   1.1  christos 		/*
    180   1.1  christos 		 * The amount we want to transfer in this iteration is
    181   1.1  christos 		 * one FS block less the amount of the data before
    182   1.1  christos 		 * our startpoint (duh!)
    183   1.1  christos 		 */
    184   1.1  christos 		xfersize = fs->fs_bsize - blkoffset;
    185   1.1  christos 
    186   1.1  christos 		/*
    187   1.1  christos 		 * But if we actually want less than the block,
    188   1.1  christos 		 * or the file doesn't have a whole block more of data,
    189   1.1  christos 		 * then use the lesser number.
    190   1.1  christos 		 */
    191   1.1  christos 		if (uio->uio_resid < xfersize)
    192   1.1  christos 			xfersize = uio->uio_resid;
    193   1.1  christos 		if (bytesinfile < xfersize)
    194   1.1  christos 			xfersize = bytesinfile;
    195   1.1  christos 
    196   1.1  christos 		if (lblktosize(fs, nextlbn) >= dp->di_extsize) {
    197   1.1  christos 			/*
    198   1.1  christos 			 * Don't do readahead if this is the end of the info.
    199   1.1  christos 			 */
    200   1.1  christos 			error = bread(vp, -1 - lbn, size, 0, &bp);
    201   1.1  christos 		} else {
    202   1.1  christos 			/*
    203   1.1  christos 			 * If we have a second block, then
    204   1.1  christos 			 * fire off a request for a readahead
    205   1.1  christos 			 * as well as a read. Note that the 4th and 5th
    206   1.1  christos 			 * arguments point to arrays of the size specified in
    207   1.1  christos 			 * the 6th argument.
    208   1.1  christos 			 */
    209   1.1  christos 			u_int nextsize = sblksize(fs, dp->di_extsize, nextlbn);
    210   1.1  christos 
    211   1.1  christos 			nextlbn = -1 - nextlbn;
    212   1.1  christos 			error = breadn(vp, -1 - lbn,
    213   1.1  christos 			    size, &nextlbn, &nextsize, 1, 0, &bp);
    214   1.1  christos 		}
    215   1.1  christos 		if (error) {
    216   1.1  christos 			brelse(bp, 0);
    217   1.1  christos 			bp = NULL;
    218   1.1  christos 			break;
    219   1.1  christos 		}
    220   1.1  christos 
    221   1.1  christos 		/*
    222   1.1  christos 		 * We should only get non-zero b_resid when an I/O error
    223   1.1  christos 		 * has occurred, which should cause us to break above.
    224   1.1  christos 		 * However, if the short read did not cause an error,
    225   1.1  christos 		 * then we want to ensure that we do not uiomove bad
    226   1.1  christos 		 * or uninitialized data.
    227   1.1  christos 		 */
    228   1.1  christos 		size -= bp->b_resid;
    229   1.1  christos 		if (size < xfersize) {
    230   1.1  christos 			if (size == 0)
    231   1.1  christos 				break;
    232   1.1  christos 			xfersize = size;
    233   1.1  christos 		}
    234   1.1  christos 
    235   1.1  christos 		error = uiomove((char *)bp->b_data + blkoffset,
    236   1.1  christos 					(int)xfersize, uio);
    237   1.1  christos 		if (error)
    238   1.1  christos 			break;
    239   1.1  christos 		vfs_bio_brelse(bp, ioflag);
    240   1.1  christos 	}
    241   1.1  christos 
    242   1.1  christos 	/*
    243   1.1  christos 	 * This can only happen in the case of an error
    244   1.1  christos 	 * because the loop above resets bp to NULL on each iteration
    245   1.1  christos 	 * and on normal completion has not set a new value into it.
    246   1.1  christos 	 * so it must have come from a 'break' statement
    247   1.1  christos 	 */
    248   1.1  christos 	if (bp != NULL)
    249   1.1  christos 		vfs_bio_brelse(bp, ioflag);
    250   1.1  christos 	return (error);
    251   1.1  christos }
    252   1.1  christos /*
    253   1.1  christos  * Extended attribute area writing.
    254   1.1  christos  */
    255   1.1  christos static int
    256   1.1  christos ffs_extwrite(struct vnode *vp, struct uio *uio, int ioflag, kauth_cred_t ucred)
    257   1.1  christos {
    258   1.1  christos 	struct inode *ip;
    259   1.1  christos 	struct ufs2_dinode *dp;
    260   1.1  christos 	struct fs *fs;
    261   1.1  christos 	struct buf *bp;
    262   1.1  christos 	ufs_lbn_t lbn;
    263   1.1  christos 	off_t osize;
    264   1.1  christos 	ssize_t resid;
    265   1.1  christos 	int blkoffset, error, flags, size, xfersize;
    266   1.1  christos 
    267   1.1  christos 	ip = VTOI(vp);
    268   1.1  christos 	fs = ITOFS(ip);
    269   1.1  christos 	dp = ip->i_din2;
    270   1.1  christos 
    271   1.1  christos #ifdef INVARIANTS
    272  1.10       chs 	if (uio->uio_rw != UIO_WRITE || ip->i_ump->um_fstype != UFS2)
    273   1.1  christos 		panic("ffs_extwrite: mode");
    274   1.1  christos #endif
    275   1.1  christos 
    276   1.1  christos 	if (ioflag & IO_APPEND)
    277   1.1  christos 		uio->uio_offset = dp->di_extsize;
    278   1.1  christos 	KASSERT(uio->uio_offset >= 0);
    279   1.1  christos 	if ((uoff_t)uio->uio_offset + uio->uio_resid >
    280   1.1  christos 	    UFS_NXADDR * fs->fs_bsize)
    281   1.1  christos 		return (EFBIG);
    282   1.1  christos 
    283   1.1  christos 	resid = uio->uio_resid;
    284   1.1  christos 	osize = dp->di_extsize;
    285   1.1  christos 	flags = IO_EXT;
    286   1.1  christos 	if (ioflag & IO_SYNC)
    287   1.1  christos 		flags |= IO_SYNC;
    288   1.1  christos 
    289   1.1  christos 	if ((error = UFS_WAPBL_BEGIN(vp->v_mount)) != 0)
    290   1.1  christos 		return error;
    291   1.1  christos 
    292   1.1  christos 	for (error = 0; uio->uio_resid > 0;) {
    293   1.1  christos 		lbn = lblkno(fs, uio->uio_offset);
    294   1.1  christos 		blkoffset = blkoff(fs, uio->uio_offset);
    295   1.1  christos 		xfersize = fs->fs_bsize - blkoffset;
    296   1.1  christos 		if (uio->uio_resid < xfersize)
    297   1.1  christos 			xfersize = uio->uio_resid;
    298   1.1  christos 
    299   1.1  christos 		/*
    300   1.1  christos 		 * We must perform a read-before-write if the transfer size
    301   1.1  christos 		 * does not cover the entire buffer.
    302   1.1  christos 		 */
    303   1.1  christos 		if (fs->fs_bsize > xfersize)
    304   1.1  christos 			flags |= BA_CLRBUF;
    305   1.1  christos 		else
    306   1.1  christos 			flags &= ~BA_CLRBUF;
    307   1.1  christos 		error = UFS_BALLOC(vp, uio->uio_offset, xfersize,
    308   1.1  christos 		    ucred, flags, &bp);
    309   1.1  christos 		if (error != 0)
    310   1.1  christos 			break;
    311   1.1  christos 		/*
    312   1.1  christos 		 * If the buffer is not valid we have to clear out any
    313   1.1  christos 		 * garbage data from the pages instantiated for the buffer.
    314   1.1  christos 		 * If we do not, a failed uiomove() during a write can leave
    315   1.1  christos 		 * the prior contents of the pages exposed to a userland
    316   1.1  christos 		 * mmap().  XXX deal with uiomove() errors a better way.
    317   1.1  christos 		 */
    318   1.1  christos 		if ((bp->b_flags & BC_NOCACHE) && fs->fs_bsize <= xfersize)
    319   1.1  christos 			vfs_bio_clrbuf(bp);
    320   1.1  christos 
    321   1.1  christos 		if (uio->uio_offset + xfersize > dp->di_extsize)
    322   1.1  christos 			dp->di_extsize = uio->uio_offset + xfersize;
    323   1.1  christos 
    324   1.1  christos 		size = sblksize(fs, dp->di_extsize, lbn) - bp->b_resid;
    325   1.1  christos 		if (size < xfersize)
    326   1.1  christos 			xfersize = size;
    327   1.1  christos 
    328   1.1  christos 		error =
    329   1.1  christos 		    uiomove((char *)bp->b_data + blkoffset, (int)xfersize, uio);
    330   1.1  christos 
    331   1.1  christos 		vfs_bio_set_flags(bp, ioflag);
    332   1.1  christos 
    333   1.1  christos 		/*
    334   1.1  christos 		 * If IO_SYNC each buffer is written synchronously.  Otherwise
    335   1.1  christos 		 * if we have a severe page deficiency write the buffer
    336   1.1  christos 		 * asynchronously.  Otherwise try to cluster, and if that
    337   1.1  christos 		 * doesn't do it then either do an async write (if O_DIRECT),
    338   1.1  christos 		 * or a delayed write (if not).
    339   1.1  christos 		 */
    340   1.1  christos 		if (ioflag & IO_SYNC) {
    341   1.1  christos 			(void)bwrite(bp);
    342   1.1  christos 		} else if (vm_page_count_severe() ||
    343   1.1  christos 			    buf_dirty_count_severe() ||
    344   1.1  christos 			    xfersize + blkoffset == fs->fs_bsize ||
    345   1.1  christos 			    (ioflag & (IO_ASYNC | IO_DIRECT)))
    346   1.1  christos 			bawrite(bp);
    347   1.1  christos 		else
    348   1.1  christos 			bdwrite(bp);
    349   1.1  christos 		if (error || xfersize == 0)
    350   1.1  christos 			break;
    351   1.1  christos 		UFS_INODE_SET_FLAG(ip, IN_CHANGE);
    352   1.1  christos 	}
    353   1.1  christos 	/*
    354   1.1  christos 	 * If we successfully wrote any data, and we are not the superuser
    355   1.1  christos 	 * we clear the setuid and setgid bits as a precaution against
    356   1.1  christos 	 * tampering.
    357   1.1  christos 	 */
    358   1.1  christos 	if ((ip->i_mode & (ISUID | ISGID)) && resid > uio->uio_resid && ucred) {
    359   1.1  christos 		ip->i_mode &= ~(ISUID | ISGID);
    360   1.1  christos 		dp->di_mode = ip->i_mode;
    361   1.1  christos 	}
    362   1.1  christos 	if (error) {
    363   1.1  christos 		if (ioflag & IO_UNIT) {
    364   1.1  christos 			(void)ffs_truncate(vp, osize,
    365   1.1  christos 			    IO_EXT | (ioflag&IO_SYNC), ucred);
    366   1.1  christos 			uio->uio_offset -= resid - uio->uio_resid;
    367   1.1  christos 			uio->uio_resid = resid;
    368   1.1  christos 		}
    369   1.1  christos 	} else if (resid > uio->uio_resid && (ioflag & IO_SYNC))
    370   1.1  christos 		error = ffs_update(vp, NULL, NULL, UPDATE_WAIT);
    371   1.1  christos 	UFS_WAPBL_END(vp->v_mount);
    372   1.1  christos 	return (error);
    373   1.1  christos }
    374   1.1  christos 
    375   1.1  christos /*
    376   1.1  christos  * Vnode operating to retrieve a named extended attribute.
    377   1.1  christos  *
    378   1.1  christos  * Locate a particular EA (nspace:name) in the area (ptr:length), and return
    379   1.1  christos  * the length of the EA, and possibly the pointer to the entry and to the data.
    380   1.1  christos  */
    381   1.1  christos static int
    382   1.1  christos ffs_findextattr(u_char *ptr, u_int length, int nspace, const char *name,
    383   1.1  christos     struct extattr **eapp, u_char **eac)
    384   1.1  christos {
    385   1.1  christos 	struct extattr *eap, *eaend;
    386   1.1  christos 	size_t nlen;
    387   1.1  christos 
    388   1.1  christos 	nlen = strlen(name);
    389   1.1  christos 	KASSERT(ALIGNED_TO(ptr, struct extattr));
    390   1.1  christos 	eap = (struct extattr *)ptr;
    391   1.1  christos 	eaend = (struct extattr *)(ptr + length);
    392   1.1  christos 	for (; eap < eaend; eap = EXTATTR_NEXT(eap)) {
    393   1.1  christos 		/* make sure this entry is complete */
    394   1.1  christos 		if (EXTATTR_NEXT(eap) > eaend)
    395   1.1  christos 			break;
    396   1.1  christos 		if (eap->ea_namespace != nspace || eap->ea_namelength != nlen
    397   1.1  christos 		    || memcmp(eap->ea_name, name, nlen) != 0)
    398   1.1  christos 			continue;
    399   1.1  christos 		if (eapp != NULL)
    400   1.1  christos 			*eapp = eap;
    401   1.1  christos 		if (eac != NULL)
    402   1.1  christos 			*eac = EXTATTR_CONTENT(eap);
    403   1.1  christos 		return (EXTATTR_CONTENT_SIZE(eap));
    404   1.1  christos 	}
    405   1.1  christos 	return (-1);
    406   1.1  christos }
    407   1.1  christos 
    408   1.1  christos static int
    409   1.1  christos ffs_rdextattr(u_char **p, struct vnode *vp, int extra)
    410   1.1  christos {
    411   1.1  christos 	struct inode *ip;
    412   1.1  christos 	struct ufs2_dinode *dp;
    413   1.1  christos 	struct fs *fs;
    414   1.1  christos 	struct uio luio;
    415   1.1  christos 	struct iovec liovec;
    416   1.1  christos 	u_int easize;
    417   1.1  christos 	int error;
    418   1.1  christos 	u_char *eae;
    419   1.1  christos 
    420   1.1  christos 	ip = VTOI(vp);
    421   1.1  christos 	fs = ITOFS(ip);
    422   1.1  christos 	dp = ip->i_din2;
    423   1.1  christos 	easize = dp->di_extsize;
    424   1.1  christos 	if ((uoff_t)easize + extra > UFS_NXADDR * fs->fs_bsize)
    425   1.1  christos 		return (EFBIG);
    426   1.1  christos 
    427   1.1  christos 	eae = malloc(easize + extra, M_TEMP, M_WAITOK);
    428   1.1  christos 
    429   1.1  christos 	liovec.iov_base = eae;
    430   1.1  christos 	liovec.iov_len = easize;
    431   1.1  christos 	luio.uio_iov = &liovec;
    432   1.1  christos 	luio.uio_iovcnt = 1;
    433   1.1  christos 	luio.uio_offset = 0;
    434   1.1  christos 	luio.uio_resid = easize;
    435   1.1  christos 	luio.uio_vmspace = vmspace_kernel();
    436   1.1  christos 	luio.uio_rw = UIO_READ;
    437   1.1  christos 
    438   1.1  christos 	error = ffs_extread(vp, &luio, IO_EXT | IO_SYNC);
    439   1.1  christos 	if (error) {
    440   1.1  christos 		free(eae, M_TEMP);
    441   1.1  christos 		return(error);
    442   1.1  christos 	}
    443   1.1  christos 	*p = eae;
    444   1.1  christos 	return (0);
    445   1.1  christos }
    446   1.1  christos 
    447   1.1  christos static void
    448   1.1  christos ffs_lock_ea(struct vnode *vp)
    449   1.1  christos {
    450   1.2  christos 	genfs_node_wrlock(vp);
    451   1.1  christos }
    452   1.1  christos 
    453   1.1  christos static void
    454   1.1  christos ffs_unlock_ea(struct vnode *vp)
    455   1.1  christos {
    456   1.2  christos 	genfs_node_unlock(vp);
    457   1.1  christos }
    458   1.1  christos 
    459   1.1  christos static int
    460   1.1  christos ffs_open_ea(struct vnode *vp, kauth_cred_t cred)
    461   1.1  christos {
    462   1.1  christos 	struct inode *ip;
    463   1.1  christos 	struct ufs2_dinode *dp;
    464   1.1  christos 	int error;
    465   1.1  christos 
    466   1.1  christos 	ip = VTOI(vp);
    467   1.9       chs 	if ((ip->i_ump->um_flags & UFS_EA) == 0) {
    468   1.9       chs 		return EOPNOTSUPP;
    469   1.9       chs 	}
    470   1.1  christos 
    471   1.1  christos 	ffs_lock_ea(vp);
    472   1.1  christos 	if (ip->i_ea_area != NULL) {
    473   1.1  christos 		ip->i_ea_refs++;
    474   1.1  christos 		ffs_unlock_ea(vp);
    475   1.1  christos 		return (0);
    476   1.1  christos 	}
    477   1.1  christos 	dp = ip->i_din2;
    478   1.1  christos 	error = ffs_rdextattr(&ip->i_ea_area, vp, 0);
    479   1.1  christos 	if (error) {
    480   1.1  christos 		ffs_unlock_ea(vp);
    481   1.1  christos 		return (error);
    482   1.1  christos 	}
    483   1.1  christos 	ip->i_ea_len = dp->di_extsize;
    484   1.1  christos 	ip->i_ea_error = 0;
    485   1.1  christos 	ip->i_ea_refs++;
    486   1.1  christos 	ffs_unlock_ea(vp);
    487   1.1  christos 	return (0);
    488   1.1  christos }
    489   1.1  christos 
    490   1.1  christos /*
    491   1.1  christos  * Vnode extattr transaction commit/abort
    492   1.1  christos  */
    493   1.1  christos static int
    494   1.1  christos ffs_close_ea(struct vnode *vp, int commit, kauth_cred_t cred)
    495   1.1  christos {
    496   1.1  christos 	struct inode *ip;
    497   1.1  christos 	struct uio luio;
    498   1.1  christos 	struct iovec liovec;
    499   1.1  christos 	int error;
    500   1.1  christos 	struct ufs2_dinode *dp;
    501   1.1  christos 
    502   1.1  christos 	ip = VTOI(vp);
    503   1.9       chs 	KASSERT((ip->i_ump->um_flags & UFS_EA) != 0);
    504   1.1  christos 
    505   1.1  christos 	if (commit)
    506   1.1  christos 		KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
    507   1.1  christos 	else
    508   1.1  christos 		KASSERT(VOP_ISLOCKED(vp));
    509   1.1  christos 	ffs_lock_ea(vp);
    510   1.1  christos 	if (ip->i_ea_area == NULL) {
    511   1.1  christos 		ffs_unlock_ea(vp);
    512   1.1  christos 		return (EINVAL);
    513   1.1  christos 	}
    514   1.1  christos 	dp = ip->i_din2;
    515   1.1  christos 	error = ip->i_ea_error;
    516   1.1  christos 	if (commit && error == 0) {
    517   1.1  christos 		ASSERT_VOP_ELOCKED(vp, "ffs_close_ea commit");
    518   1.1  christos 		if (cred == NOCRED)
    519   1.1  christos 			cred =  lwp0.l_cred;
    520   1.1  christos 		liovec.iov_base = ip->i_ea_area;
    521   1.1  christos 		liovec.iov_len = ip->i_ea_len;
    522   1.1  christos 		luio.uio_iov = &liovec;
    523   1.1  christos 		luio.uio_iovcnt = 1;
    524   1.1  christos 		luio.uio_offset = 0;
    525   1.1  christos 		luio.uio_resid = ip->i_ea_len;
    526   1.1  christos 		luio.uio_vmspace = vmspace_kernel();
    527   1.1  christos 		luio.uio_rw = UIO_WRITE;
    528   1.1  christos 
    529   1.1  christos 		/* XXX: I'm not happy about truncating to zero size */
    530   1.2  christos 		if (ip->i_ea_len < dp->di_extsize) {
    531   1.2  christos 			if ((error = UFS_WAPBL_BEGIN(vp->v_mount)) != 0) {
    532   1.2  christos 				ffs_unlock_ea(vp);
    533   1.2  christos 				return error;
    534   1.2  christos 			}
    535   1.1  christos 			error = ffs_truncate(vp, 0, IO_EXT, cred);
    536   1.2  christos 			UFS_WAPBL_END(vp->v_mount);
    537   1.2  christos 		}
    538   1.1  christos 		error = ffs_extwrite(vp, &luio, IO_EXT | IO_SYNC, cred);
    539   1.1  christos 	}
    540   1.1  christos 	if (--ip->i_ea_refs == 0) {
    541   1.1  christos 		free(ip->i_ea_area, M_TEMP);
    542   1.1  christos 		ip->i_ea_area = NULL;
    543   1.1  christos 		ip->i_ea_len = 0;
    544   1.1  christos 		ip->i_ea_error = 0;
    545   1.1  christos 	}
    546   1.1  christos 	ffs_unlock_ea(vp);
    547   1.1  christos 	return (error);
    548   1.1  christos }
    549   1.1  christos 
    550   1.1  christos /*
    551   1.1  christos  * Vnode extattr strategy routine for fifos.
    552   1.1  christos  *
    553   1.1  christos  * We need to check for a read or write of the external attributes.
    554   1.1  christos  * Otherwise we just fall through and do the usual thing.
    555   1.1  christos  */
    556   1.1  christos int
    557   1.1  christos ffsext_strategy(void *v)
    558   1.1  christos {
    559   1.1  christos 	struct vop_strategy_args /* {
    560   1.1  christos 		struct vnodeop_desc *a_desc;
    561   1.1  christos 		struct vnode *a_vp;
    562   1.1  christos 		struct buf *a_bp;
    563   1.1  christos 	} */ *ap = v;
    564   1.1  christos 	struct vnode *vp;
    565   1.1  christos 	daddr_t lbn;
    566   1.1  christos 
    567   1.1  christos 	vp = ap->a_vp;
    568   1.1  christos 	lbn = ap->a_bp->b_lblkno;
    569   1.1  christos 	if (I_IS_UFS2(VTOI(vp)) && lbn < 0 && lbn >= -UFS_NXADDR)
    570   1.1  christos 		return ufs_strategy(ap);
    571   1.1  christos 	if (vp->v_type == VFIFO)
    572   1.1  christos 		return vn_fifo_bypass(ap);
    573   1.1  christos 	panic("spec nodes went here");
    574   1.1  christos }
    575   1.1  christos 
    576   1.1  christos /*
    577   1.1  christos  * Vnode extattr transaction commit/abort
    578   1.1  christos  */
    579   1.1  christos int
    580   1.1  christos ffs_openextattr(void *v)
    581   1.1  christos {
    582   1.1  christos 	struct vop_openextattr_args /* {
    583   1.1  christos 		struct vnode *a_vp;
    584   1.1  christos 		kauth_cred_t a_cred;
    585   1.1  christos 		struct proc *a_p;
    586   1.1  christos 	} */ *ap = v;
    587   1.1  christos 	struct inode *ip = VTOI(ap->a_vp);
    588   1.1  christos 
    589   1.1  christos 	/* Not supported for UFS1 file systems. */
    590  1.10       chs 	if (ip->i_ump->um_fstype == UFS1)
    591   1.1  christos 		return (EOPNOTSUPP);
    592   1.1  christos 
    593   1.8       chs #ifdef __FreeBSD__
    594   1.1  christos 	if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK)
    595   1.1  christos 		return (EOPNOTSUPP);
    596   1.8       chs #endif
    597   1.1  christos 
    598   1.1  christos 	return (ffs_open_ea(ap->a_vp, ap->a_cred));
    599   1.1  christos }
    600   1.1  christos 
    601   1.1  christos /*
    602   1.1  christos  * Vnode extattr transaction commit/abort
    603   1.1  christos  */
    604   1.1  christos int
    605   1.1  christos ffs_closeextattr(void *v)
    606   1.1  christos {
    607   1.1  christos 	struct vop_closeextattr_args /* {
    608   1.1  christos 		struct vnode *a_vp;
    609   1.1  christos 		int a_commit;
    610   1.1  christos 		kauth_cred_t a_cred;
    611   1.1  christos 		struct proc *a_p;
    612   1.1  christos 	} */ *ap = v;
    613   1.1  christos 	struct inode *ip = VTOI(ap->a_vp);
    614   1.1  christos 
    615   1.1  christos 	/* Not supported for UFS1 file systems. */
    616  1.10       chs 	if (ip->i_ump->um_fstype == UFS1)
    617   1.1  christos 		return (EOPNOTSUPP);
    618   1.1  christos 
    619   1.8       chs #ifdef __FreeBSD__
    620   1.1  christos 	if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK)
    621   1.1  christos 		return (EOPNOTSUPP);
    622   1.8       chs #endif
    623   1.1  christos 
    624   1.1  christos 	if (ap->a_commit && (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY))
    625   1.1  christos 		return (EROFS);
    626   1.1  christos 
    627   1.1  christos 	return (ffs_close_ea(ap->a_vp, ap->a_commit, ap->a_cred));
    628   1.1  christos }
    629   1.1  christos 
    630   1.1  christos /*
    631   1.1  christos  * Vnode operation to retrieve a named extended attribute.
    632   1.1  christos  */
    633   1.1  christos int
    634   1.1  christos ffs_getextattr(void *v)
    635   1.1  christos {
    636   1.1  christos 	struct vop_getextattr_args /* {
    637   1.1  christos 		struct vnode *a_vp;
    638   1.1  christos 		int a_attrnamespace;
    639   1.1  christos 		const char *a_name;
    640   1.1  christos 		struct uio *a_uio;
    641   1.1  christos 		size_t *a_size;
    642   1.1  christos 		kauth_cred_t a_cred;
    643   1.1  christos 		struct proc *a_p;
    644   1.1  christos 	} */ *ap = v;
    645   1.1  christos 	struct vnode *vp = ap->a_vp;
    646   1.1  christos 	struct inode *ip = VTOI(vp);
    647   1.1  christos 
    648   1.1  christos 	KASSERT(VOP_ISLOCKED(vp));
    649  1.10       chs 
    650  1.10       chs 	if (ip->i_ump->um_fstype == UFS1) {
    651  1.10       chs #ifdef UFS_EXTATTR
    652   1.1  christos 		return ufs_getextattr(ap);
    653  1.10       chs #else
    654  1.10       chs 		return EOPNOTSUPP;
    655  1.10       chs #endif
    656   1.1  christos 	}
    657   1.1  christos 
    658   1.1  christos 	u_char *eae, *p;
    659   1.1  christos 	unsigned easize;
    660   1.1  christos 	int error, ealen;
    661   1.1  christos 
    662   1.8       chs #ifdef __FreeBSD__
    663   1.1  christos 	if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK)
    664   1.1  christos 		return (EOPNOTSUPP);
    665   1.8       chs #endif
    666   1.1  christos 
    667   1.5  christos 	error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
    668   1.1  christos 	    ap->a_cred, VREAD);
    669   1.1  christos 	if (error)
    670   1.1  christos 		return (error);
    671   1.1  christos 
    672   1.1  christos 	error = ffs_open_ea(ap->a_vp, ap->a_cred);
    673   1.1  christos 	if (error)
    674   1.1  christos 		return (error);
    675   1.1  christos 
    676   1.1  christos 	eae = ip->i_ea_area;
    677   1.1  christos 	easize = ip->i_ea_len;
    678   1.1  christos 
    679   1.1  christos 	ealen = ffs_findextattr(eae, easize, ap->a_attrnamespace, ap->a_name,
    680   1.1  christos 	    NULL, &p);
    681   1.1  christos 	if (ealen >= 0) {
    682   1.1  christos 		error = 0;
    683   1.1  christos 		if (ap->a_size != NULL)
    684   1.1  christos 			*ap->a_size = ealen;
    685   1.1  christos 		else if (ap->a_uio != NULL)
    686   1.1  christos 			error = uiomove(p, ealen, ap->a_uio);
    687   1.1  christos 	} else
    688   1.1  christos 		error = ENOATTR;
    689   1.1  christos 
    690   1.1  christos 	ffs_close_ea(ap->a_vp, 0, ap->a_cred);
    691   1.1  christos 	return (error);
    692   1.1  christos }
    693   1.1  christos 
    694   1.1  christos /*
    695   1.1  christos  * Vnode operation to set a named attribute.
    696   1.1  christos  */
    697   1.1  christos int
    698   1.1  christos ffs_setextattr(void *v)
    699   1.1  christos {
    700   1.1  christos 	struct vop_setextattr_args /* {
    701   1.1  christos 		struct vnode *a_vp;
    702   1.1  christos 		int a_attrnamespace;
    703   1.1  christos 		const char *a_name;
    704   1.1  christos 		struct uio *a_uio;
    705   1.1  christos 		kauth_cred_t a_cred;
    706   1.1  christos 		struct proc *a_p;
    707   1.1  christos 	} */ *ap = v;
    708   1.1  christos 	struct vnode *vp = ap->a_vp;
    709   1.1  christos 	struct inode *ip = VTOI(vp);
    710   1.1  christos 	struct fs *fs = ip->i_fs;
    711   1.1  christos 
    712   1.1  christos 	KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
    713  1.10       chs 	if (ip->i_ump->um_fstype == UFS1) {
    714  1.10       chs #ifdef UFS_EXTATTR
    715   1.1  christos 		return ufs_setextattr(ap);
    716  1.10       chs #else
    717  1.10       chs 		return EOPNOTSUPP;
    718  1.10       chs #endif
    719   1.1  christos 	}
    720   1.1  christos 
    721   1.1  christos 	struct extattr *eap;
    722   1.1  christos 	uint32_t ealength, ul;
    723   1.1  christos 	ssize_t ealen;
    724   1.1  christos 	int olen, eapad1, eapad2, error, i, easize;
    725   1.1  christos 	u_char *eae;
    726   1.1  christos 	void *tmp;
    727   1.1  christos 
    728   1.1  christos 	if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK)
    729   1.1  christos 		return (EOPNOTSUPP);
    730   1.1  christos 
    731   1.1  christos 	if (strlen(ap->a_name) == 0)
    732   1.1  christos 		return (EINVAL);
    733   1.1  christos 
    734   1.1  christos 	/* XXX Now unsupported API to delete EAs using NULL uio. */
    735   1.1  christos 	if (ap->a_uio == NULL)
    736   1.1  christos 		return (EOPNOTSUPP);
    737   1.1  christos 
    738   1.1  christos 	if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
    739   1.1  christos 		return (EROFS);
    740   1.1  christos 
    741   1.1  christos 	ealen = ap->a_uio->uio_resid;
    742   1.1  christos 	if (ealen < 0 || ealen > lblktosize(fs, UFS_NXADDR))
    743   1.1  christos 		return (EINVAL);
    744   1.1  christos 
    745   1.5  christos 	error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
    746   1.1  christos 	    ap->a_cred, VWRITE);
    747   1.1  christos 	if (error) {
    748   1.1  christos 
    749   1.1  christos 		/*
    750   1.1  christos 		 * ffs_lock_ea is not needed there, because the vnode
    751   1.1  christos 		 * must be exclusively locked.
    752   1.1  christos 		 */
    753   1.1  christos 		if (ip->i_ea_area != NULL && ip->i_ea_error == 0)
    754   1.1  christos 			ip->i_ea_error = error;
    755   1.1  christos 		return (error);
    756   1.1  christos 	}
    757   1.1  christos 
    758   1.1  christos 	error = ffs_open_ea(ap->a_vp, ap->a_cred);
    759   1.1  christos 	if (error)
    760   1.1  christos 		return (error);
    761   1.1  christos 
    762   1.1  christos 	ealength = sizeof(uint32_t) + 3 + strlen(ap->a_name);
    763   1.1  christos 	eapad1 = roundup2(ealength, 8) - ealength;
    764   1.1  christos 	eapad2 = roundup2(ealen, 8) - ealen;
    765   1.1  christos 	ealength += eapad1 + ealen + eapad2;
    766   1.1  christos 
    767   1.1  christos 	/*
    768   1.1  christos 	 * CEM: rewrites of the same size or smaller could be done in-place
    769   1.1  christos 	 * instead.  (We don't acquire any fine-grained locks in here either,
    770   1.1  christos 	 * so we could also do bigger writes in-place.)
    771   1.1  christos 	 */
    772   1.1  christos 	eae = malloc(ip->i_ea_len + ealength, M_TEMP, M_WAITOK);
    773   1.1  christos 	bcopy(ip->i_ea_area, eae, ip->i_ea_len);
    774   1.1  christos 	easize = ip->i_ea_len;
    775   1.1  christos 
    776   1.1  christos 	olen = ffs_findextattr(eae, easize, ap->a_attrnamespace, ap->a_name,
    777   1.1  christos 	    &eap, NULL);
    778   1.1  christos         if (olen == -1) {
    779   1.1  christos 		/* new, append at end */
    780   1.1  christos 		KASSERT(ALIGNED_TO(eae + easize, struct extattr));
    781   1.1  christos 		eap = (struct extattr *)(eae + easize);
    782   1.1  christos 		easize += ealength;
    783   1.1  christos 	} else {
    784   1.1  christos 		ul = eap->ea_length;
    785   1.1  christos 		i = (u_char *)EXTATTR_NEXT(eap) - eae;
    786   1.1  christos 		if (ul != ealength) {
    787   1.1  christos 			bcopy(EXTATTR_NEXT(eap), (u_char *)eap + ealength,
    788   1.1  christos 			    easize - i);
    789   1.1  christos 			easize += (ealength - ul);
    790   1.1  christos 		}
    791   1.1  christos 	}
    792   1.1  christos 	if (easize > lblktosize(fs, UFS_NXADDR)) {
    793   1.1  christos 		free(eae, M_TEMP);
    794   1.1  christos 		ffs_close_ea(ap->a_vp, 0, ap->a_cred);
    795   1.1  christos 		if (ip->i_ea_area != NULL && ip->i_ea_error == 0)
    796   1.1  christos 			ip->i_ea_error = ENOSPC;
    797   1.1  christos 		return (ENOSPC);
    798   1.1  christos 	}
    799   1.1  christos 	eap->ea_length = ealength;
    800   1.1  christos 	eap->ea_namespace = ap->a_attrnamespace;
    801   1.1  christos 	eap->ea_contentpadlen = eapad2;
    802   1.1  christos 	eap->ea_namelength = strlen(ap->a_name);
    803   1.1  christos 	memcpy(eap->ea_name, ap->a_name, strlen(ap->a_name));
    804   1.1  christos 	bzero(&eap->ea_name[strlen(ap->a_name)], eapad1);
    805   1.1  christos 	error = uiomove(EXTATTR_CONTENT(eap), ealen, ap->a_uio);
    806   1.1  christos 	if (error) {
    807   1.1  christos 		free(eae, M_TEMP);
    808   1.1  christos 		ffs_close_ea(ap->a_vp, 0, ap->a_cred);
    809   1.1  christos 		if (ip->i_ea_area != NULL && ip->i_ea_error == 0)
    810   1.1  christos 			ip->i_ea_error = error;
    811   1.1  christos 		return (error);
    812   1.1  christos 	}
    813   1.1  christos 	bzero((u_char *)EXTATTR_CONTENT(eap) + ealen, eapad2);
    814   1.1  christos 
    815   1.1  christos 	tmp = ip->i_ea_area;
    816   1.1  christos 	ip->i_ea_area = eae;
    817   1.1  christos 	ip->i_ea_len = easize;
    818   1.1  christos 	free(tmp, M_TEMP);
    819   1.1  christos 	error = ffs_close_ea(ap->a_vp, 1, ap->a_cred);
    820   1.1  christos 	return (error);
    821   1.1  christos }
    822   1.1  christos 
    823   1.1  christos /*
    824   1.1  christos  * Vnode operation to retrieve extended attributes on a vnode.
    825   1.1  christos  */
    826   1.1  christos int
    827   1.1  christos ffs_listextattr(void *v)
    828   1.1  christos {
    829   1.1  christos 	struct vop_listextattr_args /* {
    830   1.1  christos 		struct vnode *a_vp;
    831   1.1  christos 		int a_attrnamespace;
    832   1.1  christos 		struct uio *a_uio;
    833   1.1  christos 		size_t *a_size;
    834   1.1  christos 		kauth_cred_t a_cred;
    835   1.1  christos 		struct proc *a_p;
    836   1.1  christos 	} */ *ap = v;
    837   1.1  christos 	struct inode *ip = VTOI(ap->a_vp);
    838   1.1  christos 
    839  1.10       chs 	if (ip->i_ump->um_fstype == UFS1) {
    840  1.10       chs #ifdef UFS_EXTATTR
    841   1.1  christos 		return ufs_listextattr(ap);
    842  1.10       chs #else
    843  1.10       chs 		return EOPNOTSUPP;
    844  1.10       chs #endif
    845   1.1  christos 	}
    846   1.1  christos 
    847   1.1  christos 	struct extattr *eap, *eaend;
    848   1.1  christos 	int error, ealen;
    849   1.1  christos 
    850   1.1  christos 	if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK)
    851   1.1  christos 		return (EOPNOTSUPP);
    852   1.1  christos 
    853   1.5  christos 	error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
    854   1.1  christos 	    ap->a_cred, VREAD);
    855   1.1  christos 	if (error)
    856   1.1  christos 		return (error);
    857   1.1  christos 
    858   1.1  christos 	error = ffs_open_ea(ap->a_vp, ap->a_cred);
    859   1.1  christos 	if (error)
    860   1.1  christos 		return (error);
    861   1.1  christos 
    862   1.1  christos 	error = 0;
    863   1.1  christos 	if (ap->a_size != NULL)
    864   1.1  christos 		*ap->a_size = 0;
    865   1.1  christos 
    866   1.1  christos 	KASSERT(ALIGNED_TO(ip->i_ea_area, struct extattr));
    867   1.1  christos 	eap = (struct extattr *)ip->i_ea_area;
    868   1.1  christos 	eaend = (struct extattr *)(ip->i_ea_area + ip->i_ea_len);
    869   1.1  christos 	for (; error == 0 && eap < eaend; eap = EXTATTR_NEXT(eap)) {
    870   1.1  christos 		/* make sure this entry is complete */
    871   1.1  christos 		if (EXTATTR_NEXT(eap) > eaend)
    872   1.1  christos 			break;
    873   1.1  christos 		if (eap->ea_namespace != ap->a_attrnamespace)
    874   1.1  christos 			continue;
    875   1.1  christos 
    876   1.1  christos 		ealen = eap->ea_namelength;
    877   1.1  christos 		if (ap->a_size != NULL)
    878   1.1  christos 			*ap->a_size += ealen + 1;
    879   1.1  christos 		else if (ap->a_uio != NULL)
    880   1.1  christos 			error = uiomove(&eap->ea_namelength, ealen + 1,
    881   1.1  christos 			    ap->a_uio);
    882   1.1  christos 	}
    883   1.1  christos 
    884   1.1  christos 	ffs_close_ea(ap->a_vp, 0, ap->a_cred);
    885   1.1  christos 	return (error);
    886   1.1  christos }
    887   1.1  christos 
    888   1.1  christos /*
    889   1.1  christos  * Vnode operation to remove a named attribute.
    890   1.1  christos  */
    891   1.1  christos int
    892   1.1  christos ffs_deleteextattr(void *v)
    893   1.1  christos {
    894   1.1  christos 	struct vop_deleteextattr_args /* {
    895   1.1  christos 		struct vnode *a_vp;
    896   1.1  christos 		int a_attrnamespace;
    897   1.1  christos 		kauth_cred_t a_cred;
    898   1.1  christos 		struct proc *a_p;
    899   1.1  christos 	} */ *ap = v;
    900   1.1  christos 	struct vnode *vp = ap->a_vp;
    901   1.1  christos 	struct inode *ip = VTOI(vp);
    902   1.1  christos 
    903  1.10       chs 	if (ip->i_ump->um_fstype == UFS1) {
    904  1.10       chs #ifdef UFS_EXTATTR
    905   1.1  christos 		return ufs_deleteextattr(ap);
    906  1.10       chs #else
    907  1.10       chs 		return EOPNOTSUPP;
    908  1.10       chs #endif
    909   1.1  christos 	}
    910   1.1  christos 
    911   1.1  christos 	struct extattr *eap;
    912   1.1  christos 	uint32_t ul;
    913   1.1  christos 	int olen, error, i, easize;
    914   1.1  christos 	u_char *eae;
    915   1.1  christos 	void *tmp;
    916   1.1  christos 
    917   1.8       chs #ifdef __FreeBSD__
    918   1.1  christos 	if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK)
    919   1.1  christos 		return (EOPNOTSUPP);
    920   1.8       chs #endif
    921   1.1  christos 
    922   1.1  christos 	if (strlen(ap->a_name) == 0)
    923   1.1  christos 		return (EINVAL);
    924   1.1  christos 
    925   1.1  christos 	if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
    926   1.1  christos 		return (EROFS);
    927   1.1  christos 
    928   1.5  christos 	error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
    929   1.1  christos 	    ap->a_cred, VWRITE);
    930   1.1  christos 	if (error) {
    931   1.1  christos 		/*
    932   1.1  christos 		 * ffs_lock_ea is not needed there, because the vnode
    933   1.1  christos 		 * must be exclusively locked.
    934   1.1  christos 		 */
    935   1.1  christos 		if (ip->i_ea_area != NULL && ip->i_ea_error == 0)
    936   1.1  christos 			ip->i_ea_error = error;
    937   1.1  christos 		return (error);
    938   1.1  christos 	}
    939   1.1  christos 
    940   1.1  christos 	error = ffs_open_ea(ap->a_vp, ap->a_cred);
    941   1.1  christos 	if (error)
    942   1.1  christos 		return (error);
    943   1.1  christos 
    944   1.1  christos 	/* CEM: delete could be done in-place instead */
    945   1.1  christos 	eae = malloc(ip->i_ea_len, M_TEMP, M_WAITOK);
    946   1.1  christos 	bcopy(ip->i_ea_area, eae, ip->i_ea_len);
    947   1.1  christos 	easize = ip->i_ea_len;
    948   1.1  christos 
    949   1.1  christos 	olen = ffs_findextattr(eae, easize, ap->a_attrnamespace, ap->a_name,
    950   1.1  christos 	    &eap, NULL);
    951   1.1  christos 	if (olen == -1) {
    952   1.1  christos 		/* delete but nonexistent */
    953   1.1  christos 		free(eae, M_TEMP);
    954   1.1  christos 		ffs_close_ea(ap->a_vp, 0, ap->a_cred);
    955   1.1  christos 		return (ENOATTR);
    956   1.1  christos 	}
    957   1.1  christos 	ul = eap->ea_length;
    958   1.1  christos 	i = (u_char *)EXTATTR_NEXT(eap) - eae;
    959   1.1  christos 	bcopy(EXTATTR_NEXT(eap), eap, easize - i);
    960   1.1  christos 	easize -= ul;
    961   1.1  christos 
    962   1.1  christos 	tmp = ip->i_ea_area;
    963   1.1  christos 	ip->i_ea_area = eae;
    964   1.1  christos 	ip->i_ea_len = easize;
    965   1.1  christos 	free(tmp, M_TEMP);
    966   1.1  christos 	error = ffs_close_ea(ap->a_vp, 1, ap->a_cred);
    967   1.1  christos 	return error;
    968   1.1  christos }
    969