[PATCH] cpio: implement output prefix for passthrough mode (-p)

Shubham Chakraborty via busybox <[email protected]>
Newsgroups gmane.linux.busybox
Message-ID <[email protected]>
GNU cpio -vp DIR outputs "DIR/NAME" instead of just "NAME".
This patch implements this behavior by adding a cpio__prefix
field to archive_handle_t and updating header_list/header_verbose_list
to use it.

To achieve this, the action_header callback signature was changed
from (const file_header_t*) to (archive_handle_t*) to allow
access to the prefix and other handle-specific data.

Also removes a related TODO in archival/libarchive/header_list.c.

Signed-off-by: Shubham Chakraborty <[email protected]>
---
 archival/ar.c                             |  3 ++-
 archival/cpio.c                           | 12 +++++++++++-
 archival/libarchive/get_header_ar.c       |  2 +-
 archival/libarchive/get_header_cpio.c     |  2 +-
 archival/libarchive/get_header_tar.c      |  2 +-
 archival/libarchive/header_list.c         |  9 ++++++---
 archival/libarchive/header_skip.c         |  2 +-
 archival/libarchive/header_verbose_list.c | 19 ++++++++++++-------
 include/bb_archive.h                      |  9 +++++----
 9 files changed, 40 insertions(+), 20 deletions(-)

diff --git a/archival/ar.c b/archival/ar.c
index 320cbae72..d3d6c3c06 100644
--- a/archival/ar.c
+++ b/archival/ar.c
@@ -194,8 +194,9 @@ static int write_ar_archive(archive_handle_t *handle)
 }
 #endif /* FEATURE_AR_CREATE */
 
-static void FAST_FUNC header_verbose_list_ar(const file_header_t *file_header)
+static void FAST_FUNC header_verbose_list_ar(archive_handle_t *archive_handle)
 {
+	const file_header_t *file_header = archive_handle->file_header;
 	char mode[12];
 	char *mtime;
 
diff --git a/archival/cpio.c b/archival/cpio.c
index b033b3733..dfeb12c8a 100644
--- a/archival/cpio.c
+++ b/archival/cpio.c
@@ -511,7 +511,8 @@ int cpio_main(int argc UNUSED_PARAM, char **argv)
 			goto dump;
 		}
 		/* parent */
-		xchdir(*argv++);
+		archive_handle->cpio__prefix = *argv++;
+		xchdir(archive_handle->cpio__prefix);
 		close(pp.wr);
 		xmove_fd(pp.rd, STDIN_FILENO);
 		//opt &= ~OPT_PASSTHROUGH;
@@ -557,6 +558,15 @@ int cpio_main(int argc UNUSED_PARAM, char **argv)
 			archive_handle->action_header = header_list;
 		}
 	}
+	if (archive_handle->cpio__prefix && (opt & OPT_VERBOSE)) {
+		if (archive_handle->action_header == header_list)
+			archive_handle->action_header = header_list; /* already set? */
+		else
+			archive_handle->action_header = header_verbose_list;
+	} else if (archive_handle->cpio__prefix) {
+		archive_handle->action_header = header_list;
+	}
+
 	if (opt & OPT_CREATE_LEADING_DIR) {
 		archive_handle->ah_flags |= ARCHIVE_CREATE_LEADING_DIRS;
 	}
