[Midnightbsd-cvs] src: usr.bin/tar: Upgrade to bsdtar 2.2.5

ctriv at midnightbsd.org ctriv at midnightbsd.org
Sat Sep 29 18:15:57 EDT 2007


Log Message:
-----------
Upgrade to bsdtar 2.2.5

Modified Files:
--------------
    src/usr.bin/tar:
        COPYING (r1.2 -> r1.3)
        Makefile (r1.2 -> r1.3)
        bsdtar.1 (r1.2 -> r1.3)
        bsdtar.c (r1.2 -> r1.3)
        bsdtar.h (r1.2 -> r1.3)
        bsdtar_platform.h (r1.2 -> r1.3)
        getdate.y (r1.2 -> r1.3)
        matching.c (r1.2 -> r1.3)
        read.c (r1.2 -> r1.3)
        tree.c (r1.2 -> r1.3)
        tree.h (r1.2 -> r1.3)
        util.c (r1.2 -> r1.3)
        write.c (r1.2 -> r1.3)

Added Files:
-----------
    src/usr.bin/tar:
        config_midnightbsd.h (r1.1)

-------------- next part --------------
Index: util.c
===================================================================
RCS file: /home/cvs/src/usr.bin/tar/util.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -Lusr.bin/tar/util.c -Lusr.bin/tar/util.c -u -r1.2 -r1.3
--- usr.bin/tar/util.c
+++ usr.bin/tar/util.c
@@ -24,17 +24,29 @@
  */
 
 #include "bsdtar_platform.h"
+__FBSDID("$FreeBSD: src/usr.bin/tar/util.c,v 1.17 2007/04/18 04:36:11 kientzle Exp $");
 __MBSDID("$MidnightBSD$");
-__FBSDID("$FreeBSD: src/usr.bin/tar/util.c,v 1.13.2.2 2007/01/27 06:48:39 kientzle Exp $");
 
+#ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>  /* Linux doesn't define mode_t, etc. in sys/stat.h. */
+#endif
 #include <ctype.h>
+#ifdef HAVE_ERRNO_H
 #include <errno.h>
+#endif
+#ifdef HAVE_STDARG_H
 #include <stdarg.h>
+#endif
 #include <stdio.h>
+#ifdef HAVE_STDLIB_H
 #include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
 #include <string.h>
+#endif
 
 #include "bsdtar.h"
 
@@ -383,6 +395,8 @@
 /*
  * Handle --strip-components and any future path-rewriting options.
  * Returns non-zero if the pathname should not be extracted.
+ *
+ * TODO: Support pax-style regex path rewrites.
  */
 int
 edit_pathname(struct bsdtar *bsdtar, struct archive_entry *entry)
@@ -407,10 +421,6 @@
 		}
 	}
 
-	/* Strip redundant "./" from start of filename. */
-	if (name[0] == '.' && name[1] == '/' && name[2] != '\0')
-		name += 2;
-
 	/* Strip redundant leading '/' characters. */
 	while (name[0] == '/' && name[1] == '/')
 		name++;
@@ -437,3 +447,42 @@
 	}
 	return (0);
 }
+
+/*
+ * Like strcmp(), but try to be a little more aware of the fact that
+ * we're comparing two paths.  Right now, it just handles leading
+ * "./" and trailing '/' specially, so that "a/b/" == "./a/b"
+ *
+ * TODO: Make this better, so that "./a//b/./c/" == "a/b/c"
+ * TODO: After this works, push it down into libarchive.
+ * TODO: Publish the path normalization routines in libarchive so
+ * that bsdtar can normalize paths and use fast strcmp() instead
+ * of this.
+ */
+
+int
+pathcmp(const char *a, const char *b)
+{
+	/* Skip leading './' */
+	if (a[0] == '.' && a[1] == '/' && a[2] != '\0')
+		a += 2;
+	if (b[0] == '.' && b[1] == '/' && b[2] != '\0')
+		b += 2;
+	/* Find the first difference, or return (0) if none. */
+	while (*a == *b) {
+		if (*a == '\0')
+			return (0);
+		a++;
+		b++;
+	}
+	/*
+	 * If one ends in '/' and the other one doesn't,
+	 * they're the same.
+	 */
+	if (a[0] == '/' && a[1] == '\0' && b[0] == '\0')
+		return (0);
+	if (a[0] == '\0' && b[0] == '/' && b[1] == '\0')
+		return (0);
+	/* They're really different, return the correct sign. */
+	return (*(const unsigned char *)a - *(const unsigned char *)b);
+}
Index: getdate.y
===================================================================
RCS file: /home/cvs/src/usr.bin/tar/getdate.y,v
retrieving revision 1.2
retrieving revision 1.3
diff -Lusr.bin/tar/getdate.y -Lusr.bin/tar/getdate.y -u -r1.2 -r1.3
--- usr.bin/tar/getdate.y
+++ usr.bin/tar/getdate.y
@@ -8,6 +8,7 @@
  * (eliminate some state variables and post-processing).  Among other
  * things, these changes eliminated two shift/reduce conflicts.  (Went
  * from 10 to 8.)
+ * All of Tim Kientzle's changes to this file are public domain.
  */
 
 /*
@@ -25,8 +26,7 @@
 
 #ifdef __FreeBSD__
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
-__FBSDID("$FreeBSD: src/usr.bin/tar/getdate.y,v 1.4.2.2 2006/11/10 16:09:13 kientzle Exp $");
+__FBSDID("$FreeBSD: src/usr.bin/tar/getdate.y,v 1.9 2007/07/20 01:27:50 kientzle Exp $");
 #endif
 
 #include <ctype.h>
@@ -611,7 +611,7 @@
 	char	buff[64];
 
 	for ( ; ; ) {
-		while (isspace(*yyInput))
+		while (isspace((unsigned char)*yyInput))
 			yyInput++;
 
 		/* Skip parenthesized comments. */
