Fri Aug 12 19:04:03 2016 UTC ()
add support for extended attributes in ext2fs for ext3/ext4; read-only for now


(jdolecek)
diff -r1.42 -r1.43 src/sys/ufs/files.ufs
diff -r1.41 -r1.42 src/sys/ufs/ext2fs/ext2fs.h
diff -r1.35 -r1.36 src/sys/ufs/ext2fs/ext2fs_dinode.h
diff -r1.120 -r1.121 src/sys/ufs/ext2fs/ext2fs_vnops.c
diff -r0 -r1.1 src/sys/ufs/ext2fs/ext2fs_xattr.c
diff -r0 -r1.1 src/sys/ufs/ext2fs/ext2fs_xattr.h

cvs diff -r1.42 -r1.43 src/sys/ufs/files.ufs (expand / switch to unified diff)

--- src/sys/ufs/files.ufs 2016/06/24 17:21:56 1.42
+++ src/sys/ufs/files.ufs 2016/08/12 19:04:03 1.43
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1# $NetBSD: files.ufs,v 1.42 2016/06/24 17:21:56 christos Exp $ 1# $NetBSD: files.ufs,v 1.43 2016/08/12 19:04:03 jdolecek Exp $
2 2
3deffs FFS 3deffs FFS
4deffs EXT2FS 4deffs EXT2FS
5deffs MFS 5deffs MFS
6deffs LFS 6deffs LFS
7deffs CHFS 7deffs CHFS
8 8
9defflag opt_ffs.h FFS_EI FFS_NO_SNAPSHOT APPLE_UFS 9defflag opt_ffs.h FFS_EI FFS_NO_SNAPSHOT APPLE_UFS
10 UFS_DIRHASH UFS_EXTATTR 10 UFS_DIRHASH UFS_EXTATTR
11 11
12defflag opt_lfs.h LFS_EI LFS_KERNEL_RFW 12defflag opt_lfs.h LFS_EI LFS_KERNEL_RFW
13 LFS_DIRHASH LFS_EXTATTR 13 LFS_DIRHASH LFS_EXTATTR
14 LFS_QUOTA LFS_QUOTA2 14 LFS_QUOTA LFS_QUOTA2
@@ -18,26 +18,27 @@ file ufs/ext2fs/ext2fs_alloc.c ext2fs @@ -18,26 +18,27 @@ file ufs/ext2fs/ext2fs_alloc.c ext2fs
18file ufs/ext2fs/ext2fs_balloc.c ext2fs 18file ufs/ext2fs/ext2fs_balloc.c ext2fs
19file ufs/ext2fs/ext2fs_bmap.c ext2fs 19file ufs/ext2fs/ext2fs_bmap.c ext2fs
20file ufs/ext2fs/ext2fs_bswap.c ext2fs 20file ufs/ext2fs/ext2fs_bswap.c ext2fs
21file ufs/ext2fs/ext2fs_hash.c ext2fs 21file ufs/ext2fs/ext2fs_hash.c ext2fs
22file ufs/ext2fs/ext2fs_htree.c ext2fs 22file ufs/ext2fs/ext2fs_htree.c ext2fs
23file ufs/ext2fs/ext2fs_extents.c ext2fs 23file ufs/ext2fs/ext2fs_extents.c ext2fs
24file ufs/ext2fs/ext2fs_inode.c ext2fs 24file ufs/ext2fs/ext2fs_inode.c ext2fs
25file ufs/ext2fs/ext2fs_lookup.c ext2fs 25file ufs/ext2fs/ext2fs_lookup.c ext2fs
26file ufs/ext2fs/ext2fs_readwrite.c ext2fs 26file ufs/ext2fs/ext2fs_readwrite.c ext2fs
27file ufs/ext2fs/ext2fs_rename.c ext2fs 27file ufs/ext2fs/ext2fs_rename.c ext2fs
28file ufs/ext2fs/ext2fs_subr.c ext2fs 28file ufs/ext2fs/ext2fs_subr.c ext2fs
29file ufs/ext2fs/ext2fs_vfsops.c ext2fs 29file ufs/ext2fs/ext2fs_vfsops.c ext2fs
30file ufs/ext2fs/ext2fs_vnops.c ext2fs 30file ufs/ext2fs/ext2fs_vnops.c ext2fs
 31file ufs/ext2fs/ext2fs_xattr.c ext2fs
31 32
32define chfs: vfs, ffs 33define chfs: vfs, ffs
33file ufs/chfs/ebh.c chfs 34file ufs/chfs/ebh.c chfs
34file ufs/chfs/chfs_scan.c chfs 35file ufs/chfs/chfs_scan.c chfs
35file ufs/chfs/chfs_write.c chfs 36file ufs/chfs/chfs_write.c chfs
36file ufs/chfs/chfs_vnode_cache.c chfs 37file ufs/chfs/chfs_vnode_cache.c chfs
37file ufs/chfs/chfs_erase.c chfs 38file ufs/chfs/chfs_erase.c chfs
38file ufs/chfs/chfs_build.c chfs 39file ufs/chfs/chfs_build.c chfs
39file ufs/chfs/chfs_wbuf.c chfs 40file ufs/chfs/chfs_wbuf.c chfs
40file ufs/chfs/chfs_vnops.c chfs 41file ufs/chfs/chfs_vnops.c chfs
41file ufs/chfs/chfs_gc.c chfs 42file ufs/chfs/chfs_gc.c chfs
42file ufs/chfs/chfs_nodeops.c chfs 43file ufs/chfs/chfs_nodeops.c chfs
43file ufs/chfs/chfs_malloc.c chfs 44file ufs/chfs/chfs_malloc.c chfs

cvs diff -r1.41 -r1.42 src/sys/ufs/ext2fs/ext2fs.h (expand / switch to unified diff)

