PERFORCE change 153792 for review

Sam Leffler sam at FreeBSD.org
Sat Nov 29 12:44:23 PST 2008


http://perforce.freebsd.org/chv.cgi?CH=153792

Change 153792 by sam at sam_ebb on 2008/11/29 20:44:11

	IFC @ 153791

Affected files ...

.. //depot/projects/vap/share/man/man4/man4.arm/Makefile#4 integrate
.. //depot/projects/vap/share/man/man4/upgt.4#3 integrate
.. //depot/projects/vap/sys/dev/fb/s3_pci.c#6 integrate
.. //depot/projects/vap/sys/dev/hwpmc/hwpmc_intel.c#3 branch
.. //depot/projects/vap/usr.bin/cpio/cpio.c#8 integrate
.. //depot/projects/vap/usr.bin/cpio/cpio.h#5 integrate
.. //depot/projects/vap/usr.bin/cpio/test/test_option_tv.stdout.uu#2 integrate
.. //depot/projects/vap/usr.bin/tar/config_freebsd.h#9 integrate
.. //depot/projects/vap/usr.bin/tar/util.c#7 integrate

Differences ...

==== //depot/projects/vap/share/man/man4/man4.arm/Makefile#4 (text+ko) ====

@@ -1,7 +1,10 @@
-# $FreeBSD: src/share/man/man4/man4.arm/Makefile,v 1.2 2008/11/27 16:50:23 raj Exp $
+# $FreeBSD: src/share/man/man4/man4.arm/Makefile,v 1.3 2008/11/29 19:01:44 brueffer Exp $
 
 MAN=	mge.4 npe.4
 
+MLINKS= mge.4 if_mge.4
+MLINKS+=npe.4 if_npe.4
+
 MANSUBDIR=/arm
 
 .include <bsd.prog.mk>

==== //depot/projects/vap/share/man/man4/upgt.4#3 (text+ko) ====

@@ -1,5 +1,5 @@
 .\" $OpenBSD: upgt.4,v 1.6 2008/04/17 14:01:22 jmc Exp $
-.\" $FreeBSD$
+.\" $FreeBSD: src/share/man/man4/upgt.4,v 1.2 2008/11/29 18:58:20 brueffer Exp $
 .\"
 .\" Copyright (c) 2007 Marcus Glocker <mglocker at openbsd.org>
 .\" Copyright (c) 2005-2007
@@ -49,7 +49,7 @@
 .\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd $Mdocdate: April 17 2008 $
+.Dd April 17, 2008
 .Os
 .Dt UPGT 4
 .Sh NAME
@@ -140,29 +140,43 @@
 .\"users have to download these files on their own.
 This driver requires the
 .Nm upgtfw
-be installed before it will work.
+firmware be installed before it will work.
 The firmware files are not publicly available.
 A package of the firmware which can be installed via
 .Xr pkg_add 1
-with:
+is available:
 .Bd -literal -offset indent
 http://weongyo.org/project/upgt/upgt-firmware-2.13.1.0.tar.gz
 .Ed
 .Sh HARDWARE
-The following adapters should work:
+The
+.Nm
+driver supports USB 2.0 Conexant/Intersil PrismGT series wireless
+adapters based on the GW3887 chipset, among them:
 .Pp
-.Bl -tag -width Ds -offset indent -compact
-.It Belkin F5D7050 (version 1000)
-.It Cohiba Proto Board
-.It D-Link DWL-G120 Cohiba
-.It FSC Connect2Air E-5400 USB D1700
-.It Gigaset USB Adapter 54
-.It Inventel UR045G
-.It Netgear WG111v2
-.It SMC EZ ConnectG SMC2862W-G
-.It Sagem XG703A
-.It Spinnaker DUT
-.It Spinnaker Proto Board
+.Bl -bullet -compact
+.It
+Belkin F5D7050 (version 1000)
+.It
+Cohiba Proto Board
+.It
+D-Link DWL-G120 Cohiba
+.It
+FSC Connect2Air E-5400 USB D1700
+.It
+Gigaset USB Adapter 54
+.It
+Inventel UR045G
+.It
+Netgear WG111v2
+.It
+SMC EZ ConnectG SMC2862W-G
+.It
+Sagem XG703A
+.It
+Spinnaker DUT
+.It
+Spinnaker Proto Board
 .El
 .Sh EXAMPLES
 Join an existing BSS network (i.e., connect to an access point):