@@ -638,11 +638,11 @@
 
 			/* Force to lowercase and strip '.' characters. */
 			while (*src != '\0'
-			    && (isalnum(*src) || *src == '.')
+			    && (isalnum((unsigned char)*src) || *src == '.')
 			    && i < sizeof(buff)-1) {
 				if (*src != '.') {
-					if (isupper(*src))
-						buff[i++] = tolower(*src);
+					if (isupper((unsigned char)*src))
+						buff[i++] = tolower((unsigned char)*src);
 					else
 						buff[i++] = *src;
 				}
@@ -676,8 +676,8 @@
 		 * Because '-' and '+' have other special meanings, I
 		 * don't deal with signed numbers here.
 		 */
-		if (isdigit(c = *yyInput)) {
-			for (yylval.Number = 0; isdigit(c = *yyInput++); )
+		if (isdigit((unsigned char)(c = *yyInput))) {
+			for (yylval.Number = 0; isdigit((unsigned char)(c = *yyInput++)); )
 				yylval.Number = 10 * yylval.Number + c - '0';
 			yyInput--;
 			return (tUNUMBER);
Index: COPYING
===================================================================
RCS file: /home/cvs/src/usr.bin/tar/COPYING,v
retrieving revision 1.2
retrieving revision 1.3
diff -Lusr.bin/tar/COPYING -Lusr.bin/tar/COPYING -u -r1.2 -r1.3
--- usr.bin/tar/COPYING
+++ usr.bin/tar/COPYING
@@ -24,4 +24,4 @@
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-$FreeBSD: src/usr.bin/tar/COPYING,v 1.1.8.1 2007/01/27 06:48:39 kientzle Exp $
+$FreeBSD: src/usr.bin/tar/COPYING,v 1.2 2007/01/09 08:12:17 kientzle Exp $
Index: matching.c
===================================================================
RCS file: /home/cvs/src/usr.bin/tar/matching.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -Lusr.bin/tar/matching.c -Lusr.bin/tar/matching.c -u -r1.2 -r1.3
--- usr.bin/tar/matching.c
+++ usr.bin/tar/matching.c
@@ -24,12 +24,18 @@
  */
 
 #include "bsdtar_platform.h"
+__FBSDID("$FreeBSD: src/usr.bin/tar/matching.c,v 1.11 2007/03/11 10:36:42 kientzle Exp $");
 __MBSDID("$MidnightBSD$");
-__FBSDID("$FreeBSD: src/usr.bin/tar/matching.c,v 1.9.2.1 2007/01/27 06:48:39 kientzle Exp $");
 
+#ifdef HAVE_ERRNO_H
 #include <errno.h>
+#endif
+#ifdef HAVE_STDLIB_H
 #include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
 #include <string.h>
+#endif
 
 #include "bsdtar.h"
 
--- /dev/null
+++ usr.bin/tar/config_midnightbsd.h
@@ -0,0 +1,101 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * 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 AUTHOR(S) ``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 AUTHOR(S) 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.
+ *
+ * $FreeBSD: src/usr.bin/tar/config_freebsd.h,v 1.1 2007/03/11 10:36:42 kientzle Exp $
+ # $MidnightBSD: src/usr.bin/tar/config_midnightbsd.h,v 1.1 2007/09/29 22:15:57 ctriv Exp $
+ */
+
+/* A default configuration for FreeBSD, used if there is no config.h. */
+
+#define	PACKAGE_NAME "bsdtar"
+
+#define	HAVE_ACL_GET_PERM 0
+#define	HAVE_ACL_GET_PERM_NP 1
+#define	HAVE_ACL_PERMSET_T 1
+#define	HAVE_ACL_USER 1
+#undef	HAVE_ATTR_XATTR_H
+#define	HAVE_BZLIB_H 1
+#define	HAVE_CHFLAGS 1
+#define	HAVE_DIRENT_D_NAMLEN 1
+#define	HAVE_DIRENT_H 1
+#define	HAVE_D_MD_ORDER 1
+#define	HAVE_ERRNO_H 1
+#undef	HAVE_EXT2FS_EXT2_FS_H
+#define	HAVE_FCHDIR 1
+#define	HAVE_FCNTL_H 1
+#define	HAVE_FNMATCH 1
+#define	HAVE_FNMATCH_H 1
+#define	HAVE_FNM_LEADING_DIR 1
+#define	HAVE_FTRUNCATE 1
+#define	HAVE_GETOPT_LONG 1
+#undef	HAVE_GETXATTR
+#define	HAVE_GRP_H 1
+#define	HAVE_INTTYPES_H 1
+#define	HAVE_LANGINFO_H 1
+#undef	HAVE_LGETXATTR
+#undef	HAVE_LIBACL
+#define	HAVE_LIBARCHIVE 1
+#define	HAVE_LIBBZ2 1
+#define	HAVE_LIBZ 1
+#define	HAVE_LIMITS_H 1
+#undef	HAVE_LINUX_EXT2_FS_H
+#undef	HAVE_LINUX_FS_H
+#undef	HAVE_LISTXATTR
+#undef	HAVE_LLISTXATTR
+#define	HAVE_LOCALE_H 1
+#define	HAVE_MALLOC 1
+#define	HAVE_MEMMOVE 1
+#define	HAVE_MEMORY_H 1
+#define	HAVE_MEMSET 1
+#define	HAVE_NL_LANGINFO 1
+#define	HAVE_PATHS_H 1
+#define	HAVE_PWD_H 1
+#define	HAVE_SETLOCALE 1
+#define	HAVE_STDARG_H 1
+#define	HAVE_STDINT_H 1
+#define	HAVE_STDLIB_H 1
+#define	HAVE_STRCHR 1
+#define	HAVE_STRDUP 1
+#define	HAVE_STRERROR 1
+#define	HAVE_STRFTIME 1
+#define	HAVE_STRINGS_H 1
+#define	HAVE_STRING_H 1
+#define	HAVE_STRRCHR 1
+#undef	HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
+#define	HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 1
+#define	HAVE_STRUCT_STAT_ST_RDEV 1
+#define	HAVE_SYS_ACL_H 1
+#define	HAVE_SYS_IOCTL_H 1
+#define	HAVE_SYS_PARAM_H 1
+#define	HAVE_SYS_STAT_H 1
+#define	HAVE_TIME_H 1
+#define	HAVE_SYS_TYPES_H 1
+#define	HAVE_UINTMAX_T 1
+#define	HAVE_UNISTD_H 1
+#define	HAVE_UNSIGNED_LONG_LONG
+#define	HAVE_VPRINTF 1
+#define	HAVE_ZLIB_H 1
+#undef	MAJOR_IN_MKDEV
+#define	STDC_HEADERS 1
+
Index: tree.h
===================================================================
RCS file: /home/cvs/src/usr.bin/tar/tree.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -Lusr.bin/tar/tree.h -Lusr.bin/tar/tree.h -u -r1.2 -r1.3
--- usr.bin/tar/tree.h
+++ usr.bin/tar/tree.h
@@ -22,8 +22,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $MidnightBSD$
- * $FreeBSD: src/usr.bin/tar/tree.h,v 1.2.2.1 2007/01/27 06:48:39 kientzle Exp $
+ * $FreeBSD: src/usr.bin/tar/tree.h,v 1.3 2007/01/09 08:12:17 kientzle Exp $
  */
 
 /*-
Index: bsdtar.h
===================================================================
RCS file: /home/cvs/src/usr.bin/tar/bsdtar.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -Lusr.bin/tar/bsdtar.h -Lusr.bin/tar/bsdtar.h -u -r1.2 -r1.3
--- usr.bin/tar/bsdtar.h
+++ usr.bin/tar/bsdtar.h
@@ -22,8 +22,8 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
+ * $FreeBSD: src/usr.bin/tar/bsdtar.h,v 1.28 2007/05/29 05:39:10 kientzle Exp $
  * $MidnightBSD$
- * $FreeBSD: src/usr.bin/tar/bsdtar.h,v 1.23.2.3 2007/01/27 06:48:39 kientzle Exp $
  */
 
 #include "bsdtar_platform.h"
@@ -56,6 +56,7 @@
 	char		  mode; /* Program mode: 'c', 't', 'r', 'u', 'x' */
 	char		  symlink_mode; /* H or L, per BSD conventions */
 	char		  create_compression; /* j, y, or z */
+	const char	 *compress_program;
 	char		  option_absolute_paths; /* -P */
 	char		  option_dont_traverse_mounts; /* --one-file-system */
 	char		  option_fast_read; /* --fast-read */
@@ -109,6 +110,7 @@
 int	excluded(struct bsdtar *, const char *pathname);
 int	include(struct bsdtar *, const char *pattern);
 int	include_from_file(struct bsdtar *, const char *pathname);
+int	pathcmp(const char *a, const char *b);
 int	process_lines(struct bsdtar *bsdtar, const char *pathname,
 	    int (*process)(struct bsdtar *, const char *));
 void	safe_fprintf(FILE *, const char *fmt, ...);
Index: write.c
===================================================================
RCS file: /home/cvs/src/usr.bin/tar/write.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -Lusr.bin/tar/write.c -Lusr.bin/tar/write.c -u -r1.2 -r1.3
--- usr.bin/tar/write.c
+++ usr.bin/tar/write.c
@@ -24,30 +24,60 @@
  */
 
 #include "bsdtar_platform.h"
+__FBSDID("$FreeBSD: src/usr.bin/tar/write.c,v 1.63 2007/05/29 05:39:10 kientzle Exp $");
 __MBSDID("$MidnightBSD$");
-__FBSDID("$FreeBSD: src/usr.bin/tar/write.c,v 1.41.2.5 2007/02/25 07:24:44 kientzle Exp $");
 
-#include <sys/stat.h>
+#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#ifdef HAVE_POSIX_ACL
+#endif
+#ifdef HAVE_SYS_ACL_H
 #include <sys/acl.h>
 #endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
 #ifdef HAVE_ATTR_XATTR_H
 #include <attr/xattr.h>
 #endif
+#ifdef HAVE_ERRNO_H
 #include <errno.h>
+#endif
+#ifdef HAVE_EXT2FS_EXT2_FS_H
+#include <ext2fs/ext2_fs.h>
+#endif
+#ifdef HAVE_FCNTL_H
 #include <fcntl.h>
+#endif
+#ifdef HAVE_FNMATCH_H
 #include <fnmatch.h>
+#endif
+#ifdef HAVE_GRP_H
 #include <grp.h>
+#endif
+#ifdef HAVE_LIMITS_H
 #include <limits.h>
+#endif
+#ifdef HAVE_LINUX_FS_H
+#include <linux/fs.h>	/* for Linux file flags */
+#endif
+#ifdef HAVE_LINUX_EXT2_FS_H
+#include <linux/ext2_fs.h>	/* for Linux file flags */
+#endif
+#ifdef HAVE_PWD_H
 #include <pwd.h>
+#endif
 #include <stdio.h>
+#ifdef HAVE_STDLIB_H
 #include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
 #include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
 #include <unistd.h>
-#ifdef __linux
-#include <ext2fs/ext2_fs.h>
-#include <sys/ioctl.h>
 #endif
 
 #include "bsdtar.h"
@@ -100,11 +130,15 @@
 static void		 add_dir_list(struct bsdtar *bsdtar, const char *path,
 			     time_t mtime_sec, int mtime_nsec);
 static int		 append_archive(struct bsdtar *, struct archive *,
-			     const char *fname);
+			     struct archive *ina);
+static int		 append_archive_filename(struct bsdtar *,
+			     struct archive *, const char *fname);
 static void		 archive_names_from_file(struct bsdtar *bsdtar,
 			     struct archive *a);
 static int		 archive_names_from_file_helper(struct bsdtar *bsdtar,
 			     const char *line);
+static int		 copy_file_data(struct bsdtar *bsdtar,
+			     struct archive *a, struct archive *ina);
 static void		 create_cleanup(struct bsdtar *);
 static void		 free_buckets(struct bsdtar *, struct links_cache *);
 static void		 free_cache(struct name_cache *cache);
@@ -126,7 +160,7 @@
 static void		 write_archive(struct archive *, struct bsdtar *);
 static void		 write_entry(struct bsdtar *, struct archive *,
 			     const struct stat *, const char *pathname,
-			     unsigned pathlen, const char *accpath);
+			     const char *accpath);
 static int		 write_file_data(struct bsdtar *, struct archive *,
 			     int fd);
 static void		 write_hierarchy(struct bsdtar *, struct archive *,
@@ -170,23 +204,28 @@
 	} else
 		archive_write_set_bytes_per_block(a, DEFAULT_BYTES_PER_BLOCK);
 
-	switch (bsdtar->create_compression) {
-	case 0:
-		break;
+	if (bsdtar->compress_program) {
+		archive_write_set_compression_program(a, bsdtar->compress_program);
+	} else {
+		switch (bsdtar->create_compression) {
+		case 0:
+			archive_write_set_compression_none(a);
+			break;
 #ifdef HAVE_LIBBZ2
-	case 'j': case 'y':
-		archive_write_set_compression_bzip2(a);
-		break;
+		case 'j': case 'y':
+			archive_write_set_compression_bzip2(a);
+			break;
 #endif
 #ifdef HAVE_LIBZ
-	case 'z':
-		archive_write_set_compression_gzip(a);
-		break;
+		case 'z':
+			archive_write_set_compression_gzip(a);
+			break;
 #endif
-	default:
-		bsdtar_errc(bsdtar, 1, 0,
-		    "Unrecognized compression option -%c",
-		    bsdtar->create_compression);
+		default:
+			bsdtar_errc(bsdtar, 1, 0,
+			    "Unrecognized compression option -%c",
+			    bsdtar->create_compression);
+		}
 	}
 
 	r = archive_write_open_file(a, bsdtar->filename);
@@ -421,10 +460,11 @@
 			}
 			set_chdir(bsdtar, arg);
 		} else {
-			if (*arg != '/' || (arg[0] == '@' && arg[1] != '/'))
+			if (*arg != '/' && (arg[0] != '@' || arg[1] != '/'))
 				do_chdir(bsdtar); /* Handle a deferred -C */
 			if (*arg == '@') {
-				if (append_archive(bsdtar, a, arg + 1) != 0)
+				if (append_archive_filename(bsdtar, a,
+				    arg + 1) != 0)
 					break;
 			} else
 				write_hierarchy(bsdtar, a, arg);
@@ -484,12 +524,11 @@
  * operation will complete and return non-zero.
  */
 static int
-append_archive(struct bsdtar *bsdtar, struct archive *a, const char *filename)
+append_archive_filename(struct bsdtar *bsdtar, struct archive *a,
+    const char *filename)
 {
 	struct archive *ina;
-	struct archive_entry *in_entry;
-	int bytes_read, bytes_written;
-	char buff[8192];
+	int rc;
 
 	if (strcmp(filename, "-") == 0)
 		filename = NULL; /* Library uses NULL for stdio. */
@@ -502,6 +541,25 @@
 		bsdtar->return_value = 1;
 		return (0);
 	}
+
+	rc = append_archive(bsdtar, a, ina);
+
+	if (archive_errno(ina)) {
+		bsdtar_warnc(bsdtar, 0, "Error reading archive %s: %s",
+		    filename, archive_error_string(ina));
+		bsdtar->return_value = 1;
+	}
+	archive_read_finish(ina);
+
+	return (rc);
+}
+
+static int
+append_archive(struct bsdtar *bsdtar, struct archive *a, struct archive *ina)
+{
+	struct archive_entry *in_entry;
+	int e;
+
 	while (0 == archive_read_next_header(ina, &in_entry)) {
 		if (!new_enough(bsdtar, archive_entry_pathname(in_entry),
 			archive_entry_stat(in_entry)))
@@ -514,40 +572,52 @@
 		if (bsdtar->verbose)
 			safe_fprintf(stderr, "a %s",
 			    archive_entry_pathname(in_entry));
-		/* XXX handle/report errors XXX */
-		if (archive_write_header(a, in_entry)) {
-			bsdtar_warnc(bsdtar, 0, "%s",
-			    archive_error_string(a));
-			bsdtar->return_value = 1;
-			return (-1);
-		}
-		bytes_read = archive_read_data(ina, buff, sizeof(buff));
-		while (bytes_read > 0) {
-			bytes_written =
-			    archive_write_data(a, buff, bytes_read);
-			if (bytes_written < bytes_read) {
-				bsdtar_warnc(bsdtar, archive_errno(a), "%s",
+
+		e = archive_write_header(a, in_entry);
+		if (e != ARCHIVE_OK) {
+			if (!bsdtar->verbose)
+				bsdtar_warnc(bsdtar, 0, "%s: %s",
+				    archive_entry_pathname(in_entry),
 				    archive_error_string(a));
-				return (-1);
-			}
-			bytes_read =
-			    archive_read_data(ina, buff, sizeof(buff));
+			else
+				fprintf(stderr, ": %s", archive_error_string(a));
 		}
+		if (e == ARCHIVE_FATAL)
+			exit(1);
+
+		if (e >= ARCHIVE_WARN)
+			if (copy_file_data(bsdtar, a, ina))
+				exit(1);
+
 		if (bsdtar->verbose)
 			fprintf(stderr, "\n");
-
 	}
-	if (archive_errno(ina)) {
-		bsdtar_warnc(bsdtar, 0, "Error reading archive %s: %s",
-		    filename, archive_error_string(ina));
-		bsdtar->return_value = 1;
-	}
-	archive_read_finish(ina);
 
 	/* Note: If we got here, we saw no write errors, so return success. */
 	return (0);
 }
 
+/* Helper function to copy data between archives. */
+static int
+copy_file_data(struct bsdtar *bsdtar, struct archive *a, struct archive *ina)
+{
+	char	buff[64*1024];
+	ssize_t	bytes_read;
+	ssize_t	bytes_written;
+
+	bytes_read = archive_read_data(ina, buff, sizeof(buff));
+	while (bytes_read > 0) {
+		bytes_written = archive_write_data(a, buff, bytes_read);
+		if (bytes_written < bytes_read) {
+			bsdtar_warnc(bsdtar, 0, "%s", archive_error_string(a));
+			return (-1);
+		}
+		bytes_read = archive_read_data(ina, buff, sizeof(buff));
+	}
+
+	return (0);
+}
+
 /*
  * Add the file or dir hierarchy named by 'path' to the archive
  */
@@ -584,8 +654,17 @@
 		lst = tree_current_lstat(tree);
 		if (lst == NULL) {
 			/* Couldn't lstat(); must not exist. */
-			bsdtar_warnc(bsdtar, errno, "%s: Cannot stat", path);
-			bsdtar->return_value = 1;
+			bsdtar_warnc(bsdtar, errno, "%s: Cannot stat", name);
+
+			/*
+			 * Report an error via the exit code if the failed
+			 * path is a prefix of what the user provided via
+			 * the command line.  (Testing for string equality
+			 * here won't work due to trailing '/' characters.)
+			 */
+			if (memcmp(name, path, strlen(name)) == 0)
+				bsdtar->return_value = 1;
+
 			continue;
 		}
 		if (S_ISLNK(lst->st_mode))
@@ -690,7 +769,6 @@
 		 * pathname editing and newness testing.
 		 */
 		write_entry(bsdtar, a, lst, name,
-		    tree_current_pathlen(tree),
 		    tree_current_access_path(tree));
 	}
 	tree_close(tree);
@@ -701,7 +779,7 @@
  */
 static void
 write_entry(struct bsdtar *bsdtar, struct archive *a, const struct stat *st,
-    const char *pathname, unsigned pathlen, const char *accpath)
+    const char *pathname, const char *accpath)
 {
 	struct archive_entry	*entry;
 	int			 e;
@@ -712,8 +790,6 @@
 #endif
 	static char		 linkbuffer[PATH_MAX+1];
 
-	(void)pathlen; /* UNUSED */
-
 	fd = -1;
 	entry = archive_entry_new();
 
@@ -821,7 +897,7 @@
 	 * to inform us that the archive body won't get stored.  In
 	 * that case, just skip the write.
 	 */
-	if (fd >= 0 && archive_entry_size(entry) > 0)
+	if (e >= ARCHIVE_WARN && fd >= 0 && archive_entry_size(entry) > 0)
 		if (write_file_data(bsdtar, a, fd))
 			exit(1);
 
@@ -1396,7 +1472,7 @@
 	if (bsdtar->archive_dir != NULL &&
 	    bsdtar->archive_dir->head != NULL) {
 		for (p = bsdtar->archive_dir->head; p != NULL; p = p->next) {
-			if (strcmp(path, p->name)==0)
+			if (pathcmp(path, p->name)==0)
 				return (p->mtime_sec < st->st_mtime ||
 				    (p->mtime_sec == st->st_mtime &&
 					p->mtime_nsec
@@ -1419,9 +1495,6 @@
 {
 	struct archive_dir_entry	*p;
 
-	if (path[0] == '.' && path[1] == '/' && path[2] != '\0')
-		path += 2;
-
 	/*
 	 * Search entire list to see if this file has appeared before.
 	 * If it has, override the timestamp data.
Index: bsdtar.1
===================================================================
RCS file: /home/cvs/src/usr.bin/tar/bsdtar.1,v
retrieving revision 1.2
retrieving revision 1.3
diff -Lusr.bin/tar/bsdtar.1 -Lusr.bin/tar/bsdtar.1 -u -r1.2 -r1.3
--- usr.bin/tar/bsdtar.1
+++ usr.bin/tar/bsdtar.1
@@ -22,8 +22,8 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
+.\" $FreeBSD: src/usr.bin/tar/bsdtar.1,v 1.35 2007/05/29 05:39:10 kientzle Exp $
 .\" $MidnightBSD$
-.\" $FreeBSD: src/usr.bin/tar/bsdtar.1,v 1.29.2.3 2007/01/27 06:48:39 kientzle Exp $
 .\"
 .Dd April 13, 2004
 .Dt BSDTAR 1
@@ -51,6 +51,9 @@
 .Sh DESCRIPTION
 .Nm
 creates and manipulates streaming archive files.
+This implementation can extract from tar, pax, cpio, zip, jar, ar,
+and ISO 9660 cdrom images and can create tar, pax, cpio, ar,
+and shar archives.
 .Pp
 The first synopsis form shows a
 .Dq bundled
@@ -358,6 +361,10 @@
 overwrites existing files, which preserves existing hardlinks.
 With this option, existing hardlinks will be broken, as will any
 symlink that would affect the location of an extracted file.
+.It Fl -use-compress-program Ar program
+Pipe the input (in x or t mode) or the output (in c mode) through
+.Pa program
+instead of using the builtin compression support.
 .It Fl v
 Produce verbose output.
 In create and extract modes,
@@ -461,6 +468,9 @@
 the default tape drive:
 .Dl Nm Fl x
 .Pp
+To examine the contents of an ISO 9660 cdrom image:
+.Dl Nm Fl tf Pa image.iso
+.Pp
 To move file hierarchies, invoke
 .Nm
 as
Index: bsdtar.c
===================================================================
RCS file: /home/cvs/src/usr.bin/tar/bsdtar.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -Lusr.bin/tar/bsdtar.c -Lusr.bin/tar/bsdtar.c -u -r1.2 -r1.3
--- usr.bin/tar/bsdtar.c
+++ usr.bin/tar/bsdtar.c
@@ -24,13 +24,21 @@
  */
 
 #include "bsdtar_platform.h"
+__FBSDID("$FreeBSD: src/usr.bin/tar/bsdtar.c,v 1.77 2007/09/09 00:07:18 kientzle Exp $");
 __MBSDID("$MidnightBSD$");
-__FBSDID("$FreeBSD: src/usr.bin/tar/bsdtar.c,v 1.63.2.5 2007/01/27 06:48:39 kientzle Exp $");
 
+#ifdef HAVE_SYS_PARAM_H
 #include <sys/param.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
+#endif
+#ifdef HAVE_ERRNO_H
 #include <errno.h>
+#endif
+#ifdef HAVE_FCNTL_H
 #include <fcntl.h>
+#endif
 #ifdef HAVE_GETOPT_LONG
 #include <getopt.h>
 #else
@@ -46,21 +54,35 @@
 #ifdef HAVE_LANGINFO_H
 #include <langinfo.h>
 #endif
+#ifdef HAVE_LOCALE_H
 #include <locale.h>
+#endif
 #ifdef HAVE_PATHS_H
 #include <paths.h>
 #endif
 #include <stdio.h>
+#ifdef HAVE_STDLIB_H
 #include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
 #include <string.h>
+#endif
+#ifdef HAVE_TIME_H
 #include <time.h>
+#endif
+#ifdef HAVE_UNISTD_H
 #include <unistd.h>
+#endif
 #if HAVE_ZLIB_H
 #include <zlib.h>
 #endif
 
 #include "bsdtar.h"
 
+/*
+ * Per POSIX.1-1988, tar defaults to reading/writing archives to/from
+ * the default tape device for the system.  Pick something reasonable here.
+ */
 #ifdef __linux
 #define	_PATH_DEFTAPE "/dev/st0"
 #endif
@@ -118,11 +140,14 @@
 	OPTION_NEWER_MTIME,
 	OPTION_NEWER_MTIME_THAN,
 	OPTION_NODUMP,
+	OPTION_NO_SAME_OWNER,
 	OPTION_NO_SAME_PERMISSIONS,
 	OPTION_NULL,
 	OPTION_ONE_FILE_SYSTEM,
+	OPTION_POSIX,
 	OPTION_STRIP_COMPONENTS,
 	OPTION_TOTALS,
+	OPTION_USE_COMPRESS_PROGRAM,
 	OPTION_VERSION
 };
 
@@ -167,10 +192,11 @@
 	{ "nodump",             no_argument,       NULL, OPTION_NODUMP },
 	{ "norecurse",          no_argument,       NULL, 'n' },
 	{ "no-recursion",       no_argument,       NULL, 'n' },
-	{ "no-same-owner",	no_argument,	   NULL, 'o' },
+	{ "no-same-owner",	no_argument,	   NULL, OPTION_NO_SAME_OWNER },
 	{ "no-same-permissions",no_argument,	   NULL, OPTION_NO_SAME_PERMISSIONS },
 	{ "null",		no_argument,	   NULL, OPTION_NULL },
 	{ "one-file-system",	no_argument,	   NULL, OPTION_ONE_FILE_SYSTEM },
+	{ "posix",		no_argument,	   NULL, OPTION_POSIX },
 	{ "preserve-permissions", no_argument,     NULL, 'p' },
 	{ "read-full-blocks",	no_argument,	   NULL, 'B' },
 	{ "same-permissions",   no_argument,       NULL, 'p' },
@@ -180,11 +206,18 @@
 	{ "unlink",		no_argument,       NULL, 'U' },
 	{ "unlink-first",	no_argument,       NULL, 'U' },
 	{ "update",             no_argument,       NULL, 'u' },
+	{ "use-compress-program",
+				required_argument, NULL, OPTION_USE_COMPRESS_PROGRAM },
 	{ "verbose",            no_argument,       NULL, 'v' },
 	{ "version",            no_argument,       NULL, OPTION_VERSION },
 	{ NULL, 0, NULL, 0 }
 };
 
+/* A basic set of security flags to request from libarchive. */
+#define	SECURITY					\
+	(ARCHIVE_EXTRACT_SECURE_SYMLINKS		\
+	 | ARCHIVE_EXTRACT_SECURE_NODOTDOT)
+
 int
 main(int argc, char **argv)
 {
@@ -233,9 +266,19 @@
 	/* Default: preserve mod time on extract */
 	bsdtar->extract_flags = ARCHIVE_EXTRACT_TIME;
 
-	/* Default for root user: preserve ownership on extract. */
-	if (bsdtar->user_uid == 0)
+	/* Default: Perform basic security checks. */
+	bsdtar->extract_flags |= SECURITY;
+
+	/* Defaults for root user: */
+	if (bsdtar->user_uid == 0) {
+		/* --same-owner */
 		bsdtar->extract_flags |= ARCHIVE_EXTRACT_OWNER;
+		/* -p */
+		bsdtar->extract_flags |= ARCHIVE_EXTRACT_PERM;
+		bsdtar->extract_flags |= ARCHIVE_EXTRACT_ACL;
+		bsdtar->extract_flags |= ARCHIVE_EXTRACT_XATTR;
+		bsdtar->extract_flags |= ARCHIVE_EXTRACT_FFLAGS;
+	}
 
 	/* Rewrite traditional-style tar arguments, if used. */
 	argv = rewrite_argv(bsdtar, &argc, argv, tar_opts);
@@ -244,6 +287,12 @@
 	bsdtar->argc = argc;
 
 	/* Process all remaining arguments now. */
+	/*
+	 * Comments following each option indicate where that option
+	 * originated:  SUSv2, POSIX, GNU tar, star, etc.  If there's
+	 * no such comment, then I don't know of anyone else who
+	 * implements that option.
+	 */
 	while ((opt = bsdtar_getopt(bsdtar, tar_opts, &option)) != -1) {
 		switch (opt) {
 		case 'B': /* GNU tar */
@@ -270,7 +319,7 @@
 				bsdtar_errc(bsdtar, 1, 0,
 				    "Couldn't exclude %s\n", optarg);
 			break;
-		case OPTION_FORMAT:
+		case OPTION_FORMAT: /* GNU tar, others */
 			bsdtar->create_format = optarg;
 			break;
 		case 'f': /* SUSv2 */
@@ -289,14 +338,29 @@
 			/* Hack: -h by itself is the "help" command. */
 			possible_help_request = 1;
 			break;
-		case OPTION_HELP:
+		case OPTION_HELP: /* GNU tar, others */
 			long_help(bsdtar);
 			exit(0);
 			break;
 		case 'I': /* GNU tar */
+			/*
+			 * TODO: Allow 'names' to come from an archive,
+			 * not just a text file.  Design a good UI for
+			 * allowing names and mode/owner to be read
+			 * from an archive, with contents coming from
+			 * disk.  This can be used to "refresh" an
+			 * archive or to design archives with special
+			 * permissions without having to create those
+			 * permissions on disk.
+			 */
 			bsdtar->names_from_file = optarg;
 			break;
 		case OPTION_INCLUDE:
+			/*
+			 * Noone else has the @archive extension, so
+			 * noone else needs this to filter entries
+			 * when transforming archives.
+			 */
 			if (include(bsdtar, optarg))
 				bsdtar_errc(bsdtar, 1, 0,
 				    "Failed to add %s to inclusion list",
@@ -340,6 +404,13 @@
 		case 'n': /* GNU tar */
 			bsdtar->option_no_subdirs = 1;
 			break;
+	        /*
+		 * Selecting files by time:
+		 *    --newer-?time='date' Only files newer than 'date'
+		 *    --newer-?time-than='file' Only files newer than time
+		 *         on specified file (useful for incremental backups)
+		 * TODO: Add corresponding "older" options to reverse these.
+		 */
 		case OPTION_NEWER_CTIME: /* GNU tar */
 			bsdtar->newer_ctime_sec = get_date(optarg);
 			break;
@@ -371,13 +442,14 @@
 		case OPTION_NODUMP: /* star */
 			bsdtar->option_honor_nodump = 1;
 			break;
+		case OPTION_NO_SAME_OWNER: /* GNU tar */
+			bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_OWNER;
+			break;
 		case OPTION_NO_SAME_PERMISSIONS: /* GNU tar */
-			/*
-			 * This is always the default in FreeBSD's
-			 * version of GNU tar; it's also the default
-			 * behavior for bsdtar, so treat the
-			 * command-line option as a no-op.
-			 */
+			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 OPTION_NULL: /* GNU tar */
 			bsdtar->option_null++;
@@ -385,10 +457,10 @@
 		case 'O': /* GNU tar */
 			bsdtar->option_stdout = 1;
 			break;
-		case 'o': /* SUSv2 and GNU conflict here */
+		case 'o': /* SUSv2 and GNU conflict here, but not fatally */
 			option_o = 1; /* Record it and resolve it later. */
 			break;
-		case OPTION_ONE_FILE_SYSTEM: /* -l in GNU tar */
+		case OPTION_ONE_FILE_SYSTEM: /* GNU tar */
 			bsdtar->option_dont_traverse_mounts = 1;
 			break;
 #if 0
@@ -403,6 +475,7 @@
 			break;
 #endif
 		case 'P': /* GNU tar */
+			bsdtar->extract_flags &= ~SECURITY;
 			bsdtar->option_absolute_paths = 1;
 			break;
 		case 'p': /* GNU tar, star */
@@ -411,6 +484,9 @@
 			bsdtar->extract_flags |= ARCHIVE_EXTRACT_XATTR;
 			bsdtar->extract_flags |= ARCHIVE_EXTRACT_FFLAGS;
 			break;
+		case OPTION_POSIX: /* GNU tar */
+			bsdtar->create_format = "pax";
+			break;
 		case 'r': /* SUSv2 */
 			set_mode(bsdtar, opt);
 			break;
@@ -437,9 +513,17 @@
 		case 'v': /* SUSv2 */
 			bsdtar->verbose++;
 			break;
-		case OPTION_VERSION:
+		case OPTION_VERSION: /* GNU convention */
 			version();
 			break;
+#if 0
+		/*
+		 * The -W longopt feature is handled inside of
+		 * bsdtar_getop(), so -W is not available here.
+		 */
+		case 'W': /* Obscure, but useful GNU convention. */
+			break;
+#endif
 		case 'w': /* SUSv2 */
 			bsdtar->option_interactive = 1;
 			break;
@@ -483,6 +567,9 @@
 			usage(bsdtar);
 #endif
 			break;
+		case OPTION_USE_COMPRESS_PROGRAM:
+			bsdtar->compress_program = optarg;
+			break;
 		default:
 			usage(bsdtar);
 		}
@@ -491,11 +578,14 @@
 	/*
 	 * Sanity-check options.
 	 */
+
+	/* If no "real" mode was specified, treat -h as --help. */
 	if ((bsdtar->mode == '\0') && possible_help_request) {
 		long_help(bsdtar);
 		exit(0);
 	}
 
+	/* Otherwise, a mode is required. */
 	if (bsdtar->mode == '\0')
 		bsdtar_errc(bsdtar, 1, 0,
 		    "Must specify one of -c, -r, -t, -u, -x");
@@ -579,6 +669,9 @@
 	}
 
 	cleanup_exclusions(bsdtar);
+	if (bsdtar->return_value != 0)
+		bsdtar_warnc(bsdtar, 0,
+		    "Error exit delayed from previous errors.");
 	return (bsdtar->return_value);
 }
 
@@ -824,6 +917,10 @@
 				    "(matches both %s and %s)",
 				    p, (*poption)->name, option->name);
 
+			if ((*poption)->has_arg == required_argument
+			    && optarg == NULL)
+				bsdtar_errc(bsdtar, 1, 0,
+				    "Option \"%s\" requires argument", p);
 		} else {
 			opt = '?';
 			/* TODO: Set up a fake 'struct option' for
Index: Makefile
===================================================================
RCS file: /home/cvs/src/usr.bin/tar/Makefile,v
retrieving revision 1.2
retrieving revision 1.3
diff -Lusr.bin/tar/Makefile -Lusr.bin/tar/Makefile -u -r1.2 -r1.3
--- usr.bin/tar/Makefile
+++ usr.bin/tar/Makefile
@@ -1,13 +1,14 @@
+# $FreeBSD: src/usr.bin/tar/Makefile,v 1.32 2007/07/20 01:24:49 kientzle Exp $
 # $MidnightBSD$
-# $FreeBSD: src/usr.bin/tar/Makefile,v 1.24.2.1 2006/07/30 06:32:14 kientzle Exp $
 
 PROG=	bsdtar
-VERSION=	1.2.53
+VERSION=	2.2.5
 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
 CFLAGS+=	-DPACKAGE_VERSION=\"${VERSION}\"
+CFLAGS+=	-DPLATFORM_CONFIG_H=\"config_midnightbsd.h\"
 CFLAGS+=	-I${.CURDIR}
 SYMLINKS=	bsdtar ${BINDIR}/tar
 MLINKS=	bsdtar.1 tar.1
Index: tree.c
===================================================================
RCS file: /home/cvs/src/usr.bin/tar/tree.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -Lusr.bin/tar/tree.c -Lusr.bin/tar/tree.c -u -r1.2 -r1.3
--- usr.bin/tar/tree.c
+++ usr.bin/tar/tree.c
@@ -43,16 +43,30 @@
  * regular dir or via fchdir(2) for a symlink).
  */
 #include "bsdtar_platform.h"
+__FBSDID("$FreeBSD: src/usr.bin/tar/tree.c,v 1.8 2007/03/11 10:36:42 kientzle Exp $");
 __MBSDID("$MidnightBSD$");
-__FBSDID("$FreeBSD: src/usr.bin/tar/tree.c,v 1.2.2.2 2007/01/27 06:48:39 kientzle Exp $");
 
+#ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
+#endif
+#ifdef HAVE_DIRENT_H
 #include <dirent.h>
+#endif
+#ifdef HAVE_ERRNO_H
 #include <errno.h>
+#endif
+#ifdef HAVE_FCNTL_H
 #include <fcntl.h>
+#endif
+#ifdef HAVE_STDLIB_H
 #include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
 #include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
 #include <unistd.h>
+#endif
 
 #include "tree.h"
 
@@ -394,46 +408,70 @@
 }
 
 /*
- * Test whether current entry is a dir or dir link.
+ * Test whether current entry is a dir or link to a dir.
  */
 int
 tree_current_is_dir(struct tree *t)
 {
-	/* If we've already pulled stat(), just use that. */
-	if (t->flags & hasStat)
-		return (S_ISDIR(tree_current_stat(t)->st_mode));
+	const struct stat *st;
 
-	/* If we've already pulled lstat(), we may be able to use that. */
+	/*
+	 * If we already have lstat() info, then try some
+	 * cheap tests to determine if this is a dir.
+	 */
 	if (t->flags & hasLstat) {
 		/* If lstat() says it's a dir, it must be a dir. */
 		if (S_ISDIR(tree_current_lstat(t)->st_mode))
 			return 1;
-		/* If it's not a dir and not a link, we're done. */
+		/* Not a dir; might be a link to a dir. */
+		/* If it's not a link, then it's not a link to a dir. */
 		if (!S_ISLNK(tree_current_lstat(t)->st_mode))
 			return 0;
 		/*
-		 * If the above two tests fail, then it's a link, but
-		 * we don't know whether it's a link to a dir or a
-		 * non-dir.
+		 * It's a link, but we don't know what it's a link to,
+		 * so we'll have to use stat().
 		 */
 	}
 
-	/* TODO: Use a more efficient mechanism when available. */
-	return (S_ISDIR(tree_current_stat(t)->st_mode));
+	st = tree_current_stat(t);
+	/* If we can't stat it, it's not a dir. */
+	if (st == NULL)
+		return 0;
+	/* Use the definitive test.  Hopefully this is cached. */
+	return (S_ISDIR(st->st_mode));
 }
 
 /*
- * Test whether current entry is a physical directory.
+ * Test whether current entry is a physical directory.  Usually, we
+ * already have at least one of stat() or lstat() in memory, so we
+ * use tricks to try to avoid an extra trip to the disk.
  */
 int
 tree_current_is_physical_dir(struct tree *t)
 {
-	/* If we've already pulled lstat(), just use that. */
-	if (t->flags & hasLstat)
-		return (S_ISDIR(tree_current_lstat(t)->st_mode));
+	const struct stat *st;
+
+	/*
+	 * If stat() says it isn't a dir, then it's not a dir.
+	 * If stat() data is cached, this check is free, so do it first.
+	 */
+	if ((t->flags & hasStat)
+	    && (!S_ISDIR(tree_current_stat(t)->st_mode)))
+		return 0;
 
-	/* TODO: Use a more efficient mechanism when available. */
-	return (S_ISDIR(tree_current_lstat(t)->st_mode));
+	/*
+	 * Either stat() said it was a dir (in which case, we have
+	 * to determine whether it's really a link to a dir) or
+	 * stat() info wasn't available.  So we use lstat(), which
+	 * hopefully is already cached.
+	 */
+
+	st = tree_current_lstat(t);
+	/* If we can't stat it, it's not a dir. */
+	if (st == NULL)
+		return 0;
+	/* Use the definitive test.  Hopefully this is cached. */
+	return (S_ISDIR(st->st_mode));
 }
 
 /*
@@ -442,12 +480,10 @@
 int
 tree_current_is_physical_link(struct tree *t)
 {
-	/* If we've already pulled lstat(), just use that. */
-	if (t->flags & hasLstat)
-		return (S_ISLNK(tree_current_lstat(t)->st_mode));
-
-	/* TODO: Use a more efficient mechanism when available. */
-	return (S_ISLNK(tree_current_lstat(t)->st_mode));
+	const struct stat *st = tree_current_lstat(t);
+	if (st == NULL)
+		return 0;
+	return (S_ISLNK(st->st_mode));
 }
 
 /*
Index: read.c
===================================================================
RCS file: /home/cvs/src/usr.bin/tar/read.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -Lusr.bin/tar/read.c -Lusr.bin/tar/read.c -u -r1.2 -r1.3
--- usr.bin/tar/read.c
+++ usr.bin/tar/read.c
@@ -24,33 +24,55 @@
  */
 
 #include "bsdtar_platform.h"
+__FBSDID("$FreeBSD: src/usr.bin/tar/read.c,v 1.34 2007/07/20 01:24:49 kientzle Exp $");
 __MBSDID("$MidnightBSD$");
-__FBSDID("$FreeBSD: src/usr.bin/tar/read.c,v 1.23.2.3 2007/01/27 06:48:39 kientzle Exp $");
 
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
 #ifdef MAJOR_IN_MKDEV
 #include <sys/mkdev.h>
+#elif defined(MAJOR_IN_SYSMACROS)
+#include <sys/sysmacros.h>
 #endif
+#ifdef HAVE_SYS_PARAM_H
 #include <sys/param.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
-#include <sys/types.h>
+#endif
 
+#ifdef HAVE_ERRNO_H
 #include <errno.h>
+#endif
+#ifdef HAVE_GRP_H
 #include <grp.h>
+#endif
+#ifdef HAVE_LIMITS_H
 #include <limits.h>
+#endif
+#ifdef HAVE_PWD_H
 #include <pwd.h>
+#endif
 #include <stdio.h>
+#ifdef HAVE_STDLIB_H
 #include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
 #include <string.h>
+#endif
+#ifdef HAVE_TIME_H
 #include <time.h>
+#endif
+#ifdef HAVE_UNISTD_H
 #include <unistd.h>
+#endif
 
 #include "bsdtar.h"
 
-static void	cleanup_security(struct bsdtar *);
 static void	list_item_verbose(struct bsdtar *, FILE *,
 		    struct archive_entry *);
 static void	read_archive(struct bsdtar *bsdtar, char mode);
-static int	security_problem(struct bsdtar *, struct archive_entry *);
 
 void
 tar_mode_t(struct bsdtar *bsdtar)
@@ -85,7 +107,10 @@
 		include_from_file(bsdtar, bsdtar->names_from_file);
 
 	a = archive_read_new();
-	archive_read_support_compression_all(a);
+	if (bsdtar->compress_program != NULL)
+		archive_read_support_compression_program(a, bsdtar->compress_program);
+	else
+		archive_read_support_compression_all(a);
 	archive_read_support_format_all(a);
 	if (archive_read_open_file(a, bsdtar->filename,
 	    bsdtar->bytes_per_block != 0 ? bsdtar->bytes_per_block :
@@ -103,19 +128,17 @@
 		r = archive_read_next_header(a, &entry);
 		if (r == ARCHIVE_EOF)
 			break;
-		if (r == ARCHIVE_WARN)
+		if (r < ARCHIVE_OK)
 			bsdtar_warnc(bsdtar, 0, "%s", archive_error_string(a));
-		if (r == ARCHIVE_FATAL) {
+		if (r <= ARCHIVE_WARN)
 			bsdtar->return_value = 1;
-			bsdtar_warnc(bsdtar, 0, "%s", archive_error_string(a));
-			break;
-		}
 		if (r == ARCHIVE_RETRY) {
 			/* Retryable error: try again */
-			bsdtar_warnc(bsdtar, 0, "%s", archive_error_string(a));
 			bsdtar_warnc(bsdtar, 0, "Retrying...");
 			continue;
 		}
+		if (r == ARCHIVE_FATAL)
+			break;
 
 		/*
 		 * Exclude entries that are too old.
@@ -187,19 +210,11 @@
 				fprintf(out, "\n");
 				bsdtar_warnc(bsdtar, 0, "%s",
 				    archive_error_string(a));
+				bsdtar->return_value = 1;
 				break;
 			}
 			fprintf(out, "\n");
 		} else {
-			/*
-			 * Skip security problems before prompting.
-			 * Otherwise, the user may be confused that a
-			 * file they wanted to extract was
-			 * subsequently skipped.
-			 */
-			if (security_problem(bsdtar, entry))
-				continue;
-
 			if (bsdtar->option_interactive &&
 			    !yes("extract '%s'", archive_entry_pathname(entry)))
 				continue;
@@ -213,11 +228,12 @@
 				    archive_entry_pathname(entry));
 				fflush(stderr);
 			}
-			if (bsdtar->option_stdout) {
-				/* TODO: Catch/recover any errors here. */
-				archive_read_data_into_fd(a, 1);
-			} else if (archive_read_extract(a, entry,
-				       bsdtar->extract_flags)) {
+			if (bsdtar->option_stdout)
+				r = archive_read_data_into_fd(a, 1);
+			else
+				r = archive_read_extract(a, entry,
+				    bsdtar->extract_flags);
+			if (r != ARCHIVE_OK) {
 				if (!bsdtar->verbose)
 					safe_fprintf(stderr, "%s",
 					    archive_entry_pathname(entry));
@@ -225,14 +241,12 @@
 				    archive_error_string(a));
 				if (!bsdtar->verbose)
 					fprintf(stderr, "\n");
-				/*
-				 * TODO: Decide how to handle
-				 * extraction error... <sigh>
-				 */
 				bsdtar->return_value = 1;
 			}
 			if (bsdtar->verbose)
 				fprintf(stderr, "\n");
+			if (r == ARCHIVE_FATAL)
+				break;
 		}
 	}
 
