Merge code from upstream libtar + bug fixes

All updates and fixes applied from upstream libtar as of
March 1, 2016.

Debug flag is disabled, however non-debug output now
provides 1 line of useful output per object extracted.

I've also merged some fixes from CyanogenMod's
fork of libtar:

From: Tom Marshall <tdm@cyngn.com>
Date: Thu, 11 Feb 2016 16:24:40 -0800
Subject: libtar: Cleanup, secure, and extend numeric fields
Commit: e18b457ea1cbf6be1adc3b75450ed1c737cd82ea

From: Tom Marshall <tdm@cyngn.com>
Date: Thu, 11 Feb 2016 12:49:30 -0800
Subject: libtar: Make file sizes 64-bit clean
Commit: e628c2025549a24018bc568351465130a05daafb

From: Tom Marshall <tdm@cyngn.com>
Date: Thu, 17 Apr 2014 09:39:25 -0700
Subject: libtar: Add methods for in-memory files
Commit: 8ec5627a8ff0a91724c6d5b344f0e887da922527

From: Tom Marshall <tdm@cyngn.com>
Date: Wed, 2 Jul 2014 09:34:40 -0700
Subject: libtar: Fix hardlink extract
Commit: 166d83a51e0c51abcea37694dbd7df92d03c1f56

From: philz-cwm6 <phytowardt@gmail.com>
Date: Sat, 26 Apr 2014 01:11:35 +0200
Subject: libtar: Various bug fixes and enhancements
Commit: a271d763e94235ccee9ecaabdb52bf4b9b2f8c06
(Some of this was not merged in, as better solutions were
available from upstream libtar)

From: Tom Marshall <tdm@cyngn.com>
Date: Wed, 9 Apr 2014 09:35:54 -0700
Subject: libtar: Add const qualifiers to reduce compile warnings
Commit: 0600afa19fe827d06d3fcf24a7aabd52dbf487b4

Change-Id: I6d008cb6fdf950f835bbed63aeb8727cc5c86083
diff --git a/libtar/append.c b/libtar/append.c
index 1831990..4be679c 100644
--- a/libtar/append.c
+++ b/libtar/append.c
@@ -13,8 +13,11 @@
 #include <internal.h>
 
 #include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <time.h>
 #include <sys/param.h>
 #include <sys/types.h>
 
@@ -28,7 +31,7 @@
 #endif
 
 #ifdef HAVE_SELINUX
-#include "selinux/selinux.h"
+# include "selinux/selinux.h"
 #endif
 
 struct tar_dev
@@ -57,7 +60,7 @@
 
 /* appends a file to the tar archive */
 int