==== //depot/projects/vap/sys/dev/fb/s3_pci.c#6 (text+ko) ====

@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/dev/fb/s3_pci.c,v 1.10 2005/09/28 14:54:06 marius Exp $");
+__FBSDID("$FreeBSD: src/sys/dev/fb/s3_pci.c,v 1.11 2008/11/29 20:16:53 kib Exp $");
 
 /* Enable LFB on S3 cards that has only VESA 1.2 BIOS */
 
@@ -389,7 +389,7 @@
 }
 
 static int
-s3lfb_mmap(video_adapter_t *adp, vm_offset_t offset, vm_offset_t *paddr,
+s3lfb_mmap(video_adapter_t *adp, vm_offset_t offset, vm_paddr_t *paddr,
 	  int prot)
 {
 	return (*prevvidsw->mmap)(adp, offset, paddr, prot);

==== //depot/projects/vap/usr.bin/cpio/cpio.c#8 (text+ko) ====

@@ -26,7 +26,7 @@
 
 
 #include "cpio_platform.h"
-__FBSDID("$FreeBSD: src/usr.bin/cpio/cpio.c,v 1.13 2008/09/04 05:20:46 kientzle Exp $");
+__FBSDID("$FreeBSD: src/usr.bin/cpio/cpio.c,v 1.14 2008/11/29 20:22:02 kientzle Exp $");
 
 #include <sys/types.h>
 #include <archive.h>
@@ -41,6 +41,12 @@
 #ifdef HAVE_FCNTL_H
 #include <fcntl.h>
 #endif
+#ifdef HAVE_GRP_H
+#include <grp.h>
+#endif
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
 #ifdef HAVE_STDARG_H
 #include <stdarg.h>
 #endif
@@ -58,11 +64,32 @@
 #include "cpio.h"
 #include "matching.h"
 
+/* Fixed size of uname/gname caches. */
+#define	name_cache_size 101
+
+struct name_cache {
+	int	probes;
+	int	hits;
+	size_t	size;
+	struct {
+		id_t id;
+		char *name;
+	} cache[name_cache_size];
+};
+
 static int	copy_data(struct archive *, struct archive *);
 static const char *cpio_rename(const char *name);
 static int	entry_to_archive(struct cpio *, struct archive_entry *);
 static int	file_to_archive(struct cpio *, const char *);
+static void	free_cache(struct name_cache *cache);
+static void	list_item_verbose(struct cpio *, struct archive_entry *);
 static void	long_help(void);
+static const char *lookup_gname(struct cpio *, gid_t gid);
+static int	lookup_gname_helper(struct cpio *,
+		    const char **name, id_t gid);
+static const char *lookup_uname(struct cpio *, uid_t uid);
+static int	lookup_uname_helper(struct cpio *,
+		    const char **name, id_t uid);
 static void	mode_in(struct cpio *);
 static void	mode_list(struct cpio *);
 static void	mode_out(struct cpio *);
@@ -271,6 +298,8 @@
 		    "Must specify at least one of -i, -o, or -p");
 	}
 
+	free_cache(cpio->gname_cache);
+	free_cache(cpio->uname_cache);
 	return (0);
 }
 
@@ -805,18 +834,9 @@
 		}
 		if (excluded(cpio, archive_entry_pathname(entry)))
 			continue;
-		if (cpio->verbose) {
-			/* TODO: uname/gname lookups */
-			/* TODO: Clean this up. */
-			fprintf(stdout,
-			    "%s%3d %8s%8s " CPIO_FILESIZE_PRINTF " %s\n",
-			    archive_entry_strmode(entry),
-			    archive_entry_nlink(entry),
-			    archive_entry_uname(entry),
-			    archive_entry_gname(entry),
-			    (CPIO_FILESIZE_TYPE)archive_entry_size(entry),
-			    archive_entry_pathname(entry));
-		} else
+		if (cpio->verbose)
+			list_item_verbose(cpio, entry);
+		else
 			fprintf(stdout, "%s\n", archive_entry_pathname(entry));
 	}
 	r = archive_read_close(a);
@@ -832,7 +852,74 @@
 	exit(0);
 }
 
+/*
+ * Display information about the current file.
+ *
+ * The format here roughly duplicates the output of 'ls -l'.
+ * This is based on SUSv2, where 'tar tv' is documented as
+ * listing additional information in an "unspecified format,"
+ * and 'pax -l' is documented as using the same format as 'ls -l'.
+ */
 static void