@@ -241,7 +255,6 @@
 		    archive_format_name(a), archive_compression_name(a));
 
 	archive_read_finish(a);
-	cleanup_security(bsdtar);
 }
 
 
@@ -285,7 +298,7 @@
 	/* Use uname if it's present, else uid. */
 	p = archive_entry_uname(entry);
 	if ((p == NULL) || (*p == '\0')) {
-		sprintf(tmp, "%d ", st->st_uid);
+		sprintf(tmp, "%lu ", (unsigned long)st->st_uid);
 		p = tmp;
 	}
 	w = strlen(p);
@@ -299,7 +312,7 @@
 		fprintf(out, "%s", p);
 		w = strlen(p);
 	} else {
-		sprintf(tmp, "%d", st->st_gid);
+		sprintf(tmp, "%lu", (unsigned long)st->st_gid);
 		w = strlen(tmp);
 		fprintf(out, "%s", tmp);
 	}
@@ -310,9 +323,9 @@
 	 * If gs_width is too small, grow it.
 	 */
 	if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) {
-		sprintf(tmp, "%d,%u",
-		    major(st->st_rdev),
-		    (unsigned)minor(st->st_rdev)); /* ls(1) also casts here. */
+		sprintf(tmp, "%lu,%lu",
+		    (unsigned long)major(st->st_rdev),
+		    (unsigned long)minor(st->st_rdev)); /* ls(1) also casts here. */
 	} else {
 		/*
 		 * Note the use of platform-dependent macros to format
@@ -343,128 +356,3 @@
 	else if (S_ISLNK(st->st_mode)) /* Symbolic link */
 		safe_fprintf(out, " -> %s", archive_entry_symlink(entry));
 }
