From ec3fd37495e977af375a98a472d19ae0ccbcd874 Mon Sep 17 00:00:00 2001 From: Michael Forney Date: Sat, 3 Dec 2016 20:49:24 -0800 Subject: [PATCH] pax: Fix GNU long name handling with short read --- bin/pax/ar_subs.c | 66 +++++++++++++++++++++++++++++++++------------ bin/pax/buf_subs.c | 4 +-- bin/pax/file_subs.c | 25 +---------------- 3 files changed, 51 insertions(+), 44 deletions(-) diff --git a/bin/pax/ar_subs.c b/bin/pax/ar_subs.c index e5b0a4ee5d1..f0a55abe2f7 100644 --- a/bin/pax/ar_subs.c +++ b/bin/pax/ar_subs.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -51,6 +52,7 @@ static void wr_archive(ARCHD *, int is_app); static int get_arc(void); static int next_head(ARCHD *); +static int rd_gnu_string(ARCHD *); extern sigset_t s_mask; /* @@ -93,16 +95,8 @@ list(void) * step through the archive until the format says it is done */ while (next_head(arcn) == 0) { - if (arcn->type == PAX_GLL || arcn->type == PAX_GLF) { - /* - * we need to read, to get the real filename - */ - off_t cnt; - if (!rd_wrfile(arcn, arcn->type == PAX_GLF - ? -1 : -2, &cnt)) - (void)rd_skip(cnt + arcn->pad); + if (rd_gnu_string(arcn)) continue; - } /* * check for pattern, and user specified options match. @@ -208,15 +202,8 @@ extract(void) * says it is done */ while (next_head(arcn) == 0) { - if (arcn->type == PAX_GLL || arcn->type == PAX_GLF) { - /* - * we need to read, to get the real filename - */ - if (!rd_wrfile(arcn, arcn->type == PAX_GLF - ? -1 : -2, &cnt)) - (void)rd_skip(cnt + arcn->pad); + if (rd_gnu_string(arcn)) continue; - } /* * check for pattern, and user specified options match. When @@ -1243,3 +1230,48 @@ get_arc(void) paxwarn(1, "Sorry, unable to determine archive format."); return(-1); } + +/* + * rd_gnu_string() + * Read the file contents into an allocated string if it is a GNU tar + * long link/file. + * Return: + * 1 if gnu string read, 0 otherwise + */ + +static int +rd_gnu_string(ARCHD *arcn) +{ + char **strp; + + switch (arcn->type) { + case PAX_GLF: + strp = &gnu_name_string; + break; + case PAX_GLL: + strp = &gnu_link_string; + break; + default: + strp = NULL; + break; + } + if (!strp) + return 0; + /* + * we need to read, to get the real filename + */ + if (*strp) + err(1, "WARNING! Major Internal Error! GNU hack Failing!"); + *strp = malloc(arcn->sb.st_size + 1); + if (*strp == NULL) { + paxwarn(1, "Out of memory"); + (void)rd_skip(arcn->skip + arcn->pad); + } else if (rd_wrbuf(*strp, arcn->sb.st_size) < arcn->sb.st_size) { + free(*strp); + *strp = NULL; + } else { + (*strp)[arcn->sb.st_size] = '\0'; + (void)rd_skip(arcn->pad); + } + return 1; +} diff --git a/bin/pax/buf_subs.c b/bin/pax/buf_subs.c index 68534dcbe25..e84f9e0d3d6 100644 --- a/bin/pax/buf_subs.c +++ b/bin/pax/buf_subs.c @@ -673,9 +673,7 @@ rd_wrfile(ARCHD *arcn, int ofd, off_t *left) * pass the blocksize of the file being written to the write routine, * if the size is zero, use the default MINFBSZ */ - if (ofd < 0) - sz = PAXPATHLEN + 1; /* GNU tar long link/file */ - else if (fstat(ofd, &sb) == 0) { + if (fstat(ofd, &sb) == 0) { if (sb.st_blksize > 0) sz = (int)sb.st_blksize; } else diff --git a/bin/pax/file_subs.c b/bin/pax/file_subs.c index 89b4872988b..8aa3d249923 100644 --- a/bin/pax/file_subs.c +++ b/bin/pax/file_subs.c @@ -919,7 +919,6 @@ file_write(int fd, char *str, int cnt, int *rem, int *isempt, int sz, char *end; int wcnt; char *st = str; - char **strp; /* * while we have data to process @@ -978,29 +977,7 @@ file_write(int fd, char *str, int cnt, int *rem, int *isempt, int sz, /* * have non-zero data in this file system block, have to write */ - switch (fd) { - case -1: - strp = &gnu_name_string; - break; - case -2: - strp = &gnu_link_string; - break; - default: - strp = NULL; - break; - } - if (strp) { - if (*strp) - err(1, "WARNING! Major Internal Error! GNU hack Failing!"); - *strp = malloc(wcnt + 1); - if (*strp == NULL) { - paxwarn(1, "Out of memory"); - return(-1); - } - memcpy(*strp, st, wcnt); - (*strp)[wcnt] = '\0'; - break; - } else if (write(fd, st, wcnt) != wcnt) { + if (write(fd, st, wcnt) != wcnt) { syswarn(1, errno, "Failed write to file %s", name); return(-1); } -- 2.26.2