+list_item_verbose(struct cpio *cpio, struct archive_entry *entry)
+{
+	char			 size[32];
+	char			 date[32];
+	const char 		*uname, *gname;
+	FILE			*out = stdout;
+	const struct stat	*st;
+	const char		*fmt;
+	time_t			 tim;
+	static time_t		 now;
+
+	st = archive_entry_stat(entry);
+
+	if (!now)
+		time(&now);
+
+	/* Use uname if it's present, else uid. */
+	uname = archive_entry_uname(entry);
+	if (uname == NULL)
+		uname = lookup_uname(cpio, archive_entry_uid(entry));
+
+	/* Use gname if it's present, else gid. */
+	gname = archive_entry_gname(entry);
+	if (gname == NULL)
+		gname = lookup_gname(cpio, archive_entry_gid(entry));
+
+	/* Print device number or file size. */
+	if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) {
+		snprintf(size, sizeof(size), "%lu,%lu",
+		    (unsigned long)major(st->st_rdev),
+		    (unsigned long)minor(st->st_rdev)); /* ls(1) also casts here. */
+	} else {
+		snprintf(size, sizeof(size), CPIO_FILESIZE_PRINTF,
+		    (CPIO_FILESIZE_TYPE)st->st_size);
+	}
+
+	/* Format the time using 'ls -l' conventions. */
+	tim = (time_t)st->st_mtime;
+	if (abs(tim - now) > (365/2)*86400)
+		fmt = cpio->day_first ? "%e %b  %Y" : "%b %e  %Y";
+	else
+		fmt = cpio->day_first ? "%e %b %H:%M" : "%b %e %H:%M";
+	strftime(date, sizeof(date), fmt, localtime(&tim));
+
+	fprintf(out, "%s%3d %-8s %-8s %8s %12s %s",
+	    archive_entry_strmode(entry),
+	    archive_entry_nlink(entry),
+	    uname, gname, size, date,
+	    archive_entry_pathname(entry));
+
+	/* Extra information for links. */
+	if (archive_entry_hardlink(entry)) /* Hard link */
+		fprintf(out, " link to %s", archive_entry_hardlink(entry));
+	else if (archive_entry_symlink(entry)) /* Symbolic link */
+		fprintf(out, " -> %s", archive_entry_symlink(entry));
+	fprintf(out, "\n");
+}
+
+static void
 mode_pass(struct cpio *cpio, const char *destdir)
 {
 	unsigned long blocks;
@@ -1040,3 +1127,123 @@
 	free(lr->pathname);
 	free(lr);
 }
