tar: optional support for restoring selinux context

function                                             old     new   delta
get_header_tar                                      1690    1976    +286
data_extract_all                                     821     881     +60
.rodata                                           151446  151503     +57
get_header_cpio                                     1044    1077     +33
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 4/0 up/down: 436/0)             Total: 436 bytes

Signed-off-by: J. Tang <tang@jtang.org>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
diff --git a/archival/libunarchive/data_extract_all.c b/archival/libunarchive/data_extract_all.c
index 58b0533..cc48942 100644
--- a/archival/libunarchive/data_extract_all.c
+++ b/archival/libunarchive/data_extract_all.c
@@ -12,6 +12,17 @@
 	int dst_fd;
 	int res;
 
+#if ENABLE_FEATURE_TAR_SELINUX
+	char *sctx = archive_handle->tar__next_file_sctx;
+	if (!sctx)
+		sctx = archive_handle->tar__global_sctx;
+	if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */
+		setfscreatecon(sctx);
+		free(archive_handle->tar__next_file_sctx);
+		archive_handle->tar__next_file_sctx = NULL;
+	}
+#endif
+
 	if (archive_handle->ah_flags & ARCHIVE_CREATE_LEADING_DIRS) {
 		char *slash = strrchr(file_header->name, '/');
 		if (slash) {
@@ -45,7 +56,7 @@
 					"same age file exists", file_header->name);
 			}
 			data_skip(archive_handle);
-			return;
+			goto ret;
 		}
 		else if ((unlink(file_header->name) == -1) && (errno != EISDIR)) {
 			bb_perror_msg_and_die("can't remove old file %s",
@@ -158,4 +169,12 @@
 			utimes(file_header->name, t);
 		}
 	}
+
+ ret: ;
+#if ENABLE_FEATURE_TAR_SELINUX
+	if (sctx) {
+		/* reset the context after creating an entry */
+		setfscreatecon(NULL);
+	}
+#endif
 }