-
-/*
- * Structure for storing path of last successful security check.
- */
-struct security {
-	char	*path;
-	size_t	 path_size;
-};
-
-/*
- * Check for a variety of security issues.  Fix what we can here,
- * generate warnings as appropriate, return non-zero to prevent
- * this entry from being extracted.
- */
-static int
-security_problem(struct bsdtar *bsdtar, struct archive_entry *entry)
-{
-	struct stat st;
-	const char *name, *pn;
-	char *p;
-	int r;
-
-	/* -P option forces us to just accept all pathnames as-is. */
-	if (bsdtar->option_absolute_paths)
-		return (0);
-
-	name = archive_entry_pathname(entry);
-
-	/* Reject any archive entry with '..' as a path element. */
-	pn = name;
-	while (pn != NULL && pn[0] != '\0') {
-		if (pn[0] == '.' && pn[1] == '.' &&
-		    (pn[2] == '\0' || pn[2] == '/')) {
-			bsdtar_warnc(bsdtar, 0,
-			    "Skipping pathname containing ..");
-			bsdtar->return_value = 1;
-			return (1);
-		}
-		pn = strchr(pn, '/');
-		if (pn != NULL)
-			pn++;
-	}
-
-	/*
-	 * Gaurd against symlink tricks.  Reject any archive entry whose
-	 * destination would be altered by a symlink.
-	 */
-	/* XXX TODO: Make this faster by comparing current path to
-	 * prefix of last successful check to avoid duplicate lstat()
-	 * calls. XXX */
-	pn = name;
-	if (bsdtar->security == NULL) {
-		bsdtar->security = malloc(sizeof(*bsdtar->security));
-		if (bsdtar->security == NULL)
-			bsdtar_errc(bsdtar, 1, errno, "No Memory");
-		bsdtar->security->path_size = MAXPATHLEN + 1;
-		bsdtar->security->path = malloc(bsdtar->security->path_size);
-		if (bsdtar->security->path == NULL)
-			bsdtar_errc(bsdtar, 1, errno, "No Memory");
-	}
-	if (strlen(name) >= bsdtar->security->path_size) {
-		free(bsdtar->security->path);
-		while (strlen(name) >= bsdtar->security->path_size)
-			bsdtar->security->path_size *= 2;
-		bsdtar->security->path = malloc(bsdtar->security->path_size);
-		if (bsdtar->security->path == NULL)
-			bsdtar_errc(bsdtar, 1, errno, "No Memory");
-	}
-	p = bsdtar->security->path;
-	while (pn != NULL && pn[0] != '\0') {
-		*p++ = *pn++;
-		while (*pn != '\0' && *pn != '/')
-			*p++ = *pn++;
-		p[0] = '\0';
-		r = lstat(bsdtar->security->path, &st);
-		if (r != 0) {
-			if (errno == ENOENT)
-				break;
-		} else if (S_ISLNK(st.st_mode)) {
-			if (pn[0] == '\0') {
-				/*
-				 * Last element is symlink; remove it
-				 * so we can overwrite it with the
-				 * item being extracted.
-				 */
-				if (!S_ISLNK(archive_entry_mode(entry))) {
-					/*
-					 * Warn only if the symlink is being
-					 * replaced with a non-symlink.
-					 */
-					bsdtar_warnc(bsdtar, 0,
-					    "Removing symlink %s",
-					    bsdtar->security->path);
-				}
-				if (unlink(bsdtar->security->path))
-					bsdtar_errc(bsdtar, 1, errno,
-					    "Unlink failed");
-				/* Symlink gone.  No more problem! */
-				return (0);
-			} else if (bsdtar->option_unlink_first) {
-				/* User asked us to remove problems. */
-				if (unlink(bsdtar->security->path))
-					bsdtar_errc(bsdtar, 1, errno,
-					    "Unlink failed");
-			} else {
-				bsdtar_warnc(bsdtar, 0,
-				    "Cannot extract %s through symlink %s",
-				    name, bsdtar->security->path);
-				bsdtar->return_value = 1;
-				return (1);
-			}
-		}
-	}
-
-	return (0);
-}
-
-static void
-cleanup_security(struct bsdtar *bsdtar)
-{
-	if (bsdtar->security != NULL) {
-		free(bsdtar->security->path);
-		free(bsdtar->security);
-	}
-}
Index: bsdtar_platform.h
===================================================================
RCS file: /home/cvs/src/usr.bin/tar/bsdtar_platform.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -Lusr.bin/tar/bsdtar_platform.h -Lusr.bin/tar/bsdtar_platform.h -u -r1.2 -r1.3
--- usr.bin/tar/bsdtar_platform.h
+++ usr.bin/tar/bsdtar_platform.h
@@ -22,8 +22,8 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
+ * $FreeBSD: src/usr.bin/tar/bsdtar_platform.h,v 1.24 2007/04/12 04:45:32 kientzle Exp $
  * $MidnightBSD$
