From cce1fd09014a4e50d5103bbb75360b522c9f3826 Mon Sep 17 00:00:00 2001 From: kientzle Date: Sun, 30 Jul 2006 06:32:14 +0000 Subject: [PATCH] MFC bsdtar 1.2.53 to FreeBSD 6: * Fixes bin/87911 (internal error attempting -u with empty file) * Fixes bin/84993 (warnings with GCC 4.1) * Fixes bin/95175 (core dump on nonexistent symlink) * Documentation fixes * Corrections to pathname matching * Portability fixes * Initial extended attribute support --- usr.bin/tar/Makefile | 38 +------- usr.bin/tar/Makefile.am | 21 ---- usr.bin/tar/bsdtar.1 | 10 +- usr.bin/tar/bsdtar.c | 10 +- usr.bin/tar/bsdtar.h | 2 +- usr.bin/tar/bsdtar_platform.h | 18 +++- usr.bin/tar/configure.ac.in | 117 ---------------------- usr.bin/tar/getdate.y | 5 +- usr.bin/tar/read.c | 4 +- usr.bin/tar/tree.c | 5 +- usr.bin/tar/util.c | 1 - usr.bin/tar/write.c | 178 ++++++++++++++++++++++++++++------ 12 files changed, 182 insertions(+), 227 deletions(-) delete mode 100644 usr.bin/tar/Makefile.am delete mode 100644 usr.bin/tar/configure.ac.in diff --git a/usr.bin/tar/Makefile b/usr.bin/tar/Makefile index 128f2c2c8a71..77ace02fa4d0 100644 --- a/usr.bin/tar/Makefile +++ b/usr.bin/tar/Makefile @@ -1,14 +1,8 @@ # $FreeBSD$ -# -# Use "make distfile" to build a tar.gz file suitable for distribution, -# including an autoconf/automake-generated build system. -# - PROG= bsdtar -VERSION= 1.02.023 -DIST_SRCS= bsdtar.c getdate.y matching.c read.c tree.c util.c write.c -SRCS= ${DIST_SRCS} +VERSION= 1.2.53 +SRCS= bsdtar.c getdate.y matching.c read.c tree.c util.c write.c WARNS?= 5 DPADD= ${LIBARCHIVE} ${LIBBZ2} ${LIBZ} LDADD= -larchive -lbz2 -lz @@ -17,32 +11,4 @@ CFLAGS+= -I${.CURDIR} SYMLINKS= bsdtar ${BINDIR}/tar MLINKS= bsdtar.1 tar.1 -DIST_BUILD_DIR= ${.OBJDIR}/${PROG}-${VERSION} -CLEANDIRS+= ${DIST_BUILD_DIR} -DISTFILE= ${PROG}-${VERSION}.tar.gz -# Files that just get copied to the distfile build directory -DIST_FILES= ${DIST_SRCS} -DIST_FILES+= ${MAN} -DIST_FILES+= bsdtar.h bsdtar_platform.h -DIST_FILES+= Makefile.am -DIST_FILES+= tree.h - -distfile: - rm -rf ${DIST_BUILD_DIR} - mkdir ${DIST_BUILD_DIR} - for f in ${DIST_FILES}; \ - do \ - cat ${.CURDIR}/$$f >${DIST_BUILD_DIR}/$$f; \ - done - cat ${.CURDIR}/configure.ac.in | \ - sed 's/@VERSION@/${VERSION}/' | \ - cat > ${DIST_BUILD_DIR}/configure.ac - (cd ${DIST_BUILD_DIR} && aclocal && autoheader && autoconf ) - (cd ${DIST_BUILD_DIR} && automake -a --foreign) - (cd ${DIST_BUILD_DIR} && ./configure && make distcheck && make dist) - mv ${DIST_BUILD_DIR}/${DISTFILE} ${.OBJDIR} - @echo ================================================== - @echo Created ${.OBJDIR}/${DISTFILE} - @echo ================================================== - .include diff --git a/usr.bin/tar/Makefile.am b/usr.bin/tar/Makefile.am deleted file mode 100644 index ce565c04bd62..000000000000 --- a/usr.bin/tar/Makefile.am +++ /dev/null @@ -1,21 +0,0 @@ -# $FreeBSD$ - -# Process this file with automake to create Makefile.in - -bin_PROGRAMS= bsdtar -bsdtar_SOURCES= \ - bsdtar.c \ - bsdtar.h \ - bsdtar_platform.h \ - getdate.y \ - matching.c \ - read.c \ - tree.c \ - tree.h \ - util.c \ - write.c -bsdtar_LDADD= -larchive -lbz2 -lz - -dist_man_MANS= bsdtar.1 - -DISTCLEANFILES= getdate.c getdate.h diff --git a/usr.bin/tar/bsdtar.1 b/usr.bin/tar/bsdtar.1 index 9d67a59fe5ee..fb26d0a4e46f 100644 --- a/usr.bin/tar/bsdtar.1 +++ b/usr.bin/tar/bsdtar.1 @@ -445,16 +445,16 @@ option. .Sh EXAMPLES The following creates a new archive called -.Ar file.tar +.Ar file.tar.gz that contains two files .Ar source.c and .Ar source.h : -.Dl Nm Fl czf Pa file.tar Pa source.c Pa source.h +.Dl Nm Fl czf Pa file.tar.gz Pa source.c Pa source.h .Pp To view a detailed table of contents for this archive: -.Dl Nm Fl tvf Pa file.tar +.Dl Nm Fl tvf Pa file.tar.gz .Pp To extract all entries from the archive on the default tape drive: @@ -463,9 +463,9 @@ the default tape drive: To move file hierarchies, invoke .Nm as -.Dl Nm Fl cf Pa - Fl C Pa srcdir\ . | Nm Fl xpBf Pa - Fl C Pa destdir +.Dl Nm Fl cf Pa - Fl C Pa srcdir\ . | Nm Fl xpf Pa - Fl C Pa destdir or more traditionally -.Dl cd srcdir \&; Nm Fl cf Pa -\ . | ( cd destdir \&; Nm Fl xpBf Pa - ) +.Dl cd srcdir \&; Nm Fl cf Pa -\ . | ( cd destdir \&; Nm Fl xpf Pa - ) .Pp In create mode, the list of files and directories to be archived can also include directory change instructions of the form diff --git a/usr.bin/tar/bsdtar.c b/usr.bin/tar/bsdtar.c index 31c6f532d7da..07a923b41fca 100644 --- a/usr.bin/tar/bsdtar.c +++ b/usr.bin/tar/bsdtar.c @@ -29,8 +29,6 @@ __FBSDID("$FreeBSD$"); #include #include -#include -#include #include #include #ifdef HAVE_GETOPT_LONG @@ -410,6 +408,7 @@ main(int argc, char **argv) case 'p': /* GNU tar, star */ bsdtar->extract_flags |= ARCHIVE_EXTRACT_PERM; bsdtar->extract_flags |= ARCHIVE_EXTRACT_ACL; + bsdtar->extract_flags |= ARCHIVE_EXTRACT_XATTR; bsdtar->extract_flags |= ARCHIVE_EXTRACT_FFLAGS; break; case 'r': /* SUSv2 */ @@ -689,9 +688,7 @@ usage(struct bsdtar *bsdtar) static void version(void) { - printf("bsdtar %s, ", PACKAGE_VERSION); - printf("%s\n", archive_version()); - printf("Copyright (C) 2003-2005 Tim Kientzle\n"); + printf("bsdtar %s - %s\n", PACKAGE_VERSION, archive_version()); exit(1); } @@ -757,8 +754,7 @@ long_help(struct bsdtar *bsdtar) } else putchar(*p); } - fprintf(stdout, "\n%s %s\n", PACKAGE_NAME, PACKAGE_VERSION); - fprintf(stdout, "%s\n", archive_version()); + version(); } static int diff --git a/usr.bin/tar/bsdtar.h b/usr.bin/tar/bsdtar.h index 5c37a7150ec3..0da306cd0df1 100644 --- a/usr.bin/tar/bsdtar.h +++ b/usr.bin/tar/bsdtar.h @@ -29,7 +29,7 @@ * $FreeBSD$ */ -#include +#include "bsdtar_platform.h" #include #define DEFAULT_BYTES_PER_BLOCK (20*512) diff --git a/usr.bin/tar/bsdtar_platform.h b/usr.bin/tar/bsdtar_platform.h index b5a083c614f4..f8b3d2cfd140 100644 --- a/usr.bin/tar/bsdtar_platform.h +++ b/usr.bin/tar/bsdtar_platform.h @@ -36,7 +36,7 @@ #define BSDTAR_PLATFORM_H_INCLUDED #if HAVE_CONFIG_H -#include "config.h" +#include "../config.h" #else #ifdef __FreeBSD__ @@ -112,8 +112,14 @@ #define __FBSDID(a) /* null */ #endif -#ifndef HAVE_LIBARCHIVE -#error Configuration error: did not find libarchive. +#ifdef HAVE_LIBARCHIVE +/* If we're using the platform libarchive, include system headers. */ +#include +#include +#else +/* Otherwise, include user headers. */ +#include "archive.h" +#include "archive_entry.h" #endif /* @@ -121,12 +127,16 @@ * including some variant of the acl_get_perm() function (which was * omitted from the POSIX.1e draft)? */ -#if HAVE_SYS_ACL_H && HAVE_ACL_PERMSET_T +#if HAVE_SYS_ACL_H && HAVE_ACL_PERMSET_T && HAVE_ACL_USER #if HAVE_ACL_GET_PERM || HAVE_ACL_GET_PERM_NP #define HAVE_POSIX_ACL 1 #endif #endif +#ifdef HAVE_LIBACL +#include +#endif + #if HAVE_ACL_GET_PERM #define ACL_GET_PERM acl_get_perm #else diff --git a/usr.bin/tar/configure.ac.in b/usr.bin/tar/configure.ac.in deleted file mode 100644 index 249fa7b44079..000000000000 --- a/usr.bin/tar/configure.ac.in +++ /dev/null @@ -1,117 +0,0 @@ -# $FreeBSD$ - -# Process this file with autoconf to produce a configure script. -AC_INIT(bsdtar, @VERSION@, kientzle@freebsd.org) -AM_INIT_AUTOMAKE(bsdtar, @VERSION@) -AC_CONFIG_SRCDIR([bsdtar.c]) -AM_CONFIG_HEADER([config.h]) - -# Checks for programs. -AC_PROG_CC -AC_PROG_YACC - -# Checks for header files. -AC_HEADER_DIRENT -AC_HEADER_STDC -AC_CHECK_HEADERS([bzlib.h fcntl.h inttypes.h langinfo.h limits.h locale.h paths.h stdint.h stdlib.h string.h sys/ioctl.h sys/param.h unistd.h zlib.h]) - -# Checks for libraries. -AC_CHECK_LIB([z], [inflate]) -AC_CHECK_LIB([bz2], [BZ2_bzDecompressInit]) -AC_CHECK_LIB([archive], [archive_version]) - -# Checks for typedefs, structures, and compiler characteristics. -AC_C_CONST -AC_TYPE_UID_T -AC_TYPE_MODE_T -AC_TYPE_OFF_T -AC_TYPE_SIZE_T -AC_CHECK_TYPE(id_t, [unsigned long]) -AC_CHECK_MEMBERS([struct stat.st_rdev, struct stat.st_mtimespec.tv_nsec, struct stat.st_mtim.tv_nsec]) - - -AC_CHECK_DECL([D_MD_ORDER], -[AC_DEFINE(HAVE_D_MD_ORDER, 1, [Define to 1 if nl_langinfo supports D_MD_ORDER])], -[], -[#if HAVE_LANGINFO_H -#include -#endif -]) - -AC_FUNC_FNMATCH -AC_CHECK_DECL([FNM_LEADING_DIR], -[AC_DEFINE(HAVE_FNM_LEADING_DIR, 1, [Define to 1 if fnmatch(3) supports the FNM_LEADING_DIR flag])], -[], -[#if HAVE_FNMATCH -#define _GNU_SOURCE /* Required on Linux to get GNU extensions */ -#include -#endif -]) - -# Check for dirent.d_namlen field explicitly -AC_CHECK_MEMBER(struct dirent.d_namlen,,, -[#if HAVE_DIRENT_H -#include -#endif -]) - -# Check for ACL support -AC_CHECK_HEADERS([sys/acl.h]) -AC_CHECK_LIB([acl],[acl_get_file]) - -AC_CHECK_TYPES(acl_permset_t,,, -[#if HAVE_SYS_TYPES_H -#include -#endif -#if HAVE_SYS_ACL_H -#include -#endif -]) - -# The "acl_get_perm()" function was omitted from the POSIX draft. -# (It's a pretty obvious oversight; otherwise, there's no way to -# test for specific permissions in a permset.) Linux uses the obvious -# name, FreeBSD adds _np to mark it as "non-Posix extension." -# Test for both as a double-check that we really have POSIX-style ACL support. -AC_CHECK_FUNCS(acl_get_perm_np acl_get_perm,,, -[#if HAVE_SYS_TYPES_H -#include -#endif -#if HAVE_SYS_ACL_H -#include -#endif -]) - -# Checks for library functions. -AC_PROG_GCC_TRADITIONAL -AC_FUNC_LSTAT -AC_HEADER_MAJOR -AC_FUNC_MALLOC -AC_FUNC_STAT -AC_FUNC_STRFTIME -AC_FUNC_VPRINTF -AC_CHECK_TYPES([uintmax_t, unsigned long long]) -AC_CHECK_FUNCS([chflags fchdir ftruncate getopt_long memmove memset nl_langinfo reallocf setlocale strchr strdup strerror strrchr]) - -# -# If any of the common 64-bit types is defined, set "int64_t" -# -AC_CHECK_TYPE(__int64_t, [long long]) -AC_CHECK_TYPE(_int64_t, [__int64_t]) -AC_CHECK_TYPE(int64_t, [_int64_t]) - -# -# If any of the common 64-bit unsigned types is defined, set "uint64_t" -# -AC_CHECK_TYPE(__uint64_t, [unsigned long long]) -AC_CHECK_TYPE(_uint64_t, [__uint64_t]) -AC_CHECK_TYPE(u_int64_t, [_uint64_t]) -AC_CHECK_TYPE(uint64_t, [u_int64_t]) - -#define HAVE_CHFLAGS 1 - -# Additional requirements -AC_SYS_LARGEFILE - -AC_CONFIG_FILES([Makefile]) -AC_OUTPUT diff --git a/usr.bin/tar/getdate.y b/usr.bin/tar/getdate.y index cc838c1b4c03..b40058c09b21 100644 --- a/usr.bin/tar/getdate.y +++ b/usr.bin/tar/getdate.y @@ -23,8 +23,10 @@ /* SUPPRESS 287 on yaccpar_sccsid *//* Unused static variable */ /* SUPPRESS 288 on yyerrlab *//* Label unused */ -#include "bsdtar_platform.h" +#ifdef __FreeBSD__ +#include __FBSDID("$FreeBSD$"); +#endif #include #include @@ -717,6 +719,7 @@ get_date(char *p) time_t nowtime; long tzone; + memset(&gmt, 0, sizeof(gmt)); yyInput = p; (void)time (&nowtime); diff --git a/usr.bin/tar/read.c b/usr.bin/tar/read.c index dc9540905497..ea677fe6eedf 100644 --- a/usr.bin/tar/read.c +++ b/usr.bin/tar/read.c @@ -31,8 +31,6 @@ __FBSDID("$FreeBSD$"); #include #include -#include -#include #include #include #include @@ -279,7 +277,7 @@ list_item_verbose(struct bsdtar *bsdtar, FILE *out, struct archive_entry *entry) if (!now) time(&now); bsdtar_strmode(entry, tmp); - fprintf(out, "%s %d ", tmp, st->st_nlink); + fprintf(out, "%s %d ", tmp, (int)(st->st_nlink)); /* Use uname if it's present, else uid. */ p = archive_entry_uname(entry); diff --git a/usr.bin/tar/tree.c b/usr.bin/tar/tree.c index 4528eea3c15b..6ecb5deaede0 100644 --- a/usr.bin/tar/tree.c +++ b/usr.bin/tar/tree.c @@ -130,7 +130,7 @@ tree_dump(struct tree *t, FILE *out) fprintf(out, "\tpwd: "); fflush(stdout); system("pwd"); fprintf(out, "\taccess: %s\n", t->basename); fprintf(out, "\tstack:\n"); - for(te = t->stack; te != NULL; te = te->next) { + for (te = t->stack; te != NULL; te = te->next) { fprintf(out, "\t\tte->name: %s%s%s\n", te->name, te->flags & needsPreVisit ? "" : " *", t->current == te ? " (current)" : ""); @@ -311,13 +311,14 @@ tree_next(struct tree *t) t->tree_errno = errno; return (t->visit_type = TREE_ERROR_DIR); } + t->depth++; t->d = opendir("."); if (t->d == NULL) { + tree_ascend(t); /* Undo "chdir" */ tree_pop(t); t->tree_errno = errno; return (t->visit_type = TREE_ERROR_DIR); } - t->depth++; t->flags &= ~hasLstat; t->flags &= ~hasStat; t->basename = "."; diff --git a/usr.bin/tar/util.c b/usr.bin/tar/util.c index 69cc67117c5b..2b7e9a7ffcfb 100644 --- a/usr.bin/tar/util.c +++ b/usr.bin/tar/util.c @@ -29,7 +29,6 @@ __FBSDID("$FreeBSD$"); #include #include /* Linux doesn't define mode_t, etc. in sys/stat.h. */ -#include #include #include #include diff --git a/usr.bin/tar/write.c b/usr.bin/tar/write.c index 39743276e9c7..19ed1279c27b 100644 --- a/usr.bin/tar/write.c +++ b/usr.bin/tar/write.c @@ -32,8 +32,9 @@ __FBSDID("$FreeBSD$"); #ifdef HAVE_POSIX_ACL #include #endif -#include -#include +#ifdef HAVE_ATTR_XATTR_H +#include +#endif #include #include #include @@ -119,6 +120,8 @@ static int new_enough(struct bsdtar *, const char *path, const struct stat *); static void setup_acls(struct bsdtar *, struct archive_entry *, const char *path); +static void setup_xattrs(struct bsdtar *, struct archive_entry *, + const char *path); static void test_for_append(struct bsdtar *); static void write_archive(struct archive *, struct bsdtar *); static void write_entry(struct bsdtar *, struct archive *, @@ -296,9 +299,13 @@ tar_mode_u(struct bsdtar *bsdtar) archive_read_support_compression_all(a); archive_read_support_format_tar(a); archive_read_support_format_gnutar(a); - archive_read_open_fd(a, bsdtar->fd, + if (archive_read_open_fd(a, bsdtar->fd, bsdtar->bytes_per_block != 0 ? bsdtar->bytes_per_block : - DEFAULT_BYTES_PER_BLOCK); + DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) { + bsdtar_errc(bsdtar, 1, 0, + "Can't open %s: %s", bsdtar->filename, + archive_error_string(a)); + } /* Build a list of all entries and their recorded mod times. */ while (0 == archive_read_next_header(a, &entry)) { @@ -440,10 +447,11 @@ archive_names_from_file_helper(struct bsdtar *bsdtar, const char *line) } /* - * Copy from specified archive to current archive. - * Returns non-zero on fatal error (i.e., output errors). Errors - * reading the input archive set bsdtar->return_value, but this - * function will still return zero. + * Copy from specified archive to current archive. Returns non-zero + * for write errors (which force us to terminate the entire archiving + * operation). If there are errors reading the input archive, we set + * bsdtar->return_value but return zero, so the overall archiving + * operation will complete and return non-zero. */ static int append_archive(struct bsdtar *bsdtar, struct archive *a, const char *filename) @@ -505,7 +513,8 @@ append_archive(struct bsdtar *bsdtar, struct archive *a, const char *filename) bsdtar->return_value = 1; } - return (0); /* TODO: Return non-zero on error */ + /* Note: If we got here, we saw no write errors, so return success. */ + return (0); } /* @@ -620,15 +629,18 @@ write_hierarchy(struct bsdtar *bsdtar, struct archive *a, const char *path) */ switch(symlink_mode) { case 'H': - /* 'H': First item (from command line) like 'L'. */ - lst = tree_current_stat(tree); /* 'H': After the first item, rest like 'P'. */ symlink_mode = 'P'; - break; + /* 'H': First item (from command line) like 'L'. */ + /* FALLTHROUGH */ case 'L': /* 'L': Do descend through a symlink to dir. */ /* 'L': Archive symlink to file as file. */ lst = tree_current_stat(tree); + /* If stat fails, we have a broken symlink; + * in that case, archive the link as such. */ + if (lst == NULL) + lst = tree_current_lstat(tree); break; default: /* 'P': Don't descend through a symlink to dir. */ @@ -643,15 +655,12 @@ write_hierarchy(struct bsdtar *bsdtar, struct archive *a, const char *path) tree_descend(tree); /* - * In -u mode, we need to check whether this - * is newer than what's already in the archive. - * In all modes, we need to obey --newerXXX flags. + * Write the entry. Note that write_entry() handles + * pathname editing and newness testing. */ - if (new_enough(bsdtar, name, lst)) { - write_entry(bsdtar, a, lst, name, - tree_current_pathlen(tree), - tree_current_access_path(tree)); - } + write_entry(bsdtar, a, lst, name, + tree_current_pathlen(tree), + tree_current_access_path(tree)); } tree_close(tree); } @@ -686,6 +695,13 @@ write_entry(struct bsdtar *bsdtar, struct archive *a, const struct stat *st, if (edit_pathname(bsdtar, entry)) goto abort; + /* + * In -u mode, check that the file is newer than what's + * already in the archive; in all modes, obey --newerXXX flags. + */ + if (!new_enough(bsdtar, archive_entry_pathname(entry), st)) + goto abort; + if (!S_ISDIR(st->st_mode) && (st->st_nlink > 1)) lookup_hardlink(bsdtar, entry, st); @@ -733,6 +749,7 @@ write_entry(struct bsdtar *bsdtar, struct archive *a, const struct stat *st, archive_entry_copy_stat(entry, st); setup_acls(bsdtar, entry, accpath); + setup_xattrs(bsdtar, entry, accpath); /* * If it's a regular file (and non-zero in size) make sure we @@ -983,11 +1000,11 @@ lookup_hardlink(struct bsdtar *bsdtar, struct archive_entry *entry, } #ifdef HAVE_POSIX_ACL -void setup_acl(struct bsdtar *bsdtar, +static void setup_acl(struct bsdtar *bsdtar, struct archive_entry *entry, const char *accpath, int acl_type, int archive_entry_acl_type); -void +static void setup_acls(struct bsdtar *bsdtar, struct archive_entry *entry, const char *accpath) { @@ -1001,7 +1018,7 @@ setup_acls(struct bsdtar *bsdtar, struct archive_entry *entry, ACL_TYPE_DEFAULT, ARCHIVE_ENTRY_ACL_TYPE_DEFAULT); } -void +static void setup_acl(struct bsdtar *bsdtar, struct archive_entry *entry, const char *accpath, int acl_type, int archive_entry_acl_type) { @@ -1065,7 +1082,7 @@ setup_acl(struct bsdtar *bsdtar, struct archive_entry *entry, } } #else -void +static void setup_acls(struct bsdtar *bsdtar, struct archive_entry *entry, const char *accpath) { @@ -1075,13 +1092,120 @@ setup_acls(struct bsdtar *bsdtar, struct archive_entry *entry, } #endif +#if HAVE_LISTXATTR && HAVE_LLISTXATTR && HAVE_GETXATTR && HAVE_LGETXATTR + +static void +setup_xattr(struct bsdtar *bsdtar, struct archive_entry *entry, + const char *accpath, const char *name) +{ + size_t size; + void *value = NULL; + char symlink_mode = bsdtar->symlink_mode; + + if (symlink_mode == 'H') + size = getxattr(accpath, name, NULL, 0); + else + size = lgetxattr(accpath, name, NULL, 0); + + if (size == -1) { + bsdtar_warnc(bsdtar, errno, "Couldn't get extended attribute"); + return; + } + + if (size > 0 && (value = malloc(size)) == NULL) { + bsdtar_errc(bsdtar, 1, errno, "Out of memory"); + return; + } + + if (symlink_mode == 'H') + size = getxattr(accpath, name, value, size); + else + size = lgetxattr(accpath, name, value, size); + + if (size == -1) { + bsdtar_warnc(bsdtar, errno, "Couldn't get extended attribute"); + return; + } + + archive_entry_xattr_add_entry(entry, name, value, size); + + free(value); +} + +/* + * Linux extended attribute support + */ +static void +setup_xattrs(struct bsdtar *bsdtar, struct archive_entry *entry, + const char *accpath) +{ + char *list, *p; + size_t list_size; + char symlink_mode = bsdtar->symlink_mode; + + if (symlink_mode == 'H') + list_size = listxattr(accpath, NULL, 0); + else + list_size = llistxattr(accpath, NULL, 0); + + if (list_size == -1) { + bsdtar_warnc(bsdtar, errno, + "Couldn't list extended attributes"); + return; + } else if (list_size == 0) + return; + + if ((list = malloc(list_size)) == NULL) { + bsdtar_errc(bsdtar, 1, errno, "Out of memory"); + return; + } + + if (symlink_mode == 'H') + list_size = listxattr(accpath, list, list_size); + else + list_size = llistxattr(accpath, list, list_size); + + if (list_size == -1) { + bsdtar_warnc(bsdtar, errno, + "Couldn't list extended attributes"); + free(list); + return; + } + + for (p = list; (p - list) < list_size; p += strlen(p) + 1) { + if (strncmp(p, "system.", 7) == 0 || + strncmp(p, "xfsroot.", 8) == 0) + continue; + + setup_xattr(bsdtar, entry, accpath, p); + } + + free(list); +} + +#else + +/* + * Generic (stub) extended attribute support. + */ +static void +setup_xattrs(struct bsdtar *bsdtar, struct archive_entry *entry, + const char *accpath) +{ + (void)bsdtar; /* UNUSED */ + (void)entry; /* UNUSED */ + (void)accpath; /* UNUSED */ +} + +#endif + static void free_cache(struct name_cache *cache) { size_t i; if (cache != NULL) { - for(i = 0; i < cache->size; i++) { + for (i = 0; i < cache->size; i++) { if (cache->cache[i].name != NULL && cache->cache[i].name != NO_NAME) free((void *)(uintptr_t)cache->cache[i].name); @@ -1235,10 +1359,6 @@ new_enough(struct bsdtar *bsdtar, const char *path, const struct stat *st) */ if (bsdtar->archive_dir != NULL && bsdtar->archive_dir->head != NULL) { - /* Ignore leading './' when comparing names. */ - if (path[0] == '.' && path[1] == '/' && path[2] != '\0') - path += 2; - for (p = bsdtar->archive_dir->head; p != NULL; p = p->next) { if (strcmp(path, p->name)==0) return (p->mtime_sec < st->st_mtime ||