+
+static void
+free_cache(struct name_cache *cache)
+{
+	size_t i;
+
+	if (cache != NULL) {
+		for (i = 0; i < cache->size; i++)
+			free(cache->cache[i].name);
+		free(cache);
+	}
+}
+
+/*
+ * Lookup uname/gname from uid/gid, return NULL if no match.
+ */
+static const char *
+lookup_name(struct cpio *cpio, struct name_cache **name_cache_variable,
+    int (*lookup_fn)(struct cpio *, const char **, id_t), id_t id)
+{
+	char asnum[16];
+	struct name_cache	*cache;
+	const char *name;
+	int slot;
+
+
+	if (*name_cache_variable == NULL) {
+		*name_cache_variable = malloc(sizeof(struct name_cache));
+		if (*name_cache_variable == NULL)
+			cpio_errc(1, ENOMEM, "No more memory");
+		memset(*name_cache_variable, 0, sizeof(struct name_cache));
+		(*name_cache_variable)->size = name_cache_size;
+	}
+
+	cache = *name_cache_variable;
+	cache->probes++;
+
+	slot = id % cache->size;
+	if (cache->cache[slot].name != NULL) {
+		if (cache->cache[slot].id == id) {
+			cache->hits++;
+			return (cache->cache[slot].name);
+		}
+		free(cache->cache[slot].name);
+		cache->cache[slot].name = NULL;
+	}
+
+	if (lookup_fn(cpio, &name, id) == 0) {
+		if (name == NULL || name[0] == '\0') {
+			/* If lookup failed, format it as a number. */
+			snprintf(asnum, sizeof(asnum), "%u", (unsigned)id);
+			name = asnum;
+		}
+		cache->cache[slot].name = strdup(name);
+		if (cache->cache[slot].name != NULL) {
+			cache->cache[slot].id = id;
+			return (cache->cache[slot].name);
+		}
+		/*
+		 * Conveniently, NULL marks an empty slot, so
+		 * if the strdup() fails, we've just failed to
+		 * cache it.  No recovery necessary.
+		 */
+	}
+	return (NULL);
+}
+
+static const char *
+lookup_uname(struct cpio *cpio, uid_t uid)
+{
+	return (lookup_name(cpio, &cpio->uname_cache,
+		    &lookup_uname_helper, (id_t)uid));
+}
+
+static int
+lookup_uname_helper(struct cpio *cpio, const char **name, id_t id)
+{
+	struct passwd	*pwent;
+
+	(void)cpio; /* UNUSED */
+
+	errno = 0;
+	pwent = getpwuid((uid_t)id);
+	if (pwent == NULL) {
+		*name = NULL;
+		if (errno != 0)
+			cpio_warnc(errno, "getpwuid(%d) failed", id);
+		return (errno);
+	}
+
+	*name = pwent->pw_name;
+	return (0);
+}
+
+static const char *
+lookup_gname(struct cpio *cpio, gid_t gid)
+{
+	return (lookup_name(cpio, &cpio->gname_cache,
+		    &lookup_gname_helper, (id_t)gid));
+}
+
+static int
+lookup_gname_helper(struct cpio *cpio, const char **name, id_t id)
+{
+	struct group	*grent;
+
+	(void)cpio; /* UNUSED */
+
+	errno = 0;
+	grent = getgrgid((gid_t)id);
+	if (grent == NULL) {
+		*name = NULL;
+		if (errno != 0)
+			cpio_warnc(errno, "getgrgid(%d) failed", id);
+		return (errno);
+	}
+
+	*name = grent->gr_name;
+	return (0);
+}

==== //depot/projects/vap/usr.bin/cpio/cpio.h#5 (text+ko) ====

@@ -22,7 +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.
  *
- * $FreeBSD: src/usr.bin/cpio/cpio.h,v 1.4 2008/08/04 01:25:48 cperciva Exp $
+ * $FreeBSD: src/usr.bin/cpio/cpio.h,v 1.5 2008/11/29 20:22:02 kientzle Exp $
  */
 
 #ifndef CPIO_H_INCLUDED
@@ -65,6 +65,7 @@
 	char		 *pass_destpath;
 	int		  uid_override;
 	int		  gid_override;
+	int		  day_first; /* true if locale prefers day/mon */
 
 	/* If >= 0, then close this when done. */
 	int		  fd;
@@ -76,6 +77,9 @@
 	int		  return_value; /* Value returned by main() */
 	struct archive_entry_linkresolver *linkresolver;
 
+	struct name_cache *uname_cache;
+	struct name_cache *gname_cache;
+
 	/* Work data. */
 	struct matching  *matching;
 	char		 *buff;

==== //depot/projects/vap/usr.bin/cpio/test/test_option_tv.stdout.uu#2 (text+ko) ====

@@ -1,5 +1,6 @@
-$FreeBSD: src/usr.bin/cpio/test/test_option_tv.stdout.uu,v 1.1 2008/05/26 17:15:35 kientzle Exp $
+$FreeBSD: src/usr.bin/cpio/test/test_option_tv.stdout.uu,v 1.2 2008/11/29 20:22:02 kientzle Exp $
 begin 644 test_option_tv.stdout