--- src/sys/ufs/ext2fs/ext2fs.h 2016/08/05 21:22:06 1.41
+++ src/sys/ufs/ext2fs/ext2fs.h 2016/08/12 19:04:03 1.42
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: ext2fs.h,v 1.41 2016/08/05 21:22:06 jdolecek Exp $ */ 1/* $NetBSD: ext2fs.h,v 1.42 2016/08/12 19:04:03 jdolecek Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 1982, 1986, 1993 4 * Copyright (c) 1982, 1986, 1993
5 * The Regents of the University of California. All rights reserved. 5 * The Regents of the University of California. All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright 12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the 13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution. 14 * documentation and/or other materials provided with the distribution.
@@ -331,26 +331,34 @@ struct m_ext2fs { @@ -331,26 +331,34 @@ struct m_ext2fs {
331 "\015INCOMPAT_DIRDATA" \ 331 "\015INCOMPAT_DIRDATA" \
332 "\014" \ 332 "\014" \
333 "\013INCOMPAT_EA_INODE" \ 333 "\013INCOMPAT_EA_INODE" \
334 "\012INCOMPAT_FLEX_BG" \ 334 "\012INCOMPAT_FLEX_BG" \
335 "\011INCOMPAT_MMP" \ 335 "\011INCOMPAT_MMP" \
336 "\010INCOMPAT_64BIT" \ 336 "\010INCOMPAT_64BIT" \
337 "\07INCOMPAT_EXTENTS" \ 337 "\07INCOMPAT_EXTENTS" \
338 "\05INCOMPAT_META_BG" \ 338 "\05INCOMPAT_META_BG" \
339 "\04INCOMPAT_USES_JOURNAL" \ 339 "\04INCOMPAT_USES_JOURNAL" \
340 "\03INCOMPAT_REPLAY_JOURNAL" \ 340 "\03INCOMPAT_REPLAY_JOURNAL" \
341 "\02INCOMPAT_FTYPE" \ 341 "\02INCOMPAT_FTYPE" \
342 "\01INCOMPAT_COMP" 342 "\01INCOMPAT_COMP"
343 343
 344#define EXT2F_HAS_COMPAT_FEATURE(ip, feature) \
 345 (ip)->i_e2fs->e2fs.e2fs_rev >= E2FS_REV1 && \
 346 ((ip)->i_e2fs->e2fs.e2fs_features_compat & (feature)) != 0
 347
 348#define EXT2F_HAS_INCOMPAT_FEATURE(ip, feature) \
 349 (ip)->i_e2fs->e2fs.e2fs_rev >= E2FS_REV1 && \
 350 ((ip)->i_e2fs->e2fs.e2fs_features_incompat & (feature)) != 0
 351
344/* 352/*
345 * Features supported in this implementation 353 * Features supported in this implementation
346 * 354 *
347 * We support the following REV1 features: 355 * We support the following REV1 features:
348 * - EXT2F_ROCOMPAT_SPARSESUPER 356 * - EXT2F_ROCOMPAT_SPARSESUPER
349 * superblock backups stored only in cg_has_sb(bno) groups 357 * superblock backups stored only in cg_has_sb(bno) groups
350 * - EXT2F_ROCOMPAT_LARGEFILE 358 * - EXT2F_ROCOMPAT_LARGEFILE
351 * use e2di_size_high in struct ext2fs_dinode to store  359 * use e2di_size_high in struct ext2fs_dinode to store
352 * upper 32bit of size for >2GB files 360 * upper 32bit of size for >2GB files
353 * - EXT2F_INCOMPAT_FTYPE 361 * - EXT2F_INCOMPAT_FTYPE
354 * store file type to e2d_type in struct ext2fs_direct 362 * store file type to e2d_type in struct ext2fs_direct
355 * (on REV0 e2d_namlen is uint16_t and no e2d_type, like ffs) 363 * (on REV0 e2d_namlen is uint16_t and no e2d_type, like ffs)
356 */ 364 */

cvs diff -r1.35 -r1.36 src/sys/ufs/ext2fs/ext2fs_dinode.h (expand / switch to unified diff)

