From b923040ec593339e1ca0a15048f5b1d2a622c150 Mon Sep 17 00:00:00 2001 From: Andreas Dilger Date: Fri, 13 Apr 2012 02:01:12 -0600 Subject: [PATCH] libext2fs: add a regression test for in-inode xattrs Add tst_read_ea test case to verify libext2fs xattr interfaces work consistently with the kernel xattr handling. The libattr-devel package 2.4.48 still has attr/xattr.h (el7, el8), so keep checking for it. Signed-off-by: Andreas Dilger --- configure | 6 ++ configure.ac | 1 + lib/ext2fs/Makefile.in | 16 +++- lib/ext2fs/tst_read_ea.c | 239 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 260 insertions(+), 2 deletions(-) create mode 100644 lib/ext2fs/tst_read_ea.c diff --git a/configure b/configure index 1f777a4..555837c 100755 --- a/configure +++ b/configure @@ -11845,6 +11845,12 @@ fi done fi +ac_fn_c_check_header_compile "$LINENO" "attr/xattr.h" "ac_cv_header_attr_xattr_h" "$ac_includes_default" +if test "x$ac_cv_header_attr_xattr_h" = xyes +then : + printf "%s\n" "#define HAVE_ATTR_XATTR_H 1" >>confdefs.h + +fi ac_fn_c_check_header_compile "$LINENO" "dirent.h" "ac_cv_header_dirent_h" "$ac_includes_default" if test "x$ac_cv_header_dirent_h" = xyes then : diff --git a/configure.ac b/configure.ac index 0b82986..47d02b2 100644 --- a/configure.ac +++ b/configure.ac @@ -987,6 +987,7 @@ else AC_CHECK_PROGS(BUILD_CC, gcc cc) fi AC_CHECK_HEADERS(m4_flatten([ + attr/xattr.h dirent.h errno.h execinfo.h diff --git a/lib/ext2fs/Makefile.in b/lib/ext2fs/Makefile.in index caa96c1..f2e6c82 100644 --- a/lib/ext2fs/Makefile.in +++ b/lib/ext2fs/Makefile.in @@ -224,6 +224,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)/@OS_IO_FILE@.c \ $(srcdir)/sparse_io.c \ @@ -306,6 +307,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) \ @@ -578,7 +584,7 @@ mkjournal: mkjournal.c $(STATIC_LIBEXT2FS) $(DEPLIBCOM_ERR) $(Q) $(CC) -o mkjournal $(srcdir)/mkjournal.c -DDEBUG \ $(STATIC_LIBEXT2FS) $(LIBCOM_ERR) $(ALL_CFLAGS) $(SYSLIBS) -fullcheck check:: tst_bitops tst_badblocks tst_iscan tst_types tst_icount \ +fullcheck 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_inline_data tst_libext2fs tst_sha256 tst_sha512 \ tst_digest_encode tst_getsize tst_getsectsize @@ -587,6 +593,7 @@ fullcheck 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 @@ -640,7 +647,7 @@ clean:: tst_badblocks tst_iscan ext2_err.et ext2_err.c ext2_err.h \ tst_byteswap tst_ismounted tst_getsize tst_getsectsize \ 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 \ tst_digest_encode tst_sha256 tst_sha512 \ ext2_tdbtool mkjournal debug_cmds.c tst_cmds.c extent_cmds.c \ @@ -1224,6 +1231,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)/hashmap.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)/hashmap.h $(srcdir)/bitops.h undo_io.o: $(srcdir)/undo_io.c $(top_builddir)/lib/config.h \ $(top_builddir)/lib/dirpaths.h $(srcdir)/ext2_fs.h \ $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \ diff --git a/lib/ext2fs/tst_read_ea.c b/lib/ext2fs/tst_read_ea.c new file mode 100644 index 0000000..1722dd0 --- /dev/null +++ b/lib/ext2fs/tst_read_ea.c @@ -0,0 +1,239 @@ +/* + * tst_read_ea.c --- this function tests the in-inode xattrs + * + * %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