diff --git a/archival/libarchive/get_header_ar.c b/archival/libarchive/get_header_ar.c
index 6bd897392..8106ccb4d 100644
--- a/archival/libarchive/get_header_ar.c
+++ b/archival/libarchive/get_header_ar.c
@@ -124,7 +124,7 @@ char FAST_FUNC get_header_ar(archive_handle_t *archive_handle)
 	typed->name[strcspn(typed->name, " /")] = '\0';
 
 	if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) {
-		archive_handle->action_header(typed);
+		archive_handle->action_header(archive_handle);
 #if ENABLE_DPKG || ENABLE_DPKG_DEB
 		if (archive_handle->dpkg__sub_archive) {
 			struct archive_handle_t *sa = archive_handle->dpkg__sub_archive;
diff --git a/archival/libarchive/get_header_cpio.c b/archival/libarchive/get_header_cpio.c
index 9ad0557c2..63a0b6d8a 100644
--- a/archival/libarchive/get_header_cpio.c
+++ b/archival/libarchive/get_header_cpio.c
@@ -125,7 +125,7 @@ char FAST_FUNC get_header_cpio(archive_handle_t *archive_handle)
 //cpio: etc/hosts not created: newer or same age file exists
 //etc/hosts  <-- should NOT show it
 //2 blocks <-- should say "0 blocks"
-		archive_handle->action_header(file_header);
+		archive_handle->action_header(archive_handle);
 	} else {
 		data_skip(archive_handle);
 	}
diff --git a/archival/libarchive/get_header_tar.c b/archival/libarchive/get_header_tar.c
index 606d8067f..470a962b1 100644
--- a/archival/libarchive/get_header_tar.c
+++ b/archival/libarchive/get_header_tar.c
@@ -469,7 +469,7 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
 	cp = last_char_is(file_header->name, '/');
 
 	if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) {
-		archive_handle->action_header(/*archive_handle->*/ file_header);
+		archive_handle->action_header(archive_handle);
 		/* Note that we kill the '/' only after action_header() */
 		/* (like GNU tar 1.15.1: verbose mode outputs "dir/dir/") */
 		if (cp)
diff --git a/archival/libarchive/header_list.c b/archival/libarchive/header_list.c
index 9490b3635..8eb64f65c 100644
--- a/archival/libarchive/header_list.c
+++ b/archival/libarchive/header_list.c
@@ -5,8 +5,11 @@
 #include "libbb.h"
 #include "bb_archive.h"
 
-void FAST_FUNC header_list(const file_header_t *file_header)
+void FAST_FUNC header_list(archive_handle_t *archive_handle)
 {
-//TODO: cpio -vp DIR should output "DIR/NAME", not just "NAME" */
-	puts(printable_string(file_header->name));
+#if ENABLE_CPIO || ENABLE_RPM2CPIO || ENABLE_RPM
+	if (archive_handle->cpio__prefix)
+		printf("%s/", archive_handle->cpio__prefix);
+#endif
+	puts(printable_string(archive_handle->file_header->name));
 }
diff --git a/archival/libarchive/header_skip.c b/archival/libarchive/header_skip.c
index f5987bfe2..e7691534e 100644
--- a/archival/libarchive/header_skip.c
+++ b/archival/libarchive/header_skip.c
@@ -5,6 +5,6 @@
 #include "libbb.h"
 #include "bb_archive.h"
 
-void FAST_FUNC header_skip(const file_header_t *file_header UNUSED_PARAM)
+void FAST_FUNC header_skip(archive_handle_t *archive_handle UNUSED_PARAM)
 {
 }
diff --git a/archival/libarchive/header_verbose_list.c b/archival/libarchive/header_verbose_list.c
index e7a09430d..63acd0f1f 100644
--- a/archival/libarchive/header_verbose_list.c
+++ b/archival/libarchive/header_verbose_list.c
@@ -5,8 +5,9 @@
 #include "libbb.h"
 #include "bb_archive.h"
 
-void FAST_FUNC header_verbose_list(const file_header_t *file_header)
+void FAST_FUNC header_verbose_list(archive_handle_t *archive_handle)
 {
+	const file_header_t *file_header = archive_handle->file_header;
 	struct tm tm_time;
 	struct tm *ptm = &tm_time; //localtime(&file_header->mtime);
 	char modestr[12];
@@ -29,7 +30,7 @@ void FAST_FUNC header_verbose_list(const file_header_t *file_header)
 		/*sprintf(gid, "%u", (unsigned)file_header->gid);*/
 		group = utoa(file_header->gid);
 	}
-	printf("%s %s/%s %9"OFF_FMT"u %4u-%02u-%02u %02u:%02u:%02u %s",
+	printf("%s %s/%s %9"OFF_FMT"u %4u-%02u-%02u %02u:%02u:%02u ",
 		bb_mode_string(modestr, file_header->mode),
 		user,
 		group,
@@ -39,14 +40,13 @@ void FAST_FUNC header_verbose_list(const file_header_t *file_header)
 		ptm->tm_mday,
 		ptm->tm_hour,
 		ptm->tm_min,
-		ptm->tm_sec,
-		file_header->name);
+		ptm->tm_sec);
 
 #else /* !FEATURE_TAR_UNAME_GNAME */
 
 	localtime_r(&file_header->mtime, ptm);
 
-	printf("%s %u/%u %9"OFF_FMT"u %4u-%02u-%02u %02u:%02u:%02u %s",
+	printf("%s %u/%u %9"OFF_FMT"u %4u-%02u-%02u %02u:%02u:%02u ",
 		bb_mode_string(modestr, file_header->mode),
 		(unsigned)file_header->uid,
 		(unsigned)file_header->gid,
@@ -56,11 +56,16 @@ void FAST_FUNC header_verbose_list(const file_header_t *file_header)
 		ptm->tm_mday,
 		ptm->tm_hour,
 		ptm->tm_min,
-		ptm->tm_sec,
-		printable_string(file_header->name));
+		ptm->tm_sec);
 
 #endif /* FEATURE_TAR_UNAME_GNAME */
 
+#if ENABLE_CPIO || ENABLE_RPM2CPIO || ENABLE_RPM
+	if (archive_handle->cpio__prefix)
+		printf("%s/", archive_handle->cpio__prefix);
+#endif
+	printf("%s", printable_string(file_header->name));
+
 	/* NB: GNU tar shows "->" for symlinks and "link to" for hardlinks */
 	if (file_header->link_target) {
 		printf(" -> %s", printable_string(file_header->link_target));
diff --git a/include/bb_archive.h b/include/bb_archive.h
index 1dc77f31d..d6a7162d6 100644
--- a/include/bb_archive.h
+++ b/include/bb_archive.h
@@ -68,7 +68,7 @@ typedef struct archive_handle_t {
 	llist_t *link_placeholders;
 
 	/* Process the header component, e.g. tar -t */
-	void FAST_FUNC (*action_header)(const file_header_t *);
+	void FAST_FUNC (*action_header)(struct archive_handle_t *);
 
 	/* Process the data component, e.g. extract to filesystem */
 	void FAST_FUNC (*action_data)(struct archive_handle_t *);
@@ -101,6 +101,7 @@ typedef struct archive_handle_t {
 #endif
 #if ENABLE_CPIO || ENABLE_RPM2CPIO || ENABLE_RPM
 	uoff_t cpio__blocks;
+	char *cpio__prefix;
 	struct bb_uidgid_t cpio__owner;
 	struct hardlinks_t *cpio__hardlinks_to_create;
 	struct hardlinks_t *cpio__created_hardlinks;
@@ -187,9 +188,9 @@ void data_extract_all(archive_handle_t *archive_handle) FAST_FUNC;
 void data_extract_to_stdout(archive_handle_t *archive_handle) FAST_FUNC;
 void data_extract_to_command(archive_handle_t *archive_handle) FAST_FUNC;
 
-void header_skip(const file_header_t *file_header) FAST_FUNC;
-void header_list(const file_header_t *file_header) FAST_FUNC;
-void header_verbose_list(const file_header_t *file_header) FAST_FUNC;
+void header_skip(archive_handle_t *archive_handle) FAST_FUNC;
+void header_list(archive_handle_t *archive_handle) FAST_FUNC;
+void header_verbose_list(archive_handle_t *archive_handle) FAST_FUNC;
 
 char get_header_ar(archive_handle_t *archive_handle) FAST_FUNC;
 char get_header_cpio(archive_handle_t *archive_handle) FAST_FUNC;
-- 
2.53.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.