--- src/sys/ufs/ext2fs/ext2fs_dinode.h 2016/08/06 09:29:28 1.35
+++ src/sys/ufs/ext2fs/ext2fs_dinode.h 2016/08/12 19:04:03 1.36
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: ext2fs_dinode.h,v 1.35 2016/08/06 09:29:28 jdolecek Exp $ */ 1/* $NetBSD: ext2fs_dinode.h,v 1.36 2016/08/12 19:04:03 jdolecek Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 1982, 1989, 1993 4 * Copyright (c) 1982, 1989, 1993
5 * The Regents of the University of California. All rights reserved. 5 * The Regents of the University of California. All rights reserved.
6 * (c) UNIX System Laboratories, Inc. 6 * (c) UNIX System Laboratories, Inc.
7 * All or some portions of this file are derived from material licensed 7 * All or some portions of this file are derived from material licensed
8 * to the University of California by American Telephone and Telegraph 8 * to the University of California by American Telephone and Telegraph
9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
10 * the permission of UNIX System Laboratories, Inc. 10 * the permission of UNIX System Laboratories, Inc.
11 * 11 *
12 * Redistribution and use in source and binary forms, with or without 12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions 13 * modification, are permitted provided that the following conditions
14 * are met: 14 * are met:
@@ -113,31 +113,31 @@ struct ext2fs_dinode { @@ -113,31 +113,31 @@ struct ext2fs_dinode {
113 uint32_t e2di_size; /* 4: Size (in bytes) */ 113 uint32_t e2di_size; /* 4: Size (in bytes) */
114 uint32_t e2di_atime; /* 8: Access time */ 114 uint32_t e2di_atime; /* 8: Access time */
115 uint32_t e2di_ctime; /* 12: Create time */ 115 uint32_t e2di_ctime; /* 12: Create time */
116 uint32_t e2di_mtime; /* 16: Modification time */ 116 uint32_t e2di_mtime; /* 16: Modification time */
117 uint32_t e2di_dtime; /* 20: Deletion time */ 117 uint32_t e2di_dtime; /* 20: Deletion time */
118 uint16_t e2di_gid; /* 24: Owner GID */ 118 uint16_t e2di_gid; /* 24: Owner GID */
119 uint16_t e2di_nlink; /* 26: File link count */ 119 uint16_t e2di_nlink; /* 26: File link count */
120 uint32_t e2di_nblock; /* 28: Blocks count */ 120 uint32_t e2di_nblock; /* 28: Blocks count */
121 uint32_t e2di_flags; /* 32: Status flags (chflags) */ 121 uint32_t e2di_flags; /* 32: Status flags (chflags) */
122 uint32_t e2di_version; /* 36: was reserved1 */ 122 uint32_t e2di_version; /* 36: was reserved1 */
123 uint32_t e2di_blocks[EXT2FS_NDADDR+EXT2FS_NIADDR]; 123 uint32_t e2di_blocks[EXT2FS_NDADDR+EXT2FS_NIADDR];
124 /* 40: disk blocks */ 124 /* 40: disk blocks */
125 uint32_t e2di_gen; /* 100: generation number */ 125 uint32_t e2di_gen; /* 100: generation number */
126 uint32_t e2di_facl; /* 104: file ACL (not implemented) (ext3) */ 126 uint32_t e2di_facl; /* 104: file ACL (ext3) */
127 uint32_t e2di_size_high; /* 108: Size (in bytes) high */ 127 uint32_t e2di_size_high; /* 108: Size (in bytes) high */
128 uint32_t e2di_obso_faddr;/* 112: obsolete fragment address (ext2) */ 128 uint32_t e2di_obso_faddr;/* 112: obsolete fragment address (ext2) */
129 uint16_t e2di_nblock_high; /* 116: Blocks count bits 47:32 (ext4) */ 129 uint16_t e2di_nblock_high; /* 116: Blocks count bits 47:32 (ext4) */
130 uint16_t e2di_facl_high; /* 118: file ACL bits 47:32 (ext4) */ 130 uint16_t e2di_facl_high; /* 118: file ACL bits 47:32 (ext4/64bit) */
131 uint16_t e2di_uid_high; /* 120: Owner UID top 16 bits (ext4) */ 131 uint16_t e2di_uid_high; /* 120: Owner UID top 16 bits (ext4) */
132 uint16_t e2di_gid_high; /* 122: Owner GID top 16 bits (ext4) */ 132 uint16_t e2di_gid_high; /* 122: Owner GID top 16 bits (ext4) */
133 uint16_t e2di_checksum_low; /* 124: crc LE (not implemented) (ext4) */ 133 uint16_t e2di_checksum_low; /* 124: crc LE (not implemented) (ext4) */
134 uint16_t e2di_reserved; /* 126: reserved */ 134 uint16_t e2di_reserved; /* 126: reserved */
135 uint16_t e2di_extra_isize; /* 128: inode extra size (over 128) actually used (ext4) */ 135 uint16_t e2di_extra_isize; /* 128: inode extra size (over 128) actually used (ext4) */
136 uint16_t e2di_checksum_high; /* 130: crc BE (not implemented) (ext4) */ 136 uint16_t e2di_checksum_high; /* 130: crc BE (not implemented) (ext4) */
137 uint32_t e2di_ctime_extra; /* 132: ctime (nsec << 2 | high epoch) (ext4) */ 137 uint32_t e2di_ctime_extra; /* 132: ctime (nsec << 2 | high epoch) (ext4) */
138 uint32_t e2di_mtime_extra; /* 136: mtime (nsec << 2 | high epoch) (ext4) */ 138 uint32_t e2di_mtime_extra; /* 136: mtime (nsec << 2 | high epoch) (ext4) */
139 uint32_t e2di_atime_extra; /* 140: atime (nsec << 2 | high epoch) (ext4) */ 139 uint32_t e2di_atime_extra; /* 140: atime (nsec << 2 | high epoch) (ext4) */
140 uint32_t e2di_crtime; /* 144: creation time (epoch) (ext4) */ 140 uint32_t e2di_crtime; /* 144: creation time (epoch) (ext4) */
141 uint32_t e2di_crtime_extra; /* 148: creation time (nsec << 2 | high epoch) (ext4) */ 141 uint32_t e2di_crtime_extra; /* 148: creation time (nsec << 2 | high epoch) (ext4) */
142 uint32_t e2di_version_high; /* 152: version high (ext4) */ 142 uint32_t e2di_version_high; /* 152: version high (ext4) */
143 uint32_t e2di_projid; /* 156: project id (not implemented) (ext4) */ 143 uint32_t e2di_projid; /* 156: project id (not implemented) (ext4) */

cvs diff -r1.120 -r1.121 src/sys/ufs/ext2fs/ext2fs_vnops.c (expand / switch to unified diff)

