1 1.5 christos /* $NetBSD: ext2fs_xattr.c,v 1.5 2020/05/16 18:31:53 christos Exp $ */ 2 1.1 jdolecek 3 1.1 jdolecek /*- 4 1.1 jdolecek * Copyright (c) 2016 The NetBSD Foundation, Inc. 5 1.1 jdolecek * All rights reserved. 6 1.1 jdolecek * 7 1.1 jdolecek * This code is derived from software contributed to The NetBSD Foundation 8 1.1 jdolecek * by Jaromir Dolecek. 9 1.1 jdolecek * 10 1.1 jdolecek * Redistribution and use in source and binary forms, with or without 11 1.1 jdolecek * modification, are permitted provided that the following conditions 12 1.1 jdolecek * are met: 13 1.1 jdolecek * 1. Redistributions of source code must retain the above copyright 14 1.1 jdolecek * notice, this list of conditions and the following disclaimer. 15 1.1 jdolecek * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 jdolecek * notice, this list of conditions and the following disclaimer in the 17 1.1 jdolecek * documentation and/or other materials provided with the distribution. 18 1.1 jdolecek * 19 1.1 jdolecek * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 jdolecek * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 jdolecek * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 jdolecek * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 jdolecek * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 jdolecek * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 jdolecek * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 jdolecek * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 jdolecek * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 jdolecek * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 jdolecek * POSSIBILITY OF SUCH DAMAGE. 30 1.1 jdolecek */ 31 1.1 jdolecek 32 1.1 jdolecek #include <sys/cdefs.h> 33 1.5 christos __KERNEL_RCSID(0, "$NetBSD: ext2fs_xattr.c,v 1.5 2020/05/16 18:31:53 christos Exp $"); 34 1.1 jdolecek 35 1.1 jdolecek #include <sys/param.h> 36 1.1 jdolecek #include <sys/systm.h> 37 1.1 jdolecek #include <sys/mount.h> 38 1.1 jdolecek #include <sys/proc.h> 39 1.1 jdolecek #include <sys/file.h> 40 1.1 jdolecek #include <sys/buf.h> 41 1.1 jdolecek #include <sys/vnode.h> 42 1.1 jdolecek #include <sys/kernel.h> 43 1.1 jdolecek #include <sys/kmem.h> 44 1.1 jdolecek #include <sys/trace.h> 45 1.1 jdolecek #include <sys/resourcevar.h> 46 1.1 jdolecek #include <sys/kauth.h> 47 1.1 jdolecek #include <sys/extattr.h> 48 1.1 jdolecek 49 1.1 jdolecek #include <ufs/ufs/inode.h> 50 1.1 jdolecek #include <ufs/ufs/ufsmount.h> 51 1.1 jdolecek #include <ufs/ufs/ufs_extern.h> 52 1.1 jdolecek 53 1.1 jdolecek #include <ufs/ext2fs/ext2fs.h> 54 1.1 jdolecek #include <ufs/ext2fs/ext2fs_extern.h> 55 1.1 jdolecek #include <ufs/ext2fs/ext2fs_xattr.h> 56 1.1 jdolecek 57 1.1 jdolecek static const char * const xattr_prefix_index[] = { 58 1.1 jdolecek "", 59 1.1 jdolecek "user.", 60 1.1 jdolecek "system.posix_acl_access", 61 1.1 jdolecek "system.posix_acl_default", 62 1.1 jdolecek "trusted.", 63 1.1 jdolecek "", /* unused */ 64 1.1 jdolecek "security", 65 1.1 jdolecek "system.", 66 1.1 jdolecek "system.richacl", 67 1.1 jdolecek "c", 68 1.1 jdolecek }; 69 1.1 jdolecek 70 1.1 jdolecek static int 71 1.4 christos ext2fs_find_xattr(struct ext2fs_xattr_entry *e, uint8_t *start, uint8_t *end, 72 1.4 christos int attrnamespace, struct uio *uio, size_t *size, uint8_t name_index, 73 1.4 christos const char *name) 74 1.1 jdolecek { 75 1.1 jdolecek uint8_t *value; 76 1.1 jdolecek int error; 77 1.1 jdolecek size_t value_offs, value_len, len, old_len; 78 1.1 jdolecek 79 1.1 jdolecek /* 80 1.1 jdolecek * Individual entries follow the header. Each is aligned on 4-byte 81 1.1 jdolecek * boundary. 82 1.1 jdolecek */ 83 1.1 jdolecek for(; !EXT2FS_XATTR_IS_LAST_ENTRY(e, end); e = EXT2FS_XATTR_NEXT(e)) { 84 1.1 jdolecek /* 85 1.1 jdolecek * Only EXT2FS_XATTR_PREFIX_USER is USER, anything else 86 1.1 jdolecek * is considered SYSTEM. 87 1.1 jdolecek */ 88 1.4 christos if ((attrnamespace == EXTATTR_NAMESPACE_USER 89 1.4 christos && e->e_name_index != EXT2FS_XATTR_PREFIX_USER) || 90 1.4 christos (attrnamespace == EXTATTR_NAMESPACE_SYSTEM 91 1.4 christos && e->e_name_index == EXT2FS_XATTR_PREFIX_USER)) { 92 1.1 jdolecek continue; 93 1.1 jdolecek } 94 1.1 jdolecek 95 1.1 jdolecek if (e->e_name_index != name_index || 96 1.1 jdolecek e->e_name_len != strlen(name) || 97 1.1 jdolecek strncmp(e->e_name, name, e->e_name_len) != 0) 98 1.1 jdolecek continue; 99 1.1 jdolecek 100 1.1 jdolecek value_offs = fs2h32(e->e_value_offs); 101 1.4 christos value_len = fs2h32(e->e_value_size); 102 1.4 christos value = &start[value_offs]; 103 1.1 jdolecek 104 1.1 jdolecek /* make sure the value offset are sane */ 105 1.1 jdolecek if (&value[value_len] > end) 106 1.2 christos return EINVAL; 107 1.1 jdolecek 108 1.1 jdolecek if (uio != NULL) { 109 1.1 jdolecek /* 110 1.4 christos * Figure out maximum to transfer -- use buffer size 111 1.4 christos * and local data limit. 112 1.1 jdolecek */ 113 1.1 jdolecek len = MIN(uio->uio_resid, value_len); 114 1.1 jdolecek old_len = uio->uio_resid; 115 1.1 jdolecek uio->uio_resid = len; 116 1.1 jdolecek 117 1.1 jdolecek uio->uio_resid = old_len - (len - uio->uio_resid); 118 1.1 jdolecek 119 1.1 jdolecek error = uiomove(value, value_len, uio); 120 1.1 jdolecek if (error) 121 1.1 jdolecek return error; 122 1.1 jdolecek } 123 1.1 jdolecek 124 1.1 jdolecek /* full data size */ 125 1.1 jdolecek *size += value_len; 126 1.1 jdolecek 127 1.1 jdolecek goto found; 128 1.1 jdolecek } 129 1.1 jdolecek 130 1.1 jdolecek /* requested attribute not found */ 131 1.2 christos return ENODATA; 132 1.1 jdolecek 133 1.1 jdolecek found: 134 1.2 christos return 0; 135 1.1 jdolecek } 136 1.1 jdolecek 137 1.1 jdolecek static int 138 1.4 christos ext2fs_get_inode_xattr(struct inode *ip, int attrnamespace, struct uio *uio, 139 1.4 christos size_t *size, uint8_t name_index, const char *name) 140 1.1 jdolecek { 141 1.1 jdolecek struct ext2fs_dinode *di = ip->i_din.e2fs_din; 142 1.1 jdolecek struct ext2fs_xattr_ibody_header *h; 143 1.1 jdolecek uint8_t *start, *end; 144 1.1 jdolecek 145 1.1 jdolecek start = &((uint8_t *)di)[EXT2_REV0_DINODE_SIZE + di->e2di_extra_isize]; 146 1.4 christos h = (struct ext2fs_xattr_ibody_header *)start; 147 1.4 christos end = &((uint8_t *)di)[EXT2_DINODE_SIZE(ip->i_e2fs)]; 148 1.1 jdolecek 149 1.1 jdolecek if (end <= start || fs2h32(h->h_magic) != EXT2FS_XATTR_MAGIC) 150 1.2 christos return ENODATA; 151 1.1 jdolecek 152 1.4 christos return ext2fs_find_xattr(EXT2FS_XATTR_IFIRST(h), start, end, 153 1.4 christos attrnamespace, uio, size, name_index, name); 154 1.1 jdolecek } 155 1.1 jdolecek 156 1.1 jdolecek static int 157 1.4 christos ext2fs_get_block_xattr(struct inode *ip, int attrnamespace, struct uio *uio, 158 1.4 christos size_t *size, uint8_t name_index, const char *name) 159 1.1 jdolecek { 160 1.1 jdolecek struct ext2fs_dinode *di = ip->i_din.e2fs_din; 161 1.1 jdolecek uint8_t *start, *end; 162 1.1 jdolecek struct ext2fs_xattr_header *h; 163 1.1 jdolecek int error = 0; 164 1.1 jdolecek struct buf *bp = NULL; 165 1.1 jdolecek daddr_t xblk; 166 1.1 jdolecek 167 1.1 jdolecek xblk = di->e2di_facl; 168 1.3 jdolecek if (EXT2F_HAS_INCOMPAT_FEATURE(ip->i_e2fs, EXT2F_INCOMPAT_64BIT)) 169 1.1 jdolecek xblk |= (((daddr_t)di->e2di_facl_high) << 32); 170 1.1 jdolecek 171 1.1 jdolecek /* don't do anything if no attr block was allocated */ 172 1.1 jdolecek if (xblk == 0) 173 1.2 christos return 0; 174 1.1 jdolecek 175 1.4 christos error = bread(ip->i_devvp, fsbtodb(ip->i_e2fs, xblk), 176 1.4 christos (int)ip->i_e2fs->e2fs_bsize, 0, &bp); 177 1.1 jdolecek if (error) 178 1.1 jdolecek goto out; 179 1.1 jdolecek 180 1.1 jdolecek start = (uint8_t *)bp->b_data; 181 1.1 jdolecek h = (struct ext2fs_xattr_header *)start; 182 1.1 jdolecek end = &((uint8_t *)bp->b_data)[bp->b_bcount]; 183 1.1 jdolecek 184 1.1 jdolecek if (end <= start || fs2h32(h->h_magic) != EXT2FS_XATTR_MAGIC) 185 1.1 jdolecek goto out; 186 1.1 jdolecek 187 1.4 christos error = ext2fs_find_xattr(EXT2FS_XATTR_BFIRST(h), start, end, 188 1.4 christos attrnamespace, uio, size, name_index, name); 189 1.1 jdolecek 190 1.4 christos out: 191 1.1 jdolecek if (bp) 192 1.1 jdolecek brelse(bp, 0); 193 1.2 christos return error; 194 1.1 jdolecek } 195 1.1 jdolecek int 196 1.1 jdolecek ext2fs_getextattr(void *v) 197 1.1 jdolecek { 198 1.1 jdolecek struct vop_getextattr_args /* { 199 1.1 jdolecek const struct vnodeop_desc *a_desc; 200 1.1 jdolecek struct vnode *a_vp; 201 1.1 jdolecek int a_attrnamespace; 202 1.1 jdolecek const char *a_name; 203 1.1 jdolecek struct uio *a_uio; 204 1.1 jdolecek size_t *a_size; 205 1.1 jdolecek kauth_cred_t a_cred; 206 1.1 jdolecek } */ *ap = v; 207 1.1 jdolecek struct inode *ip = VTOI(ap->a_vp); 208 1.4 christos int error; 209 1.1 jdolecek const char *prefix, *name; 210 1.1 jdolecek uint8_t name_index; 211 1.1 jdolecek size_t name_match, valuesize = 0; 212 1.1 jdolecek 213 1.5 christos error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace, ap->a_cred, 214 1.5 christos VREAD); 215 1.1 jdolecek if (error) 216 1.2 christos return error; 217 1.1 jdolecek 218 1.1 jdolecek /* 219 1.1 jdolecek * Allow only offsets of zero to encourage the read/replace 220 1.1 jdolecek * extended attribute semantic. Otherwise we can't guarantee 221 1.1 jdolecek * atomicity, as we don't provide locks for extended attributes. 222 1.1 jdolecek */ 223 1.1 jdolecek if (ap->a_uio != NULL && ap->a_uio->uio_offset != 0) 224 1.2 christos return ENXIO; 225 1.1 jdolecek 226 1.1 jdolecek /* figure out the name index */ 227 1.1 jdolecek name = ap->a_name; 228 1.1 jdolecek name_index = 0; 229 1.1 jdolecek name_match = 0; 230 1.4 christos for(size_t i = 0; i < __arraycount(xattr_prefix_index); i++) { 231 1.1 jdolecek prefix = xattr_prefix_index[i]; 232 1.4 christos size_t l = strlen(prefix); 233 1.4 christos if (l > 0 && strncmp(ap->a_name, prefix, l) == 0 && 234 1.4 christos name_match < l) { 235 1.4 christos name = &ap->a_name[l]; 236 1.1 jdolecek name_index = i; 237 1.4 christos name_match = l; 238 1.1 jdolecek continue; 239 1.1 jdolecek } 240 1.1 jdolecek } 241 1.1 jdolecek 242 1.1 jdolecek /* fetch the xattr */ 243 1.4 christos error = ext2fs_get_inode_xattr(ip, ap->a_attrnamespace, ap->a_uio, 244 1.4 christos &valuesize, name_index, name); 245 1.1 jdolecek if (error == ENODATA) { 246 1.1 jdolecek /* not found in inode, try facl */ 247 1.4 christos error = ext2fs_get_block_xattr(ip, ap->a_attrnamespace, 248 1.4 christos ap->a_uio, &valuesize, name_index, name); 249 1.1 jdolecek } 250 1.1 jdolecek 251 1.1 jdolecek if (ap->a_size != NULL) 252 1.1 jdolecek *ap->a_size = valuesize; 253 1.1 jdolecek 254 1.2 christos return error; 255 1.1 jdolecek } 256 1.1 jdolecek 257 1.1 jdolecek int 258 1.1 jdolecek ext2fs_setextattr(void *v) 259 1.1 jdolecek { 260 1.1 jdolecek #if 0 261 1.1 jdolecek struct vop_setextattr_args /* { 262 1.1 jdolecek const struct vnodeop_desc *a_desc; 263 1.1 jdolecek struct vnode *a_vp; 264 1.1 jdolecek int a_attrnamespace; 265 1.1 jdolecek const char *a_name; 266 1.1 jdolecek struct uio *a_uio; 267 1.1 jdolecek kauth_cred_t a_cred; 268 1.1 jdolecek } */ *ap = v; 269 1.1 jdolecek 270 1.1 jdolecek /* XXX set EXT2F_COMPAT_EXTATTR in superblock after successful set */ 271 1.1 jdolecek #endif 272 1.1 jdolecek 273 1.1 jdolecek /* XXX Not implemented */ 274 1.2 christos return EOPNOTSUPP; 275 1.1 jdolecek } 276 1.1 jdolecek 277 1.1 jdolecek static int 278 1.4 christos ext2fs_list_xattr(struct ext2fs_xattr_entry *e, uint8_t *end, 279 1.4 christos int attrnamespace, int flags, struct uio *uio, size_t *size) 280 1.1 jdolecek { 281 1.1 jdolecek char name[EXT2FS_XATTR_NAME_LEN_MAX + 1]; 282 1.1 jdolecek uint8_t len; 283 1.1 jdolecek int error; 284 1.1 jdolecek const char *prefix; 285 1.1 jdolecek 286 1.1 jdolecek /* 287 1.1 jdolecek * Individual entries follow the header. Each is aligned on 4-byte 288 1.1 jdolecek * boundary. 289 1.1 jdolecek */ 290 1.1 jdolecek for(; !EXT2FS_XATTR_IS_LAST_ENTRY(e, end); e = EXT2FS_XATTR_NEXT(e)) { 291 1.1 jdolecek /* 292 1.1 jdolecek * Only EXT2FS_XATTR_PREFIX_USER is USER, anything else 293 1.1 jdolecek * is considered SYSTEM. 294 1.1 jdolecek */ 295 1.4 christos if ((attrnamespace == EXTATTR_NAMESPACE_USER 296 1.4 christos && e->e_name_index != EXT2FS_XATTR_PREFIX_USER) || 297 1.4 christos (attrnamespace == EXTATTR_NAMESPACE_SYSTEM 298 1.4 christos && e->e_name_index == EXT2FS_XATTR_PREFIX_USER)) { 299 1.1 jdolecek continue; 300 1.1 jdolecek } 301 1.1 jdolecek 302 1.4 christos if (e->e_name_index < __arraycount(xattr_prefix_index)) 303 1.1 jdolecek prefix = xattr_prefix_index[e->e_name_index]; 304 1.1 jdolecek else 305 1.1 jdolecek prefix = ""; 306 1.1 jdolecek 307 1.1 jdolecek len = snprintf(name, sizeof(name), "%s%.*s", 308 1.1 jdolecek prefix, 309 1.1 jdolecek e->e_name_len, e->e_name); 310 1.1 jdolecek 311 1.1 jdolecek if (uio != NULL) { 312 1.1 jdolecek if (flags & EXTATTR_LIST_LENPREFIX) { 313 1.1 jdolecek /* write name length */ 314 1.4 christos error = uiomove(&len, sizeof(uint8_t), uio); 315 1.4 christos if (error) 316 1.4 christos return error; 317 1.1 jdolecek } else { 318 1.1 jdolecek /* include trailing NUL */ 319 1.1 jdolecek len++; 320 1.1 jdolecek } 321 1.1 jdolecek 322 1.1 jdolecek error = uiomove(name, len, uio); 323 1.1 jdolecek if (error) 324 1.1 jdolecek return error; 325 1.1 jdolecek 326 1.1 jdolecek *size += len; 327 1.1 jdolecek } 328 1.1 jdolecek } 329 1.1 jdolecek 330 1.2 christos return 0; 331 1.1 jdolecek } 332 1.1 jdolecek 333 1.1 jdolecek static int 334 1.4 christos ext2fs_list_inode_xattr(struct inode *ip, int attrnamespace, int flags, 335 1.4 christos struct uio *uio, size_t *size) 336 1.1 jdolecek { 337 1.1 jdolecek struct ext2fs_dinode *di = ip->i_din.e2fs_din; 338 1.1 jdolecek void *start, *end; 339 1.1 jdolecek struct ext2fs_xattr_ibody_header *h; 340 1.1 jdolecek 341 1.1 jdolecek start = &((uint8_t *)di)[EXT2_REV0_DINODE_SIZE + di->e2di_extra_isize]; 342 1.1 jdolecek h = start; 343 1.1 jdolecek end = &((uint8_t *)di)[EXT2_DINODE_SIZE(ip->i_e2fs)]; 344 1.1 jdolecek 345 1.1 jdolecek if (end <= start || fs2h32(h->h_magic) != EXT2FS_XATTR_MAGIC) 346 1.2 christos return 0; 347 1.1 jdolecek 348 1.4 christos return ext2fs_list_xattr(EXT2FS_XATTR_IFIRST(h), end, attrnamespace, 349 1.4 christos flags, uio, size); 350 1.1 jdolecek } 351 1.1 jdolecek 352 1.1 jdolecek static int 353 1.4 christos ext2fs_list_block_xattr(struct inode *ip, int attrnamespace, int flags, 354 1.4 christos struct uio *uio, size_t *size) 355 1.1 jdolecek { 356 1.1 jdolecek struct ext2fs_dinode *di = ip->i_din.e2fs_din; 357 1.1 jdolecek void *end; 358 1.1 jdolecek struct ext2fs_xattr_header *h; 359 1.1 jdolecek int error = 0; 360 1.1 jdolecek struct buf *bp = NULL; 361 1.1 jdolecek daddr_t xblk; 362 1.1 jdolecek 363 1.1 jdolecek xblk = di->e2di_facl; 364 1.3 jdolecek if (EXT2F_HAS_INCOMPAT_FEATURE(ip->i_e2fs, EXT2F_INCOMPAT_64BIT)) 365 1.1 jdolecek xblk |= (((daddr_t)di->e2di_facl_high) << 32); 366 1.1 jdolecek 367 1.1 jdolecek /* don't do anything if no attr block was allocated */ 368 1.1 jdolecek if (xblk == 0) 369 1.2 christos return 0; 370 1.1 jdolecek 371 1.4 christos error = bread(ip->i_devvp, fsbtodb(ip->i_e2fs, xblk), 372 1.4 christos (int)ip->i_e2fs->e2fs_bsize, 0, &bp); 373 1.1 jdolecek if (error) 374 1.1 jdolecek goto out; 375 1.1 jdolecek 376 1.4 christos h = (struct ext2fs_xattr_header *)bp->b_data; 377 1.4 christos end = &((uint8_t *)bp->b_data)[bp->b_bcount]; 378 1.1 jdolecek 379 1.1 jdolecek if (end <= (void *)h || fs2h32(h->h_magic) != EXT2FS_XATTR_MAGIC) 380 1.1 jdolecek goto out; 381 1.1 jdolecek 382 1.4 christos error = ext2fs_list_xattr(EXT2FS_XATTR_BFIRST(h), end, attrnamespace, 383 1.4 christos flags, uio, size); 384 1.1 jdolecek 385 1.4 christos out: 386 1.1 jdolecek if (bp) 387 1.1 jdolecek brelse(bp, 0); 388 1.2 christos return error; 389 1.1 jdolecek } 390 1.1 jdolecek 391 1.1 jdolecek int 392 1.1 jdolecek ext2fs_listextattr(void *v) 393 1.1 jdolecek { 394 1.1 jdolecek struct vop_listextattr_args /* { 395 1.1 jdolecek const struct vnodeop_desc *a_desc; 396 1.1 jdolecek struct vnode *a_vp; 397 1.1 jdolecek int a_attrnamespace; 398 1.1 jdolecek struct uio *a_uio; 399 1.1 jdolecek size_t *a_size; 400 1.1 jdolecek int a_flag; 401 1.1 jdolecek kauth_cred_t a_cred; 402 1.1 jdolecek } */ *ap = v; 403 1.1 jdolecek struct inode *ip = VTOI(ap->a_vp); 404 1.1 jdolecek int error; 405 1.1 jdolecek size_t listsize = 0; 406 1.1 jdolecek 407 1.3 jdolecek if (!EXT2F_HAS_COMPAT_FEATURE(ip->i_e2fs, EXT2F_COMPAT_EXTATTR)) { 408 1.1 jdolecek /* no EA on the filesystem */ 409 1.1 jdolecek goto out; 410 1.1 jdolecek } 411 1.1 jdolecek 412 1.5 christos error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace, ap->a_cred, 413 1.5 christos VREAD); 414 1.1 jdolecek if (error) 415 1.2 christos return error; 416 1.1 jdolecek 417 1.1 jdolecek /* 418 1.1 jdolecek * Allow only offsets of zero to encourage the read/replace 419 1.1 jdolecek * extended attribute semantic. Otherwise we can't guarantee 420 1.1 jdolecek * atomicity, as we don't provide locks for extended attributes. 421 1.1 jdolecek * XXX revisit - vnode lock enough? 422 1.1 jdolecek */ 423 1.1 jdolecek if (ap->a_uio != NULL && ap->a_uio->uio_offset != 0) 424 1.2 christos return ENXIO; 425 1.1 jdolecek 426 1.1 jdolecek /* fetch inode xattrs */ 427 1.4 christos error = ext2fs_list_inode_xattr(ip, ap->a_attrnamespace, ap->a_flag, 428 1.4 christos ap->a_uio, &listsize); 429 1.1 jdolecek if (error) 430 1.2 christos return error; 431 1.1 jdolecek 432 1.4 christos error = ext2fs_list_block_xattr(ip, ap->a_attrnamespace, ap->a_flag, 433 1.4 christos ap->a_uio, &listsize); 434 1.1 jdolecek if (error) 435 1.2 christos return error; 436 1.1 jdolecek 437 1.4 christos out: 438 1.1 jdolecek if (ap->a_size != NULL) 439 1.1 jdolecek *ap->a_size = listsize; 440 1.1 jdolecek 441 1.2 christos return 0; 442 1.1 jdolecek } 443 1.1 jdolecek 444 1.1 jdolecek int 445 1.1 jdolecek ext2fs_deleteextattr(void *v) 446 1.1 jdolecek { 447 1.1 jdolecek #if 0 448 1.1 jdolecek struct vop_deleteextattr_args /* { 449 1.1 jdolecek const struct vnodeop_desc *a_desc; 450 1.1 jdolecek struct vnode *a_vp; 451 1.1 jdolecek int a_attrnamespace; 452 1.1 jdolecek const char *a_name; 453 1.1 jdolecek kauth_cred_t a_cred; 454 1.1 jdolecek } */ *ap = v; 455 1.1 jdolecek #endif 456 1.1 jdolecek 457 1.1 jdolecek /* XXX Not implemented */ 458 1.2 christos return EOPNOTSUPP; 459 1.1 jdolecek } 460