From 1f981816ac8d855cc2af6150711f3417e02e12bf Mon Sep 17 00:00:00 2001 From: Andreas Dilger Date: Fri, 13 Apr 2012 02:01:12 -0600 Subject: [PATCH] e2fsck: clean up xattr checking code, add test Clean up xattr header/list processing for in-inode xattrs instead of doing lots of explicit pointer math. Add a regression test for in-inode xattrs. Signed-off-by: Andreas Dilger --- configure | 2 +- configure.in | 2 + e2fsck/pass1.c | 16 ++- lib/config.h.in | 6 ++ lib/ext2fs/Makefile.in | 16 ++- lib/ext2fs/ext2_ext_attr.h | 9 +- lib/ext2fs/ext2fs.h | 4 + lib/ext2fs/ext_attr.c | 71 +++++++------- lib/ext2fs/tst_read_ea.c | 239 +++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 316 insertions(+), 49 deletions(-) create mode 100644 lib/ext2fs/tst_read_ea.c diff --git a/configure b/configure index 0c59235..c73a1bf 100755 --- a/configure +++ b/configure @@ -10342,7 +10342,7 @@ fi done fi -for ac_header in dirent.h errno.h execinfo.h getopt.h malloc.h mntent.h paths.h semaphore.h setjmp.h signal.h stdarg.h stdint.h stdlib.h termios.h termio.h unistd.h utime.h linux/falloc.h linux/fd.h linux/major.h linux/loop.h net/if_dl.h netinet/in.h sys/disklabel.h sys/disk.h sys/file.h sys/ioctl.h sys/mkdev.h sys/mman.h sys/mount.h sys/prctl.h sys/resource.h sys/select.h sys/socket.h sys/sockio.h sys/stat.h sys/syscall.h sys/sysmacros.h sys/time.h sys/types.h sys/un.h sys/wait.h +for ac_header in attr/xattr.h dirent.h errno.h execinfo.h getopt.h malloc.h mntent.h paths.h semaphore.h setjmp.h signal.h stdarg.h stdint.h stdlib.h termios.h termio.h unistd.h utime.h linux/falloc.h linux/fd.h linux/major.h linux/loop.h net/if_dl.h netinet/in.h sys/disklabel.h sys/disk.h sys/file.h sys/ioctl.h sys/mkdev.h sys/mman.h sys/mount.h sys/prctl.h sys/resource.h sys/select.h sys/socket.h sys/sockio.h sys/stat.h sys/syscall.h sys/sysmacros.h sys/time.h sys/types.h sys/un.h sys/wait.h sys/xattr.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" diff --git a/configure.in b/configure.in index 6ed9a5b..1726bee 100644 --- a/configure.in +++ b/configure.in @@ -856,6 +856,7 @@ else AC_CHECK_PROGS(BUILD_CC, gcc cc) fi AC_CHECK_HEADERS(m4_flatten([ + attr/xattr.h dirent.h errno.h execinfo.h @@ -898,6 +899,7 @@ AC_CHECK_HEADERS(m4_flatten([ sys/types.h sys/un.h sys/wait.h + sys/xattr.h ])) AC_CHECK_HEADERS(net/if.h,,, [[ diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c index 150dd9f..e171df4 100644 --- a/e2fsck/pass1.c +++ b/e2fsck/pass1.c @@ -282,11 +282,10 @@ static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx) problem_t problem = 0; inode = (struct ext2_inode_large *) pctx->inode; - storage_size = EXT2_INODE_SIZE(ctx->fs->super) - EXT2_GOOD_OLD_INODE_SIZE - - inode->i_extra_isize; - start = ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE + - inode->i_extra_isize + sizeof(__u32); - entry = (struct ext2_ext_attr_entry *) start; + storage_size = EXT2_INODE_SIZE(ctx->fs->super) - + EXT2_GOOD_OLD_INODE_SIZE - inode->i_extra_isize; + entry = &IHDR(inode)->h_first_entry[0]; + start = (char *)entry; /* scan all entry's headers first */ @@ -405,7 +404,7 @@ static void check_inode_extra_space(e2fsck_t ctx, struct problem_context *pctx) e2fsck_mark_inode_bad(ctx, pctx->ino, BADNESS_HIGH); } - eamagic = IHDR(inode); + eamagic = &IHDR(inode)->h_magic; if (*eamagic != EXT2_EXT_ATTR_MAGIC && (ctx->flags & E2F_FLAG_EXPAND_EISIZE) && (inode->i_extra_isize < ctx->want_extra_isize)) { @@ -587,9 +586,8 @@ int e2fsck_pass1_delete_attr(e2fsck_t ctx, struct ext2_inode_large *inode, int in_inode = 1, error; unsigned int freed_bytes = inode->i_extra_isize; - start = (char *)inode + EXT2_GOOD_OLD_INODE_SIZE + - inode->i_extra_isize + sizeof(__u32); - entry_ino = (struct ext2_ext_attr_entry *)start; + entry_ino = &IHDR(inode)->h_first_entry[0]; + start = (char *)entry_ino; if (inode->i_file_acl) { error = ext2fs_read_ext_attr(ctx->fs, inode->i_file_acl, diff --git a/lib/config.h.in b/lib/config.h.in index 49b7d08..75aae51 100644 --- a/lib/config.h.in +++ b/lib/config.h.in @@ -52,6 +52,9 @@ /* Define to 1 if you have the `asprintf' function. */ #undef HAVE_ASPRINTF +/* Define to 1 if you have the header file. */ +#undef HAVE_ATTR_XATTR_H + /* Define to 1 if you have the `backtrace' function. */ #undef HAVE_BACKTRACE @@ -477,6 +480,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_WAIT_H +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_XATTR_H + /* Define to 1 if you have the header file. */ #undef HAVE_TERMIOS_H diff --git a/lib/ext2fs/Makefile.in b/lib/ext2fs/Makefile.in index 09bf9aa..f6f7ac6 100644 --- a/lib/ext2fs/Makefile.in +++ b/lib/ext2fs/Makefile.in @@ -186,6 +186,7 @@ SRCS= ext2_err.c \ $(srcdir)/tst_byteswap.c \ $(srcdir)/tst_getsize.c \ $(srcdir)/tst_iscan.c \ + $(srcdir)/tst_read_ea.c \ $(srcdir)/undo_io.c \ $(srcdir)/unix_io.c \ $(srcdir)/unlink.c \ @@ -262,6 +263,11 @@ tst_iscan: tst_iscan.o $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBCOM_ERR) $(Q) $(CC) -o tst_iscan tst_iscan.o $(ALL_LDFLAGS) \ $(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR) $(SYSLIBS) +tst_read_ea: tst_read_ea.o $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBCOM_ERR) + $(E) " LD $@" + $(Q) $(CC) -o tst_read_ea tst_read_ea.o $(STATIC_LIBEXT2FS) \ + $(STATIC_LIBCOM_ERR) + tst_getsize: tst_getsize.o $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBCOM_ERR) $(E) " LD $@" $(Q) $(CC) -o tst_getsize tst_getsize.o $(ALL_LDFLAGS) \ @@ -451,7 +457,7 @@ mkjournal: mkjournal.c $(STATIC_LIBEXT2FS) $(DEPLIBCOM_ERR) $(Q) $(CC) -o mkjournal $(srcdir)/mkjournal.c -DDEBUG \ $(STATIC_LIBEXT2FS) $(LIBCOM_ERR) $(ALL_CFLAGS) $(SYSLIBS) -check:: tst_bitops tst_badblocks tst_iscan tst_types tst_icount \ +check:: tst_bitops tst_badblocks tst_iscan tst_types tst_icount tst_read_ea \ tst_super_size tst_types tst_inode_size tst_csum tst_crc32c tst_bitmaps \ tst_inline tst_libext2fs $(TESTENV) ./tst_bitops @@ -459,6 +465,7 @@ check:: tst_bitops tst_badblocks tst_iscan tst_types tst_icount \ $(TESTENV) ./tst_iscan $(TESTENV) ./tst_types $(TESTENV) ./tst_icount + $(TESTENV) ./tst_read_ea $(TESTENV) ./tst_super_size $(TESTENV) ./tst_inode_size $(TESTENV) ./tst_csum @@ -504,7 +511,7 @@ clean:: tst_badblocks tst_iscan ext2_err.et ext2_err.c ext2_err.h \ tst_byteswap tst_ismounted tst_getsize tst_sectgetsize \ tst_bitops tst_types tst_icount tst_super_size tst_csum \ - tst_bitmaps tst_bitmaps_out tst_extents tst_inline \ + tst_read_ea tst_bitmaps tst_bitmaps_out tst_extents tst_inline \ tst_inline_data tst_inode_size tst_bitmaps_cmd.c \ ext2_tdbtool mkjournal debug_cmds.c tst_cmds.c extent_cmds.c \ ../libext2fs.a ../libext2fs_p.a ../libext2fs_chk.a \ @@ -982,6 +989,11 @@ tst_iscan.o: $(srcdir)/tst_iscan.c $(top_builddir)/lib/config.h \ $(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h +tst_read_ea.o: $(srcdir)/tst_read_ea.c $(srcdir)/ext2_fs.h \ + $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \ + $(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \ + $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \ + $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h undo_io.o: $(srcdir)/undo_io.c $(top_builddir)/lib/config.h \ $(top_builddir)/lib/dirpaths.h $(srcdir)/tdb.h $(srcdir)/ext2_fs.h \ $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \ diff --git a/lib/ext2fs/ext2_ext_attr.h b/lib/ext2fs/ext2_ext_attr.h index 923fe47..755024e 100644 --- a/lib/ext2fs/ext2_ext_attr.h +++ b/lib/ext2fs/ext2_ext_attr.h @@ -38,9 +38,14 @@ struct ext2_ext_attr_entry { #endif }; +struct ext2_xattr_ibody_header { + __u32 h_magic; /* EXT2_EXT_ATTR_MAGIC */ + struct ext2_ext_attr_entry h_first_entry[0]; +}; + #define BHDR(block) ((struct ext2_ext_attr_header *)block) -#define IHDR(inode) ((__u32 *)((char *)inode + EXT2_GOOD_OLD_INODE_SIZE + \ - (inode)->i_extra_isize)) +#define IHDR(inode) ((struct ext2_xattr_ibody_header *)((char *)inode + \ + EXT2_GOOD_OLD_INODE_SIZE + (inode)->i_extra_isize)) #define ENTRY(ptr) ((struct ext2_ext_attr_entry *)(ptr)) /* Name indexes */ diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h index 6d412ef..15b4ee5 100644 --- a/lib/ext2fs/ext2fs.h +++ b/lib/ext2fs/ext2fs.h @@ -1073,6 +1073,10 @@ extern errcode_t ext2fs_dup_handle(ext2_filsys src, ext2_filsys *dest); extern errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir); /* ext_attr.c */ +extern errcode_t ext2fs_attr_get(ext2_filsys fs, struct ext2_inode *inode, + int name_index, const char *name, char *buffer, + size_t buffer_size, int *easize); + extern __u32 ext2fs_ext_attr_hash_entry(struct ext2_ext_attr_entry *entry, void *data); int ext2fs_attr_get_next_attr(struct ext2_ext_attr_entry *entry, int name_index, diff --git a/lib/ext2fs/ext_attr.c b/lib/ext2fs/ext_attr.c index 91a7f16..e69c087 100644 --- a/lib/ext2fs/ext_attr.c +++ b/lib/ext2fs/ext_attr.c @@ -264,9 +264,12 @@ static errcode_t ext2fs_attr_check_names(struct ext2_ext_attr_entry *entry, return 0; } +/* The unused parameter used to be the blocksize, but with in-inode xattrs + * the xattr storage area size depends on where the xattrs are kept. Keep + * this parameter for API/ABI compatibility, but it is not needed. */ static errcode_t ext2fs_attr_find_entry(struct ext2_ext_attr_entry **pentry, int name_index, const char *name, - int size, int sorted) + int unused, int sorted) { struct ext2_ext_attr_entry *entry; int name_len; @@ -338,8 +341,6 @@ static errcode_t ext2fs_attr_ibody_find(ext2_filsys fs, struct ext2_attr_info *i, struct ext2_attr_ibody_find *is) { - __u32 *eamagic; - char *start; errcode_t error; if (EXT2_INODE_SIZE(fs->super) == EXT2_GOOD_OLD_INODE_SIZE) @@ -347,17 +348,13 @@ static errcode_t ext2fs_attr_ibody_find(ext2_filsys fs, if (inode->i_extra_isize == 0) return 0; - eamagic = IHDR(inode); - start = (char *)inode + EXT2_GOOD_OLD_INODE_SIZE + - inode->i_extra_isize + sizeof(__u32); - is->s.first = (struct ext2_ext_attr_entry *)start; - is->s.base = start; + is->s.first = &IHDR(inode)->h_first_entry[0]; + is->s.base = (char *)is->s.first; is->s.here = is->s.first; is->s.end = (char *)inode + EXT2_INODE_SIZE(fs->super); - if (*eamagic == EXT2_EXT_ATTR_MAGIC) { - error = ext2fs_attr_check_names((struct ext2_ext_attr_entry *) - start, is->s.end); + if (IHDR(inode)->h_magic == EXT2_EXT_ATTR_MAGIC) { + error = ext2fs_attr_check_names(is->s.first, is->s.end); if (error) return error; /* Find the named attribute. */ @@ -575,7 +572,6 @@ static errcode_t ext2fs_attr_ibody_set(ext2_filsys fs, struct ext2_attr_info *i, struct ext2_attr_ibody_find *is) { - __u32 *eamagic; struct ext2_attr_search *s = &is->s; errcode_t error; @@ -586,11 +582,10 @@ static errcode_t ext2fs_attr_ibody_set(ext2_filsys fs, if (error) return error; - eamagic = IHDR(inode); if (!EXT2_EXT_IS_LAST_ENTRY(s->first)) - *eamagic = EXT2_EXT_ATTR_MAGIC; + IHDR(inode)->h_magic = EXT2_EXT_ATTR_MAGIC; else - *eamagic = 0; + IHDR(inode)->h_magic = 0; return ext2fs_write_inode_full(fs, is->ino, (struct ext2_inode *)inode, EXT2_INODE_SIZE(fs->super)); @@ -755,6 +750,7 @@ static errcode_t ext2fs_attr_block_get(ext2_filsys fs, struct ext2_inode *inode, } memcpy(buffer, block_buf + entry->e_value_offs, entry->e_value_size); + error = 0; } cleanup: @@ -763,6 +759,22 @@ cleanup: return error; } +static errcode_t ext2fs_attr_check_ibody(ext2_filsys fs, + struct ext2_inode_large *inode) +{ + const int inode_size = EXT2_INODE_SIZE(fs->super); + + if (inode_size == EXT2_GOOD_OLD_INODE_SIZE) + return EXT2_ET_EA_NAME_NOT_FOUND; + + if (IHDR(inode)->h_magic != EXT2_EXT_ATTR_MAGIC) + return EXT2_ET_EA_BAD_MAGIC; + + return ext2fs_attr_check_names(&IHDR(inode)->h_first_entry[0], + (char *)inode + inode_size); +} + + static errcode_t ext2fs_attr_ibody_get(ext2_filsys fs, struct ext2_inode_large *inode, int name_index, const char *name, @@ -771,26 +783,16 @@ static errcode_t ext2fs_attr_ibody_get(ext2_filsys fs, { struct ext2_ext_attr_entry *entry; int error; - char *end, *start; - __u32 *eamagic; - - if (EXT2_INODE_SIZE(fs->super) == EXT2_GOOD_OLD_INODE_SIZE) - return EXT2_ET_EA_NAME_NOT_FOUND; - eamagic = IHDR(inode); - error = ext2fs_attr_check_block(fs, buffer); + error = ext2fs_attr_check_ibody(fs, inode); if (error) return error; - start = (char *)inode + EXT2_GOOD_OLD_INODE_SIZE + - inode->i_extra_isize + sizeof(__u32); - entry = (struct ext2_ext_attr_entry *)start; - end = (char *)inode + EXT2_INODE_SIZE(fs->super); - error = ext2fs_attr_check_names(entry, end); - if (error) - goto cleanup; + entry = &IHDR(inode)->h_first_entry[0]; + error = ext2fs_attr_find_entry(&entry, name_index, name, - end - (char *)entry, 0); + (char *)inode + EXT2_INODE_SIZE(fs->super) - + (char *)entry, 0); if (error) goto cleanup; if (easize) @@ -800,7 +802,8 @@ static errcode_t ext2fs_attr_ibody_get(ext2_filsys fs, error = EXT2_ET_EA_TOO_BIG; goto cleanup; } - memcpy(buffer, start + entry->e_value_offs,entry->e_value_size); + memcpy(buffer, (char *)&IHDR(inode)->h_first_entry[0] + + entry->e_value_offs, entry->e_value_size); } cleanup: @@ -817,7 +820,7 @@ errcode_t ext2fs_attr_get(ext2_filsys fs, struct ext2_inode *inode, error = ext2fs_attr_ibody_get(fs, (struct ext2_inode_large *)inode, name_index, name, buffer, buffer_size, easize); - if (error == EXT2_ET_EA_NAME_NOT_FOUND) + if (error == EXT2_ET_EA_NAME_NOT_FOUND || error == EXT2_ET_EA_BAD_MAGIC) error = ext2fs_attr_block_get(fs, inode, name_index, name, buffer, buffer_size, easize); @@ -860,7 +863,6 @@ errcode_t ext2fs_expand_extra_isize(ext2_filsys fs, ext2_ino_t ino, int *needed_size) { struct ext2_inode *inode_buf = NULL; - __u32 *eamagic = NULL; struct ext2_ext_attr_header *header = NULL; struct ext2_ext_attr_entry *entry = NULL, *last = NULL; struct ext2_attr_ibody_find is = { @@ -898,10 +900,9 @@ retry: if (inode->i_extra_isize >= new_extra_isize) goto cleanup; - eamagic = IHDR(inode); start = (char *)inode + EXT2_GOOD_OLD_INODE_SIZE + inode->i_extra_isize; /* No extended attributes present */ - if (*eamagic != EXT2_EXT_ATTR_MAGIC) { + if (IHDR(inode)->h_magic != EXT2_EXT_ATTR_MAGIC) { memset(start, 0, EXT2_INODE_SIZE(fs->super) - EXT2_GOOD_OLD_INODE_SIZE - inode->i_extra_isize); diff --git a/lib/ext2fs/tst_read_ea.c b/lib/ext2fs/tst_read_ea.c new file mode 100644 index 0000000..21fdf9b --- /dev/null +++ b/lib/ext2fs/tst_read_ea.c @@ -0,0 +1,239 @@ +/* + * tst_getsize.c --- this function tests the getsize function + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE /* for asprintf */ +#endif +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#include +#include +#ifdef HAVE_ATTR_XATTR_H +#include +#elif HAVE_SYS_XATTR_H +#include +#else +/* This is just a test program, let's try to work around the lack of header */ +extern ssize_t fgetxattr (int __filedes, const char *__name, + void *__value, size_t __size); +extern int fsetxattr (int __filedes, const char *__name, + const void *__value, size_t __size, int __flags); +#endif +#if HAVE_MNTENT_H +#include +#include +#if HAVE_ERRNO_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" + +#define NR_XATTRS 256 +char tmpvalue[NR_XATTRS + 1]; + +struct ea { + char *name; + char *value; +}; + +struct ea *ea_table; + +static void init_ea_table(void) +{ + int i; + + ea_table = malloc(sizeof(struct ea) * NR_XATTRS); + if (ea_table == NULL) { + perror("maloc failed"); + exit(1); + } + for (i = 0; i < NR_XATTRS; i ++) { + ea_table[i].name = malloc(i + 2 + strlen("user.")); + if (ea_table[i].name == NULL) { + perror("malloc failed"); + exit(1); + } + strcpy(ea_table[i].name, "user."); + memset(ea_table[i].name + strlen("user."), 'X', i + 1); + ea_table[i].name[i + 1 + strlen("user.")] = 0; + + ea_table[i].value = malloc(NR_XATTRS - i + 1); + if (ea_table[i].value == NULL) { + perror("malloc failed"); + exit(1); + } + memset(ea_table[i].value, 'Y', NR_XATTRS - i); + ea_table[i].value[NR_XATTRS - i] = 0; + } +} + +static int set_xattrs(int fd) +{ + int i; + + for (i = 0; i < NR_XATTRS; i ++) { + if (fsetxattr(fd, ea_table[i].name, ea_table[i].value, + NR_XATTRS - i + 1, XATTR_CREATE) == -1) { + if (errno != ENOSPC) { + perror("fsetxattr failed"); + exit(1); + } + break; + } + } + printf("\t%d xattrs are set\n", i); + return i; +} + +void get_xattrs1(int fd, int nr) +{ + int i; + ssize_t size; + + printf("\ttesting fgetxattr .. "); fflush(stdout); + + for (i = 0; i < nr; i ++) { + size = fgetxattr(fd, ea_table[i].name, tmpvalue, + NR_XATTRS - i + 1); + if (size == -1) { + perror("fgetxattr failed"); + exit(1); + } + if (memcmp(ea_table[i].value, tmpvalue, nr - i + 1)) { + fprintf(stderr, "value mismatch"); + exit(1); + } + } + + printf("%d xattrs are checked, ok\n", i); +} + +void get_xattrs2(const char *device, ext2_ino_t ino, int nr) +{ + ext2_filsys fs; + int i; + struct ext2_inode *inode; + errcode_t err; + int size; + + printf("\ttesting ext2fs_attr_get .. "); fflush(stdout); + + err = ext2fs_open(device, 0, 0, 0, unix_io_manager, &fs); + assert(err == 0); + + err = ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode); + if (err) { + com_err("get_xattrs2", err, "allocating memory"); + exit(1); + } + + err = ext2fs_read_inode_full(fs, ino, inode, + EXT2_INODE_SIZE(fs->super)); + if (err) { + com_err("get_xattrs2", err, "reading inode"); + exit(1); + } + for (i = 0; i < nr; i ++) { + err = ext2fs_attr_get(fs, inode, EXT2_ATTR_INDEX_USER, + ea_table[i].name + strlen("user."), + tmpvalue, sizeof(tmpvalue), &size); + if (err) { + com_err("get_xattrs2", err, "getting xattr"); + exit(1); + } + assert(size == (NR_XATTRS - i + 1)); + + if (memcmp(ea_table[i].value, tmpvalue, size)) { + fprintf(stderr, "value mismatch"); + exit(1); + } + } + ext2fs_close(fs); + + printf("%d xattrs are checked, ok\n", i); +} +#endif /* HAVE_MNTENT_H */ + +int main(int argc, const char *argv[]) +{ +#if HAVE_MNTENT_H + ext2_filsys fs; + FILE *f; + struct mntent *mnt; + char *name; + int fd; + errcode_t err; + struct stat st; + int nr; + int tested = 0; + + initialize_ext2_error_table(); + + init_ea_table(); + + f = setmntent(MOUNTED, "r"); + if (!f) { + fprintf(stderr, "failed to setmntent\n"); + return 1; + } + + while ((mnt = getmntent(f)) != NULL) { + if (hasmntopt(mnt, "user_xattr") == NULL) + continue; + err = ext2fs_open(mnt->mnt_fsname, 0, 0, 0, + unix_io_manager, &fs); + if (err) { + com_err("tst_read_ea", err, "opening fs %s:%s", + mnt->mnt_fsname, mnt->mnt_type); + continue; + } + ext2fs_close(fs); + + printf("type=%s, fsname=%s, mtpt=%s\n", mnt->mnt_type, + mnt->mnt_fsname, mnt->mnt_dir); + + asprintf(&name, "%s/readeaXXXXXX", mnt->mnt_dir); + fd = mkstemp(name); + if (fd == -1) { + fprintf(stderr, "tst_read_ea: mkstemp failed on %s: %s", + name, strerror(errno)); + continue; + } + if (fstat(fd, &st)) { + fprintf(stderr, "tst_read_ea: fstat failed on %s: %s\n", + name, strerror(errno)); + exit(1); + } + nr = set_xattrs(fd); + + sync(); + get_xattrs1(fd, nr); + close(fd); + + get_xattrs2(mnt->mnt_fsname, st.st_ino, nr); + + unlink(name); + free(name); + tested = 1; + } + endmntent(f); + + if (!tested) + fprintf(stderr, + "\tno ext2 based filesystems mounted with user_xattr\n" + "\thope it is ok\n"); +#endif /* HAVE_MNTENT_H */ + return 0; +} -- 1.8.3.1