--- src/sys/ufs/ext2fs/ext2fs_vnops.c 2016/08/05 20:15:41 1.120
+++ src/sys/ufs/ext2fs/ext2fs_vnops.c 2016/08/12 19:04:03 1.121
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: ext2fs_vnops.c,v 1.120 2016/08/05 20:15:41 jdolecek Exp $ */ 1/* $NetBSD: ext2fs_vnops.c,v 1.121 2016/08/12 19:04:03 jdolecek Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 1982, 1986, 1989, 1993 4 * Copyright (c) 1982, 1986, 1989, 1993
5 * The Regents of the University of California. All rights reserved. 5 * The Regents of the University of California. All rights reserved.
6 * (c) UNIX System Laboratories, Inc. 6 * (c) UNIX System Laboratories, Inc.
7 * All or some portions of this file are derived from material licensed 7 * All or some portions of this file are derived from material licensed
8 * to the University of California by American Telephone and Telegraph 8 * to the University of California by American Telephone and Telegraph
9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
10 * the permission of UNIX System Laboratories, Inc. 10 * the permission of UNIX System Laboratories, Inc.
11 * 11 *
12 * Redistribution and use in source and binary forms, with or without 12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions 13 * modification, are permitted provided that the following conditions
14 * are met: 14 * are met:
@@ -55,27 +55,27 @@ @@ -55,27 +55,27 @@
55 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 55 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
56 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 56 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
57 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 57 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
58 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 58 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
59 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 59 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
60 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 60 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
61 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 61 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
62 * 62 *
63 * @(#)ufs_vnops.c 8.14 (Berkeley) 10/26/94 63 * @(#)ufs_vnops.c 8.14 (Berkeley) 10/26/94
64 * Modified for ext2fs by Manuel Bouyer. 64 * Modified for ext2fs by Manuel Bouyer.
65 */ 65 */
66 66
67#include <sys/cdefs.h> 67#include <sys/cdefs.h>
68__KERNEL_RCSID(0, "$NetBSD: ext2fs_vnops.c,v 1.120 2016/08/05 20:15:41 jdolecek Exp $"); 68__KERNEL_RCSID(0, "$NetBSD: ext2fs_vnops.c,v 1.121 2016/08/12 19:04:03 jdolecek Exp $");
69 69
70#include <sys/param.h> 70#include <sys/param.h>
71#include <sys/systm.h> 71#include <sys/systm.h>
72#include <sys/resourcevar.h> 72#include <sys/resourcevar.h>
73#include <sys/kernel.h> 73#include <sys/kernel.h>
74#include <sys/file.h> 74#include <sys/file.h>
75#include <sys/stat.h> 75#include <sys/stat.h>
76#include <sys/buf.h> 76#include <sys/buf.h>
77#include <sys/proc.h> 77#include <sys/proc.h>
78#include <sys/mount.h> 78#include <sys/mount.h>
79#include <sys/namei.h> 79#include <sys/namei.h>
80#include <sys/vnode.h> 80#include <sys/vnode.h>
81#include <sys/lockf.h> 81#include <sys/lockf.h>
@@ -84,26 +84,27 @@ __KERNEL_RCSID(0, "$NetBSD: ext2fs_vnops @@ -84,26 +84,27 @@ __KERNEL_RCSID(0, "$NetBSD: ext2fs_vnops
84#include <sys/kauth.h> 84#include <sys/kauth.h>
85 85
86#include <miscfs/fifofs/fifo.h> 86#include <miscfs/fifofs/fifo.h>
87#include <miscfs/genfs/genfs.h> 87#include <miscfs/genfs/genfs.h>
88#include <miscfs/specfs/specdev.h> 88#include <miscfs/specfs/specdev.h>
89 89
90#include <ufs/ufs/inode.h> 90#include <ufs/ufs/inode.h>
91#include <ufs/ufs/ufs_extern.h> 91#include <ufs/ufs/ufs_extern.h>
92#include <ufs/ufs/ufsmount.h> 92#include <ufs/ufs/ufsmount.h>
93 93
94#include <ufs/ext2fs/ext2fs.h> 94#include <ufs/ext2fs/ext2fs.h>
95#include <ufs/ext2fs/ext2fs_extern.h> 95#include <ufs/ext2fs/ext2fs_extern.h>
96#include <ufs/ext2fs/ext2fs_dir.h> 96#include <ufs/ext2fs/ext2fs_dir.h>
 97#include <ufs/ext2fs/ext2fs_xattr.h>
97 98
98extern int prtactive; 99extern int prtactive;
99 100
100static int ext2fs_chmod(struct vnode *, int, kauth_cred_t, struct lwp *); 101static int ext2fs_chmod(struct vnode *, int, kauth_cred_t, struct lwp *);
101static int ext2fs_chown(struct vnode *, uid_t, gid_t, kauth_cred_t, 102static int ext2fs_chown(struct vnode *, uid_t, gid_t, kauth_cred_t,
102 struct lwp *); 103 struct lwp *);
103 104
104union _qcvt { 105union _qcvt {
105 int64_t qcvt; 106 int64_t qcvt;
106 int32_t val[2]; 107 int32_t val[2];
107}; 108};
108 109
109#define SETHIGH(q, h) { \ 110#define SETHIGH(q, h) { \
@@ -1172,26 +1173,30 @@ const struct vnodeopv_entry_desc ext2fs_ @@ -1172,26 +1173,30 @@ const struct vnodeopv_entry_desc ext2fs_
1172 { &vop_inactive_desc, ext2fs_inactive }, /* inactive */ 1173 { &vop_inactive_desc, ext2fs_inactive }, /* inactive */
1173 { &vop_reclaim_desc, ext2fs_reclaim }, /* reclaim */ 1174 { &vop_reclaim_desc, ext2fs_reclaim }, /* reclaim */
1174 { &vop_lock_desc, ufs_lock }, /* lock */ 1175 { &vop_lock_desc, ufs_lock }, /* lock */
1175 { &vop_unlock_desc, ufs_unlock }, /* unlock */ 1176 { &vop_unlock_desc, ufs_unlock }, /* unlock */
1176 { &vop_bmap_desc, ext2fs_bmap }, /* bmap */ 1177 { &vop_bmap_desc, ext2fs_bmap }, /* bmap */
1177 { &vop_strategy_desc, ufs_strategy }, /* strategy */ 1178 { &vop_strategy_desc, ufs_strategy }, /* strategy */
1178 { &vop_print_desc, ufs_print }, /* print */ 1179 { &vop_print_desc, ufs_print }, /* print */
1179 { &vop_islocked_desc, ufs_islocked }, /* islocked */ 1180 { &vop_islocked_desc, ufs_islocked }, /* islocked */
1180 { &vop_pathconf_desc, ufs_pathconf }, /* pathconf */ 1181 { &vop_pathconf_desc, ufs_pathconf }, /* pathconf */
1181 { &vop_advlock_desc, ext2fs_advlock }, /* advlock */ 1182 { &vop_advlock_desc, ext2fs_advlock }, /* advlock */
1182 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 1183 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */
1183 { &vop_getpages_desc, genfs_getpages }, /* getpages */ 1184 { &vop_getpages_desc, genfs_getpages }, /* getpages */
1184 { &vop_putpages_desc, genfs_putpages }, /* putpages */ 1185 { &vop_putpages_desc, genfs_putpages }, /* putpages */
 1186 { &vop_getextattr_desc, ext2fs_getextattr }, /* getextattr */
 1187 { &vop_setextattr_desc, ext2fs_setextattr }, /* setextattr */
 1188 { &vop_listextattr_desc, ext2fs_listextattr }, /* listextattr */
 1189 { &vop_deleteextattr_desc, ext2fs_deleteextattr },/* deleteextattr */
1185 { NULL, NULL } 1190 { NULL, NULL }
1186}; 1191};
1187const struct vnodeopv_desc ext2fs_vnodeop_opv_desc = 1192const struct vnodeopv_desc ext2fs_vnodeop_opv_desc =
1188 { &ext2fs_vnodeop_p, ext2fs_vnodeop_entries }; 1193 { &ext2fs_vnodeop_p, ext2fs_vnodeop_entries };
1189 1194
1190int (**ext2fs_specop_p)(void *); 1195int (**ext2fs_specop_p)(void *);
1191const struct vnodeopv_entry_desc ext2fs_specop_entries[] = { 1196const struct vnodeopv_entry_desc ext2fs_specop_entries[] = {
1192 { &vop_default_desc, vn_default_error }, 1197 { &vop_default_desc, vn_default_error },
1193 { &vop_lookup_desc, spec_lookup }, /* lookup */ 1198 { &vop_lookup_desc, spec_lookup }, /* lookup */
1194 { &vop_create_desc, spec_create }, /* create */ 1199 { &vop_create_desc, spec_create }, /* create */
1195 { &vop_mknod_desc, spec_mknod }, /* mknod */ 1200 { &vop_mknod_desc, spec_mknod }, /* mknod */
1196 { &vop_open_desc, spec_open }, /* open */ 1201 { &vop_open_desc, spec_open }, /* open */
1197 { &vop_close_desc, ufsspec_close }, /* close */ 1202 { &vop_close_desc, ufsspec_close }, /* close */
@@ -1222,26 +1227,30 @@ const struct vnodeopv_entry_desc ext2fs_ @@ -1222,26 +1227,30 @@ const struct vnodeopv_entry_desc ext2fs_
1222 { &vop_inactive_desc, ext2fs_inactive }, /* inactive */ 1227 { &vop_inactive_desc, ext2fs_inactive }, /* inactive */
1223 { &vop_reclaim_desc, ext2fs_reclaim }, /* reclaim */ 1228 { &vop_reclaim_desc, ext2fs_reclaim }, /* reclaim */
1224 { &vop_lock_desc, ufs_lock }, /* lock */ 1229 { &vop_lock_desc, ufs_lock }, /* lock */
1225 { &vop_unlock_desc, ufs_unlock }, /* unlock */ 1230 { &vop_unlock_desc, ufs_unlock }, /* unlock */
1226 { &vop_bmap_desc, spec_bmap }, /* bmap */ 1231 { &vop_bmap_desc, spec_bmap }, /* bmap */
1227 { &vop_strategy_desc, spec_strategy }, /* strategy */ 1232 { &vop_strategy_desc, spec_strategy }, /* strategy */
1228 { &vop_print_desc, ufs_print }, /* print */ 1233 { &vop_print_desc, ufs_print }, /* print */
1229 { &vop_islocked_desc, ufs_islocked }, /* islocked */ 1234 { &vop_islocked_desc, ufs_islocked }, /* islocked */
1230 { &vop_pathconf_desc, spec_pathconf }, /* pathconf */ 1235 { &vop_pathconf_desc, spec_pathconf }, /* pathconf */
1231 { &vop_advlock_desc, spec_advlock }, /* advlock */ 1236 { &vop_advlock_desc, spec_advlock }, /* advlock */
1232 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 1237 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */
1233 { &vop_getpages_desc, spec_getpages }, /* getpages */ 1238 { &vop_getpages_desc, spec_getpages }, /* getpages */
1234 { &vop_putpages_desc, spec_putpages }, /* putpages */ 1239 { &vop_putpages_desc, spec_putpages }, /* putpages */
 1240 { &vop_getextattr_desc, ext2fs_getextattr }, /* getextattr */
 1241 { &vop_setextattr_desc, ext2fs_setextattr }, /* setextattr */
 1242 { &vop_listextattr_desc, ext2fs_listextattr }, /* listextattr */
 1243 { &vop_deleteextattr_desc, ext2fs_deleteextattr },/* deleteextattr */
1235 { NULL, NULL } 1244 { NULL, NULL }
1236}; 1245};
1237const struct vnodeopv_desc ext2fs_specop_opv_desc = 1246const struct vnodeopv_desc ext2fs_specop_opv_desc =
1238 { &ext2fs_specop_p, ext2fs_specop_entries }; 1247 { &ext2fs_specop_p, ext2fs_specop_entries };
1239 1248
1240int (**ext2fs_fifoop_p)(void *); 1249int (**ext2fs_fifoop_p)(void *);
1241const struct vnodeopv_entry_desc ext2fs_fifoop_entries[] = { 1250const struct vnodeopv_entry_desc ext2fs_fifoop_entries[] = {
1242 { &vop_default_desc, vn_default_error }, 1251 { &vop_default_desc, vn_default_error },
1243 { &vop_lookup_desc, vn_fifo_bypass }, /* lookup */ 1252 { &vop_lookup_desc, vn_fifo_bypass }, /* lookup */
1244 { &vop_create_desc, vn_fifo_bypass }, /* create */ 1253 { &vop_create_desc, vn_fifo_bypass }, /* create */
1245 { &vop_mknod_desc, vn_fifo_bypass }, /* mknod */ 1254 { &vop_mknod_desc, vn_fifo_bypass }, /* mknod */
1246 { &vop_open_desc, vn_fifo_bypass }, /* open */ 1255 { &vop_open_desc, vn_fifo_bypass }, /* open */
1247 { &vop_close_desc, ufsfifo_close }, /* close */ 1256 { &vop_close_desc, ufsfifo_close }, /* close */
@@ -1271,17 +1280,21 @@ const struct vnodeopv_entry_desc ext2fs_ @@ -1271,17 +1280,21 @@ const struct vnodeopv_entry_desc ext2fs_
1271 { &vop_abortop_desc, vn_fifo_bypass }, /* abortop */ 1280 { &vop_abortop_desc, vn_fifo_bypass }, /* abortop */
1272 { &vop_inactive_desc, ext2fs_inactive }, /* inactive */ 1281 { &vop_inactive_desc, ext2fs_inactive }, /* inactive */
1273 { &vop_reclaim_desc, ext2fs_reclaim }, /* reclaim */ 1282 { &vop_reclaim_desc, ext2fs_reclaim }, /* reclaim */
1274 { &vop_lock_desc, ufs_lock }, /* lock */ 1283 { &vop_lock_desc, ufs_lock }, /* lock */
1275 { &vop_unlock_desc, ufs_unlock }, /* unlock */ 1284 { &vop_unlock_desc, ufs_unlock }, /* unlock */
1276 { &vop_bmap_desc, vn_fifo_bypass }, /* bmap */ 1285 { &vop_bmap_desc, vn_fifo_bypass }, /* bmap */
1277 { &vop_strategy_desc, vn_fifo_bypass }, /* strategy */ 1286 { &vop_strategy_desc, vn_fifo_bypass }, /* strategy */
1278 { &vop_print_desc, ufs_print }, /* print */ 1287 { &vop_print_desc, ufs_print }, /* print */
1279 { &vop_islocked_desc, ufs_islocked }, /* islocked */ 1288 { &vop_islocked_desc, ufs_islocked }, /* islocked */
1280 { &vop_pathconf_desc, vn_fifo_bypass }, /* pathconf */ 1289 { &vop_pathconf_desc, vn_fifo_bypass }, /* pathconf */
1281 { &vop_advlock_desc, vn_fifo_bypass }, /* advlock */ 1290 { &vop_advlock_desc, vn_fifo_bypass }, /* advlock */
1282 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 1291 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */
1283 { &vop_putpages_desc, vn_fifo_bypass }, /* putpages */ 1292 { &vop_putpages_desc, vn_fifo_bypass }, /* putpages */
 1293 { &vop_getextattr_desc, ext2fs_getextattr }, /* getextattr */
 1294 { &vop_setextattr_desc, ext2fs_setextattr }, /* setextattr */
 1295 { &vop_listextattr_desc, ext2fs_listextattr }, /* listextattr */
 1296 { &vop_deleteextattr_desc, ext2fs_deleteextattr },/* deleteextattr */
1284 { NULL, NULL } 1297 { NULL, NULL }
1285}; 1298};
1286const struct vnodeopv_desc ext2fs_fifoop_opv_desc = 1299const struct vnodeopv_desc ext2fs_fifoop_opv_desc =
1287 { &ext2fs_fifoop_p, ext2fs_fifoop_entries }; 1300 { &ext2fs_fifoop_p, ext2fs_fifoop_entries };