-G+7)W+7(M+7(M+2`@(#$@("`H;G5L;"D@("AN=6QL*2`P(&9I;&4*
+M+7)W+7(M+7(M+2`@(#$@=&EM("`@("`@=&EM("`@("`@("`@("`@(#`@1&5C
+/(#,Q("`Q.38Y(&9I;&4*
 `
 end

==== //depot/projects/vap/usr.bin/tar/config_freebsd.h#9 (text+ko) ====

@@ -22,7 +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.
  *
- * $FreeBSD: src/usr.bin/tar/config_freebsd.h,v 1.7 2008/11/08 04:43:24 kientzle Exp $
+ * $FreeBSD: src/usr.bin/tar/config_freebsd.h,v 1.8 2008/11/29 20:06:53 kientzle Exp $
  */
 
 /* A default configuration for FreeBSD, used if there is no config.h. */
@@ -101,6 +101,7 @@
 #define	HAVE_UNISTD_H 1
 #define	HAVE_UNSIGNED_LONG_LONG
 #define	HAVE_VPRINTF 1
+#define	HAVE_WCTYPE_H 1
 #define	HAVE_ZLIB_H 1
 #undef	MAJOR_IN_MKDEV
 #define	STDC_HEADERS 1

==== //depot/projects/vap/usr.bin/tar/util.c#7 (text+ko) ====

@@ -24,7 +24,7 @@
  */
 
 #include "bsdtar_platform.h"
-__FBSDID("$FreeBSD: src/usr.bin/tar/util.c,v 1.21 2008/11/10 05:04:55 kientzle Exp $");
+__FBSDID("$FreeBSD: src/usr.bin/tar/util.c,v 1.22 2008/11/29 20:06:53 kientzle Exp $");
 
 #ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
@@ -46,92 +46,161 @@
 #ifdef HAVE_STRING_H
 #include <string.h>
 #endif
+#ifdef HAVE_WCTYPE_H
+#include <wctype.h>
+#else
+/* If we don't have wctype, we need to hack up some version of iswprint(). */
+#define iswprint isprint
+#endif
 
 #include "bsdtar.h"
 
 static void	bsdtar_vwarnc(struct bsdtar *, int code,
 		    const char *fmt, va_list ap);
+static size_t	bsdtar_expand_char(char *, size_t, char);
 static const char *strip_components(const char *path, int elements);
 
+/* TODO:  Hack up a version of mbtowc for platforms with no wide
+ * character support at all.  I think the following might suffice,
+ * but it needs careful testing.
+ * #if !HAVE_MBTOWC
+ * #define mbtowc(wcp, p, n) ((*wcp = *p), 1)
+ * #endif
+ */
+
 /*
  * Print a string, taking care with any non-printable characters.
+ *
+ * Note that we use a stack-allocated buffer to receive the formatted
+ * string if we can.  This is partly performance (avoiding a call to
+ * malloc()), partly out of expedience (we have to call vsnprintf()
+ * before malloc() anyway to find out how big a buffer we need; we may
+ * as well point that first call at a small local buffer in case it
+ * works), but mostly for safety (so we can use this to print messages
+ * about out-of-memory conditions).
  */
 
 void
 safe_fprintf(FILE *f, const char *fmt, ...)
 {
-	char *buff;
-	char *buff_heap;
-	int buff_length;
+	char fmtbuff_stack[256]; /* Place to format the printf() string. */
+	char outbuff[256]; /* Buffer for outgoing characters. */
+	char *fmtbuff_heap; /* If fmtbuff_stack is too small, we use malloc */
+	char *fmtbuff;  /* Pointer to fmtbuff_stack or fmtbuff_heap. */
+	int fmtbuff_length;
 	int length;
 	va_list ap;
-	char *p;
+	const char *p;
 	unsigned i;
-	char buff_stack[256];
-	char copy_buff[256];
+	wchar_t wc;
+	char try_wc;
 
 	/* Use a stack-allocated buffer if we can, for speed and safety. */
-	buff_heap = NULL;
-	buff_length = sizeof(buff_stack);
-	buff = buff_stack;
+	fmtbuff_heap = NULL;
+	fmtbuff_length = sizeof(fmtbuff_stack);
+	fmtbuff = fmtbuff_stack;
 
+	/* Try formatting into the stack buffer. */
 	va_start(ap, fmt);
-	length = vsnprintf(buff, buff_length, fmt, ap);
+	length = vsnprintf(fmtbuff, fmtbuff_length, fmt, ap);
 	va_end(ap);
-	/* If the result is too large, allocate a buffer on the heap. */
-	if (length >= buff_length) {
-		buff_length = length+1;
-		buff_heap = malloc(buff_length);
-		/* Failsafe: use the truncated string if malloc fails. */
-		if (buff_heap != NULL) {
-			buff = buff_heap;
+
+	/* If the result was too large, allocate a buffer on the heap. */
+	if (length >= fmtbuff_length) {
+		fmtbuff_length = length+1;
+		fmtbuff_heap = malloc(fmtbuff_length);
+
+		/* Reformat the result into the heap buffer if we can. */
+		if (fmtbuff_heap != NULL) {
+			fmtbuff = fmtbuff_heap;
 			va_start(ap, fmt);
-			length = vsnprintf(buff, buff_length, fmt, ap);
+			length = vsnprintf(fmtbuff, fmtbuff_length, fmt, ap);
 			va_end(ap);
+		} else {
+			/* Leave fmtbuff pointing to the truncated
+			 * string in fmtbuff_stack. */
+			length = sizeof(fmtbuff_stack) - 1;
 		}
 	}
 
+	/* Note: mbrtowc() has a cleaner API, but mbtowc() seems a bit
+	 * more portable, so we use that here instead. */
+	mbtowc(NULL, NULL, 0); /* Reset the shift state. */
+
 	/* Write data, expanding unprintable characters. */
-	p = buff;
+	p = fmtbuff;
 	i = 0;
+	try_wc = 1;
 	while (*p != '\0') {
-		unsigned char c = *p++;
+		int n;
 
-		if (isprint(c) && c != '\\')
-			copy_buff[i++] = c;
-		else {
-			copy_buff[i++] = '\\';
-			switch (c) {
-			case '\a': copy_buff[i++] = 'a'; break;
-			case '\b': copy_buff[i++] = 'b'; break;
-			case '\f': copy_buff[i++] = 'f'; break;
-			case '\n': copy_buff[i++] = 'n'; break;
-#if '\r' != '\n'
-			/* On some platforms, \n and \r are the same. */
-			case '\r': copy_buff[i++] = 'r'; break;
-#endif
-			case '\t': copy_buff[i++] = 't'; break;
-			case '\v': copy_buff[i++] = 'v'; break;
-			case '\\': copy_buff[i++] = '\\'; break;
-			default:
-				sprintf(copy_buff + i, "%03o", c);
-				i += 3;
+		/* Convert to wide char, test if the wide
+		 * char is printable in the current locale. */
+		if (try_wc && (n = mbtowc(&wc, p, length)) != -1) {
+			length -= n;
+			if (iswprint(wc) && wc != L'\\') {
+				/* Printable, copy the bytes through. */
+				while (n-- > 0)
+					outbuff[i++] = *p++;
+			} else {
+				/* Not printable, format the bytes. */
+				while (n-- > 0)
+					i += bsdtar_expand_char(
+					    outbuff, i, *p++);
 			}
+		} else {
+			/* After any conversion failure, don't bother
+			 * trying to convert the rest. */
+			i += bsdtar_expand_char(outbuff, i, *p++);
+			try_wc = 0;
 		}
 
-		/* If our temp buffer is full, dump it and keep going. */
-		if (i > (sizeof(copy_buff) - 8)) {
-			copy_buff[i++] = '\0';
-			fprintf(f, "%s", copy_buff);
+		/* If our output buffer is full, dump it and keep going. */
+		if (i > (sizeof(outbuff) - 20)) {
+			outbuff[i++] = '\0';
+			fprintf(f, "%s", outbuff);
 			i = 0;
 		}
 	}
-	copy_buff[i++] = '\0';
-	fprintf(f, "%s", copy_buff);
+	outbuff[i++] = '\0';
+	fprintf(f, "%s", outbuff);
+
+	/* If we allocated a heap-based formatting buffer, free it now. */
+	if (fmtbuff_heap != NULL)
+		free(fmtbuff_heap);
+}
+
+/*
+ * Render an arbitrary sequence of bytes into printable ASCII characters.
+ */
+static size_t
+bsdtar_expand_char(char *buff, size_t offset, char c)
+{
+	size_t i = offset;
+
+	if (isprint(c) && c != '\\')
+		buff[i++] = c;
+	else {
+		buff[i++] = '\\';
+		switch (c) {
+		case '\a': buff[i++] = 'a'; break;
+		case '\b': buff[i++] = 'b'; break;
+		case '\f': buff[i++] = 'f'; break;
+		case '\n': buff[i++] = 'n'; break;
+#if '\r' != '\n'
+		/* On some platforms, \n and \r are the same. */
+		case '\r': buff[i++] = 'r'; break;
+#endif
+		case '\t': buff[i++] = 't'; break;
+		case '\v': buff[i++] = 'v'; break;
+		case '\\': buff[i++] = '\\'; break;
+		default:
+			sprintf(buff + i, "%03o", 0xFF & (int)c);
+			i += 3;
+		}
+	}
 
-	/* If we allocated a heap-based buffer, free it now. */
-	if (buff_heap != NULL)
-		free(buff_heap);
+	return (i - offset);
 }
 
 static void


More information about the p4-projects mailing list