- * $FreeBSD: src/usr.bin/tar/bsdtar_platform.h,v 1.15.2.4 2007/03/11 19:46:56 kientzle Exp $
  */
 
 /*
@@ -35,75 +35,15 @@
 #ifndef BSDTAR_PLATFORM_H_INCLUDED
 #define	BSDTAR_PLATFORM_H_INCLUDED
 
-#if HAVE_CONFIG_H
+#if defined(PLATFORM_CONFIG_H)
+/* Use hand-built config.h in environments that need it. */
+#include PLATFORM_CONFIG_H
+#elif defined(HAVE_CONFIG_H)
+/* Most POSIX platforms use the 'configure' script to build config.h */
 #include "../config.h"
 #else
-
-#ifdef __FreeBSD__
-#include <sys/param.h>  /* __FreeBSD_version */
-/* A default configuration for FreeBSD, used if there is no config.h. */
-#define	PACKAGE_NAME "bsdtar"
-
-#if __FreeBSD__ > 4
-#define	HAVE_ACL_GET_PERM 0
-#define	HAVE_ACL_GET_PERM_NP 1
-#define	HAVE_ACL_PERMSET_T 1
-#define	HAVE_ACL_USER 1
-#endif
-#define	HAVE_BZLIB_H 1
-#define	HAVE_CHFLAGS 1
-#define	HAVE_DIRENT_D_NAMLEN 1
-#define	HAVE_DIRENT_H 1
-#define	HAVE_D_MD_ORDER 1
-#define	HAVE_FCHDIR 1
-#define	HAVE_FCNTL_H 1
-#define	HAVE_FNMATCH 1
-#define	HAVE_FNM_LEADING_DIR 1
-#define	HAVE_FTRUNCATE 1
-#define	HAVE_GETOPT_LONG 1
-#define	HAVE_INTTYPES_H 1
-#define	HAVE_LANGINFO_H 1
-#define	HAVE_LIBARCHIVE 1
-#define	HAVE_LIBBZ2 1
-#define	HAVE_LIBZ 1
-#define	HAVE_LIMITS_H 1
-#define	HAVE_LOCALE_H 1
-#define	HAVE_MALLOC 1
-#define	HAVE_MEMMOVE 1
-#define	HAVE_MEMORY_H 1
-#define	HAVE_MEMSET 1
-#if __FreeBSD_version >= 450002 /* nl_langinfo introduced */
-#define	HAVE_NL_LANGINFO 1
-#endif
-#define	HAVE_PATHS_H 1
-#define	HAVE_SETLOCALE 1
-#define	HAVE_STDINT_H 1
-#define	HAVE_STDLIB_H 1
-#define	HAVE_STRCHR 1
-#define	HAVE_STRDUP 1
-#define	HAVE_STRERROR 1
-#define	HAVE_STRFTIME 1
-#define	HAVE_STRINGS_H 1
-#define	HAVE_STRING_H 1
-#define	HAVE_STRRCHR 1
-#define	HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 1
-#define	HAVE_STRUCT_STAT_ST_RDEV 1
-#define	HAVE_SYS_ACL_H 1
-#define	HAVE_SYS_IOCTL_H 1
-#define	HAVE_SYS_PARAM_H 1
-#define	HAVE_SYS_STAT_H 1
-#define	HAVE_SYS_TYPES_H 1
-#define	HAVE_UINTMAX_T 1
-#define	HAVE_UNISTD_H 1
-#define	HAVE_VPRINTF 1
-#define	HAVE_ZLIB_H 1
-#define	STDC_HEADERS 1
-
-#else /* !__FreeBSD__ */
 /* Warn if bsdtar hasn't been (automatically or manually) configured. */
 #error Oops: No config.h and no built-in configuration in bsdtar_platform.h.
-#endif /* !__FreeBSD__ */
-
 #endif /* !HAVE_CONFIG_H */
 
 /* No non-FreeBSD platform will have __FBSDID, so just define it here. */
@@ -139,10 +79,10 @@
 #endif
 
 #if HAVE_ACL_GET_PERM
-#define ACL_GET_PERM acl_get_perm
+#define	ACL_GET_PERM acl_get_perm
 #else
 #if HAVE_ACL_GET_PERM_NP
-#define ACL_GET_PERM acl_get_perm_np
+#define	ACL_GET_PERM acl_get_perm_np
 #endif
 #endif
 


More information about the Midnightbsd-cvs mailing list