File Added: src/sys/ufs/ext2fs/ext2fs_xattr.c
/*	$NetBSD: ext2fs_xattr.c,v 1.1 2016/08/12 19:04:03 jdolecek Exp $	*/

/*-
 * Copyright (c) 2016 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Jaromir Dolecek.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ext2fs_xattr.c,v 1.1 2016/08/12 19:04:03 jdolecek Exp $");

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/mount.h>
#include <sys/proc.h>
#include <sys/file.h>
#include <sys/buf.h>
#include <sys/vnode.h>
#include <sys/kernel.h>
#include <sys/kmem.h>
#include <sys/trace.h>
#include <sys/resourcevar.h>
#include <sys/kauth.h>
#include <sys/extattr.h>

#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/ufs/ufs_extern.h>

#include <ufs/ext2fs/ext2fs.h>
#include <ufs/ext2fs/ext2fs_extern.h>
#include <ufs/ext2fs/ext2fs_xattr.h>

static const char * const xattr_prefix_index[] = {
	"",
	"user.",
	"system.posix_acl_access",
	"system.posix_acl_default",
	"trusted.",
	"", 	/* unused */
	"security",
	"system.",
	"system.richacl",
	"c",
};

static int
ext2fs_find_xattr(struct ext2fs_xattr_entry *e, uint8_t *start, uint8_t *end, int attrnamespace, struct uio *uio, size_t *size, uint8_t name_index, const char *name)
{
	uint8_t *value;
	int error;
	size_t value_offs, value_len, len, old_len;

	/*
	 * Individual entries follow the header. Each is aligned on 4-byte
	 * boundary.
	 */
	for(; !EXT2FS_XATTR_IS_LAST_ENTRY(e, end); e = EXT2FS_XATTR_NEXT(e)) {
		/*
		 * Only EXT2FS_XATTR_PREFIX_USER is USER, anything else
		 * is considered SYSTEM.
		 */
		if ((attrnamespace == EXTATTR_NAMESPACE_USER && e->e_name_index != EXT2FS_XATTR_PREFIX_USER) ||
		    (attrnamespace == EXTATTR_NAMESPACE_SYSTEM && e->e_name_index == EXT2FS_XATTR_PREFIX_USER)) {
			continue;
		}

		if (e->e_name_index != name_index ||
		    e->e_name_len != strlen(name) ||
		    strncmp(e->e_name, name, e->e_name_len) != 0)
			continue;

		value_offs = fs2h32(e->e_value_offs);
		value_len  = fs2h32(e->e_value_size);
		value      = &start[value_offs];

		/* make sure the value offset are sane */
		if (&value[value_len] > end)
			return (EINVAL);

		if (uio != NULL) {
			/*
			 * Figure out maximum to transfer -- use buffer size and
			 * local data limit.
			 */
			len = MIN(uio->uio_resid, value_len);
			old_len = uio->uio_resid;
			uio->uio_resid = len;

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

			error = uiomove(value, value_len, uio);
			if (error)
				return error;
		}

		/* full data size */
		*size += value_len;

		goto found;
	}

	/* requested attribute not found */
	return (ENODATA);

    found:
	return (0);
}