-tar_append_file(TAR *t, char *realname, char *savename)
+tar_append_file(TAR *t, const char *realname, const char *savename)
 {
 	struct stat s;
 	int i;
@@ -82,38 +85,46 @@
 
 	/* set header block */
 #ifdef DEBUG
-	puts("    tar_append_file(): setting header block...");
+	puts("tar_append_file(): setting header block...");
 #endif
 	memset(&(t->th_buf), 0, sizeof(struct tar_header));
 	th_set_from_stat(t, &s);
 
 	/* set the header path */
 #ifdef DEBUG
-	puts("    tar_append_file(): setting header path...");
+	puts("tar_append_file(): setting header path...");
 #endif
 	th_set_path(t, (savename ? savename : realname));
 
 #ifdef HAVE_SELINUX
 	/* get selinux context */
-	if(t->options & TAR_STORE_SELINUX) {
-		if(t->th_buf.selinux_context != NULL) {
+	if (t->options & TAR_STORE_SELINUX)
+	{
+		if (t->th_buf.selinux_context != NULL)
+		{
 			free(t->th_buf.selinux_context);
 			t->th_buf.selinux_context = NULL;
 		}
 
 		security_context_t selinux_context = NULL;
-		if (lgetfilecon(realname, &selinux_context) >= 0) {
+		if (lgetfilecon(realname, &selinux_context) >= 0)
+		{
 			t->th_buf.selinux_context = strdup(selinux_context);
-			printf("setting selinux context: %s\n", selinux_context);
+			printf("  ==> set selinux context: %s\n", selinux_context);
 			freecon(selinux_context);
 		}
 		else
+		{
+#ifdef DEBUG
 			perror("Failed to get selinux context");
+#endif
+		}
 	}
 #endif
+
 	/* check if it's a hardlink */
 #ifdef DEBUG
-	puts("    tar_append_file(): checking inode cache for hardlink...");
+	puts("tar_append_file(): checking inode cache for hardlink...");
 #endif
 	libtar_hashptr_reset(&hp);
 	if (libtar_hash_getkey(t->h, &hp, &(s.st_dev),
@@ -171,7 +182,7 @@
 			i = MAXPATHLEN - 1;
 		path[i] = '\0';
 #ifdef DEBUG
-		printf("    tar_append_file(): encoding symlink \"%s\" -> "
+		printf("tar_append_file(): encoding symlink \"%s\" -> "
 		       "\"%s\"...\n", realname, path);
 #endif
 		th_set_link(t, path);
@@ -179,10 +190,10 @@
 
 	/* print file info */
 	if (t->options & TAR_VERBOSE)
-		th_print_long_ls(t);
+		printf("%s\n", th_get_pathname(t));
 
 #ifdef DEBUG
-	puts("    tar_append_file(): writing header");
+	puts("tar_append_file(): writing header");
 #endif
 	/* write header */
 	if (th_write(t) != 0)
@@ -193,7 +204,7 @@
 		return -1;
 	}
 #ifdef DEBUG
-	puts("    tar_append_file(): back from th_write()");
+	puts("tar_append_file(): back from th_write()");
 #endif
 
 	/* if it's a regular file, write the contents as well */
@@ -229,14 +240,19 @@
 
 /* add file contents to a tarchive */
 int
-tar_append_regfile(TAR *t, char *realname)
+tar_append_regfile(TAR *t, const char *realname)
 {
 	char block[T_BLOCKSIZE];
 	int filefd;
-	int j;
-	size_t size, i;
+	int64_t i, size;
+	ssize_t j;
+	int rv = -1;
 
+#if defined(O_BINARY)
+	filefd = open(realname, O_RDONLY|O_BINARY);
+#else
 	filefd = open(realname, O_RDONLY);
+#endif
 	if (filefd == -1)
 	{
 #ifdef DEBUG
@@ -253,25 +269,83 @@
 		{
 			if (j != -1)
 				errno = EINVAL;
-			return -1;
+			goto fail;
 		}
 		if (tar_block_write(t, &block) == -1)
-			return -1;
+			goto fail;
 	}
 
 	if (i > 0)
 	{
 		j = read(filefd, &block, i);
 		if (j == -1)
+			goto fail;
+		memset(&(block[i]), 0, T_BLOCKSIZE - i);
+		if (tar_block_write(t, &block) == -1)
+			goto fail;
+	}
+
+	/* success! */
+	rv = 0;
+fail:
+	close(filefd);
+
+	return rv;
+}
+
+
+/* add file contents to a tarchive */
+int
+tar_append_file_contents(TAR *t, const char *savename, mode_t mode,
+                         uid_t uid, gid_t gid, void *buf, size_t len)
+{
+	struct stat st;
+
+	memset(&st, 0, sizeof(st));
+	st.st_mode = S_IFREG | mode;
+	st.st_uid = uid;
+	st.st_gid = gid;
+	st.st_mtime = time(NULL);
+	st.st_size = len;
+
+	th_set_from_stat(t, &st);
+	th_set_path(t, savename);
+
+	/* write header */
+	if (th_write(t) != 0)
+	{
+#ifdef DEBUG
+		fprintf(stderr, "tar_append_file_contents(): could not write header, t->fd = %d\n", t->fd);
+#endif
+		return -1;
+	}
+
+	return tar_append_buffer(t, buf, len);
+}
+
+int
+tar_append_buffer(TAR *t, void *buf, size_t len)
+{
+	char block[T_BLOCKSIZE];
+	int filefd;
+	int i, j;
+	size_t size = len;
+
+	for (i = size; i > T_BLOCKSIZE; i -= T_BLOCKSIZE)
+	{
+		if (tar_block_write(t, buf) == -1)
 			return -1;
+		buf = (char *)buf + T_BLOCKSIZE;
+	}
+
+	if (i > 0)
+	{
+		memcpy(block, buf, i);
 		memset(&(block[i]), 0, T_BLOCKSIZE - i);
 		if (tar_block_write(t, &block) == -1)
 			return -1;
 	}
 
-	close(filefd);
-
 	return 0;
 }
 
-