static int
ext2fs_get_inode_xattr(struct inode *ip, int attrnamespace, struct uio *uio, size_t *size, uint8_t name_index, const char *name)
{
	struct ext2fs_dinode *di = ip->i_din.e2fs_din;
	struct ext2fs_xattr_ibody_header *h;
	uint8_t *start, *end;

	start = &((uint8_t *)di)[EXT2_REV0_DINODE_SIZE + di->e2di_extra_isize];
	h     = (struct ext2fs_xattr_ibody_header *)start;
	end   = &((uint8_t *)di)[EXT2_DINODE_SIZE(ip->i_e2fs)];

	if (end <= start || fs2h32(h->h_magic) != EXT2FS_XATTR_MAGIC)
		return (ENODATA);

	return ext2fs_find_xattr(EXT2FS_XATTR_IFIRST(h), start, end, attrnamespace, uio, size, name_index, name);
}

static int
ext2fs_get_block_xattr(struct inode *ip, int attrnamespace, struct uio *uio, size_t *size, uint8_t name_index, const char *name)
{
	struct ext2fs_dinode *di = ip->i_din.e2fs_din;
	uint8_t *start, *end;
	struct ext2fs_xattr_header *h;
	int error = 0;
	struct buf *bp = NULL;
	daddr_t xblk;

	xblk = di->e2di_facl;
	if (EXT2F_HAS_INCOMPAT_FEATURE(ip, EXT2F_INCOMPAT_64BIT))
		xblk |= (((daddr_t)di->e2di_facl_high) << 32);

	/* don't do anything if no attr block was allocated */
	if (xblk == 0)
		return (0);

	error = bread(ip->i_devvp, fsbtodb(ip->i_e2fs, xblk), (int)ip->i_e2fs->e2fs_bsize, 0, &bp);
	if (error)
		goto out;

	start = (uint8_t *)bp->b_data;
	h     = (struct ext2fs_xattr_header *)start;
	end   = &((uint8_t *)bp->b_data)[bp->b_bcount];

	if (end <= start || fs2h32(h->h_magic) != EXT2FS_XATTR_MAGIC)
		goto out;

	error = ext2fs_find_xattr(EXT2FS_XATTR_BFIRST(h), start, end, attrnamespace, uio, size, name_index, name);

    out:
	if (bp)
		brelse(bp, 0);
	return (error);
}
int
ext2fs_getextattr(void *v)
{
	struct vop_getextattr_args /* {
	        const struct vnodeop_desc *a_desc;
	        struct vnode *a_vp;
	        int a_attrnamespace;
	        const char *a_name;
	        struct uio *a_uio;
	        size_t *a_size;
	        kauth_cred_t a_cred;
	} */ *ap = v;
	struct inode *ip = VTOI(ap->a_vp);
	char namebuf[EXT2FS_XATTR_NAME_LEN_MAX + 1];
	int error, i;
	const char *prefix, *name;
	uint8_t name_index;
	size_t name_match, valuesize = 0;

	if (ap->a_attrnamespace == EXTATTR_NAMESPACE_USER)
		prefix = xattr_prefix_index[EXT2FS_XATTR_PREFIX_USER];
	else
		prefix = xattr_prefix_index[EXT2FS_XATTR_PREFIX_SYSTEM];
	snprintf(namebuf, sizeof(namebuf), "%s%s", prefix, ap->a_name);

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

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

	/* figure out the name index */
	name = ap->a_name;
	name_index = 0;
	name_match = 0;
	for(i=0; i < sizeof(xattr_prefix_index)/sizeof(void *); i++) {
		prefix = xattr_prefix_index[i];
		if (strlen(prefix) > 0 &&
		    strncmp(ap->a_name, prefix, strlen(prefix)) == 0 &&
		    name_match < strlen(prefix)) {
			name = &ap->a_name[strlen(prefix)];
			name_index = i;
			name_match = strlen(prefix);
			continue;
		}
	}

	/* fetch the xattr */
	error = ext2fs_get_inode_xattr(ip, ap->a_attrnamespace, ap->a_uio, &valuesize, name_index, name);
	if (error == ENODATA) {
		/* not found in inode, try facl */
		error = ext2fs_get_block_xattr(ip, ap->a_attrnamespace, ap->a_uio, &valuesize, name_index, name);
	}

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

	return (error);
}

int
ext2fs_setextattr(void *v)
{
#if 0
	struct vop_setextattr_args /* {
	        const struct vnodeop_desc *a_desc;
	        struct vnode *a_vp;
	        int a_attrnamespace;
	        const char *a_name;
	        struct uio *a_uio;
	        kauth_cred_t a_cred;
	} */ *ap = v;

	/* XXX set EXT2F_COMPAT_EXTATTR in superblock after successful set */
#endif

	/* XXX Not implemented */
	return (EOPNOTSUPP);
}

static int
ext2fs_list_xattr(struct ext2fs_xattr_entry *e, uint8_t *end, int attrnamespace, int flags, struct uio *uio, size_t *size)
{
	char name[EXT2FS_XATTR_NAME_LEN_MAX + 1];
	uint8_t len;
	int error;
	const char *prefix;

	/*
	 * Individual entries follow the header. Each is aligned on 4-byte
	 * boundary.
	 */
	for(; !EXT2FS_XATTR_IS_LAST_ENTRY(e, end); e = EXT2FS_XATTR_NEXT(e)) {
		/*
		 * Only EXT2FS_XATTR_PREFIX_USER is USER, anything else
		 * is considered SYSTEM.
		 */
		if ((attrnamespace == EXTATTR_NAMESPACE_USER && e->e_name_index != EXT2FS_XATTR_PREFIX_USER) ||
		    (attrnamespace == EXTATTR_NAMESPACE_SYSTEM && e->e_name_index == EXT2FS_XATTR_PREFIX_USER)) {
			continue;
		}

		if (e->e_name_index <= sizeof(xattr_prefix_index)/sizeof(void *))
			prefix = xattr_prefix_index[e->e_name_index];
		else
			prefix = "";

		len = snprintf(name, sizeof(name), "%s%.*s",
			prefix,
			e->e_name_len, e->e_name);

		if (uio != NULL) {
			if (flags & EXTATTR_LIST_LENPREFIX) {
				/* write name length */
				uiomove(&len, sizeof(uint8_t), uio);
			} else {
				/* include trailing NUL */
				len++;
			}

			error = uiomove(name, len, uio);
			if (error)
				return error;

			*size += len;
		}
	}

	return (0);
}

static int
ext2fs_list_inode_xattr(struct inode *ip, int attrnamespace, int flags, struct uio *uio, size_t *size)
{
	struct ext2fs_dinode *di = ip->i_din.e2fs_din;
	void *start, *end;
	struct ext2fs_xattr_ibody_header *h;

	start = &((uint8_t *)di)[EXT2_REV0_DINODE_SIZE + di->e2di_extra_isize];
	h     = start;
	end   = &((uint8_t *)di)[EXT2_DINODE_SIZE(ip->i_e2fs)];

	if (end <= start || fs2h32(h->h_magic) != EXT2FS_XATTR_MAGIC)
		return (0);

	return ext2fs_list_xattr(EXT2FS_XATTR_IFIRST(h), end, attrnamespace, flags, uio, size);
}

static int
ext2fs_list_block_xattr(struct inode *ip, int attrnamespace, int flags, struct uio *uio, size_t *size)
{
	struct ext2fs_dinode *di = ip->i_din.e2fs_din;
	void *end;
	struct ext2fs_xattr_header *h;
	int error = 0;
	struct buf *bp = NULL;
	daddr_t xblk;

	xblk = di->e2di_facl;
	if (EXT2F_HAS_INCOMPAT_FEATURE(ip, EXT2F_INCOMPAT_64BIT))
		xblk |= (((daddr_t)di->e2di_facl_high) << 32);

	/* don't do anything if no attr block was allocated */
	if (xblk == 0)
		return (0);

	error = bread(ip->i_devvp, fsbtodb(ip->i_e2fs, xblk), (int)ip->i_e2fs->e2fs_bsize, 0, &bp);
	if (error)
		goto out;

	h     = (struct ext2fs_xattr_header *)bp->b_data;
	end   = &((uint8_t *)bp->b_data)[bp->b_bcount];

	if (end <= (void *)h || fs2h32(h->h_magic) != EXT2FS_XATTR_MAGIC)
		goto out;

	error = ext2fs_list_xattr(EXT2FS_XATTR_BFIRST(h), end, attrnamespace, flags, uio, size);

    out:
	if (bp)
		brelse(bp, 0);
	return (error);
}

int
ext2fs_listextattr(void *v)
{
	struct vop_listextattr_args /* {
	        const struct vnodeop_desc *a_desc;
	        struct vnode *a_vp;
	        int a_attrnamespace;
	        struct uio *a_uio;
	        size_t *a_size;
	        int a_flag;
	        kauth_cred_t a_cred;
	} */ *ap = v;
	struct inode *ip = VTOI(ap->a_vp);
	int error;
	const char *prefix;
	size_t listsize = 0;

	if (!EXT2F_HAS_COMPAT_FEATURE(ip, EXT2F_COMPAT_EXTATTR)) {
		/* no EA on the filesystem */
		goto out;
	}

        /*
         * XXX: We can move this inside the loop and iterate on individual
         *      attributes.
         */
	if (ap->a_attrnamespace == EXTATTR_NAMESPACE_USER)
		prefix = xattr_prefix_index[EXT2FS_XATTR_PREFIX_USER];
	else
		prefix = xattr_prefix_index[EXT2FS_XATTR_PREFIX_SYSTEM];
        error = extattr_check_cred(ap->a_vp, prefix, ap->a_cred, VREAD);
        if (error)
                return (error);

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

	/* fetch inode xattrs */
	error = ext2fs_list_inode_xattr(ip, ap->a_attrnamespace, ap->a_flag, ap->a_uio, &listsize);
	if (error)
		return (error);

	error = ext2fs_list_block_xattr(ip, ap->a_attrnamespace, ap->a_flag, ap->a_uio, &listsize);
	if (error)
		return (error);

    out:
	if (ap->a_size != NULL)
		*ap->a_size = listsize;

	return (0);
}

int
ext2fs_deleteextattr(void *v)
{
#if 0
	struct vop_deleteextattr_args /* {
	        const struct vnodeop_desc *a_desc;
	        struct vnode *a_vp;
	        int a_attrnamespace;
	        const char *a_name;
	        kauth_cred_t a_cred;
	} */ *ap = v;
#endif

	/* XXX Not implemented */
	return (EOPNOTSUPP);
}

File Added: src/sys/ufs/ext2fs/ext2fs_xattr.h
/*	$NetBSD: ext2fs_xattr.h,v 1.1 2016/08/12 19:04:03 jdolecek Exp $	*/

/*-
 * Copyright (c) 2016 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Jaromir Dolecek.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef _UFS_EXT2FS_EXT2FS_XATTR_H_
#define _UFS_EXT2FS_EXT2FS_XATTR_H_

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ext2fs_xattr.h,v 1.1 2016/08/12 19:04:03 jdolecek Exp $");

#ifdef _KERNEL

#define EXT2FS_XATTR_MAGIC 	0xEA020000

#define EXT2FS_XATTR_NAME_LEN_MAX	255
#define EXT2FS_XATTR_REFCOUNT_MAX	1024

/*
 * This is used as header for extended attribute block within inode
 */
struct ext2fs_xattr_ibody_header {
	uint32_t h_magic;	/* Magic number - 0xEA020000 */
};

/*
 * This is used as header for extended attribute on separate disk block
 */
struct ext2fs_xattr_header {
	uint32_t h_magic;	/* Magic number - 0xEA020000 */
	uint32_t h_refcount;	/* Reference count */
	uint32_t h_blocks;	/* Number of blocks - only 1 supported */
	uint32_t h_hash;	/* Hash of all attributes */
 	uint32_t h_checksum;	/* Checksum of the extended attribute block */
	uint32_t h_reserved[3];
};

/*
 * Extended attribute on-disk header structure
 */
struct ext2fs_xattr_entry {
        uint8_t  e_name_len;		/* Name length */
        uint8_t  e_name_index;		/* Name prefix index (see below) */
        uint16_t e_value_offs;		/* Offset of value within block */
        uint32_t e_value_block;		/* Value block - not supported (always zero) */
        uint32_t e_value_size;		/* Length of value */
        uint32_t e_hash;		/* Hash (not supported) */
        char e_name[0];			/* Name string (e_name_len bytes) */
};

/*
 * Linux kernel checks only the 0, we also check that the current entry
 * doesn't overflow past end.
 */
#define EXT2FS_XATTR_IS_LAST_ENTRY(entry, end) \
	*((uint32_t *)(entry)) == 0 || EXT2FS_XATTR_NEXT(entry) > end

/*
 * Each ext2fs_xattr_entry starts on next 4-byte boundary, pad if necessary.
 */
#define EXT2FS_XATTR_PAD	4
#define EXT2FS_XATTR_ROUND	(EXT2FS_XATTR_PAD - 1)
#define EXT2FS_XATTR_LEN(name_len) \
	(((name_len) + EXT2FS_XATTR_ROUND + \
	sizeof(struct ext2fs_xattr_entry)) & ~EXT2FS_XATTR_ROUND)
#define EXT2FS_XATTR_NEXT(entry) \
	(struct ext2fs_xattr_entry *)(((uint8_t *)(entry)) + EXT2FS_XATTR_LEN((entry)->e_name_len))

#define EXT2FS_XATTR_IFIRST(h) (void *)&(h)[1]
#define EXT2FS_XATTR_BFIRST(h) EXT2FS_XATTR_IFIRST(h)

/*
 * Name prefixes
 */
#define EXT2FS_XATTR_PREFIX_NONE		0 /* no prefix */
#define EXT2FS_XATTR_PREFIX_USER		1 /* "user." */
#define EXT2FS_XATTR_PREFIX_POSIX_ACCESS	2 /* "system.posix_acl_access" */
#define EXT2FS_XATTR_PREFIX_POSIX_DEFAULT1	3 /* "system.posix_acl_default" */
#define EXT2FS_XATTR_PREFIX_TRUSTED		4 /* "trusted." */
#define EXT2FS_XATTR_PREFIX_SECURITY		6 /* "security." */
#define EXT2FS_XATTR_PREFIX_SYSTEM		7 /* "system." */
#define EXT2FS_XATTR_PREFIX_SYSTEM_RICHACL	8 /* "system.richacl" */
#define EXT2FS_XATTR_PREFIX_ENCRYPTION		9 /* "c" */

int ext2fs_getextattr(void *);
int ext2fs_setextattr(void *);
int ext2fs_listextattr(void *);
int ext2fs_deleteextattr(void *);
#endif /* _KERNEL */

#endif /* _UFS_EXT2FS_EXT2FS_XATTR_H_ */