1From f88fb1145beac6cce7012b506579d23e0b9826a2 Mon Sep 17 00:00:00 2001
2From: Michael Forney <mforney@mforney.org>
3Date: Sat, 3 Dec 2016 20:49:24 -0800
4Subject: [PATCH] pax: Fix GNU long name handling with short read
5
6---
7 bin/pax/ar_subs.c | 66 +++++++++++++++++++++++++++++++++------------
8 bin/pax/buf_subs.c | 4 +--
9 bin/pax/file_subs.c | 25 +----------------
10 3 files changed, 51 insertions(+), 44 deletions(-)
11
12diff --git a/bin/pax/ar_subs.c b/bin/pax/ar_subs.c
13index f018108af59..4c49efa1362 100644
14--- a/bin/pax/ar_subs.c
15+++ b/bin/pax/ar_subs.c
16@@ -37,6 +37,7 @@
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <sys/time.h>
20+#include <err.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <signal.h>
24@@ -51,6 +52,7 @@
25 static void wr_archive(ARCHD *, int is_app);
26 static int get_arc(void);
27 static int next_head(ARCHD *);
28+static int rd_gnu_string(ARCHD *);
29 extern sigset_t s_mask;
30
31 /*
32@@ -93,16 +95,8 @@ list(void)
33 * step through the archive until the format says it is done
34 */
35 while (next_head(arcn) == 0) {
36- if (arcn->type == PAX_GLL || arcn->type == PAX_GLF) {
37- /*
38- * we need to read, to get the real filename
39- */
40- off_t cnt;
41- if (!rd_wrfile(arcn, arcn->type == PAX_GLF
42- ? -1 : -2, &cnt))
43- (void)rd_skip(cnt + arcn->pad);
44+ if (rd_gnu_string(arcn))
45 continue;
46- }
47
48 /*
49 * check for pattern, and user specified options match.
50@@ -245,15 +239,8 @@ extract(void)
51 * says it is done
52 */
53 while (next_head(arcn) == 0) {
54- if (arcn->type == PAX_GLL || arcn->type == PAX_GLF) {
55- /*
56- * we need to read, to get the real filename
57- */
58- if (!rd_wrfile(arcn, arcn->type == PAX_GLF
59- ? -1 : -2, &cnt))
60- (void)rd_skip(cnt + arcn->pad);
61+ if (rd_gnu_string(arcn))
62 continue;
63- }
64
65 /*
66 * check for pattern, and user specified options match. When
67@@ -1282,3 +1269,48 @@ get_arc(void)
68 paxwarn(1, "Sorry, unable to determine archive format.");
69 return(-1);
70 }
71+
72+/*
73+ * rd_gnu_string()
74+ * Read the file contents into an allocated string if it is a GNU tar
75+ * long link/file.
76+ * Return:
77+ * 1 if gnu string read, 0 otherwise
78+ */
79+
80+static int
81+rd_gnu_string(ARCHD *arcn)
82+{
83+ char **strp;
84+
85+ switch (arcn->type) {
86+ case PAX_GLF:
87+ strp = &gnu_name_string;
88+ break;
89+ case PAX_GLL:
90+ strp = &gnu_link_string;
91+ break;
92+ default:
93+ strp = NULL;
94+ break;
95+ }
96+ if (!strp)
97+ return 0;
98+ /*
99+ * we need to read, to get the real filename
100+ */
101+ if (*strp)
102+ err(1, "WARNING! Major Internal Error! GNU hack Failing!");
103+ *strp = malloc(arcn->sb.st_size + 1);
104+ if (*strp == NULL) {
105+ paxwarn(1, "Out of memory");
106+ (void)rd_skip(arcn->skip + arcn->pad);
107+ } else if (rd_wrbuf(*strp, arcn->sb.st_size) < arcn->sb.st_size) {
108+ free(*strp);
109+ *strp = NULL;
110+ } else {
111+ (*strp)[arcn->sb.st_size] = '\0';
112+ (void)rd_skip(arcn->pad);
113+ }
114+ return 1;
115+}
116diff --git a/bin/pax/buf_subs.c b/bin/pax/buf_subs.c
117index 25dfed5b69b..e3e22a09cc6 100644
118--- a/bin/pax/buf_subs.c
119+++ b/bin/pax/buf_subs.c
120@@ -676,9 +676,7 @@ rd_wrfile(ARCHD *arcn, int ofd, off_t *left)
121 * pass the blocksize of the file being written to the write routine,
122 * if the size is zero, use the default MINFBSZ
123 */
124- if (ofd < 0)
125- sz = PAXPATHLEN + 1; /* GNU tar long link/file */
126- else if (fstat(ofd, &sb) == 0) {
127+ if (fstat(ofd, &sb) == 0) {
128 if (sb.st_blksize > 0)
129 sz = (int)sb.st_blksize;
130 } else
131diff --git a/bin/pax/file_subs.c b/bin/pax/file_subs.c
132index 9f482480a3b..ae0caf29f6c 100644
133--- a/bin/pax/file_subs.c
134+++ b/bin/pax/file_subs.c
135@@ -924,7 +924,6 @@ file_write(int fd, char *str, int cnt, int *rem, int *isempt, int sz,
136 char *end;
137 int wcnt;
138 char *st = str;
139- char **strp;
140
141 /*
142 * while we have data to process
143@@ -983,29 +982,7 @@ file_write(int fd, char *str, int cnt, int *rem, int *isempt, int sz,
144 /*
145 * have non-zero data in this file system block, have to write
146 */
147- switch (fd) {
148- case -1:
149- strp = &gnu_name_string;
150- break;
151- case -2:
152- strp = &gnu_link_string;
153- break;
154- default:
155- strp = NULL;
156- break;
157- }
158- if (strp) {
159- if (*strp)
160- err(1, "WARNING! Major Internal Error! GNU hack Failing!");
161- *strp = malloc(wcnt + 1);
162- if (*strp == NULL) {
163- paxwarn(1, "Out of memory");
164- return(-1);
165- }
166- memcpy(*strp, st, wcnt);
167- (*strp)[wcnt] = '\0';
168- break;
169- } else if (write(fd, st, wcnt) != wcnt) {
170+ if (write(fd, st, wcnt) != wcnt) {
171 syswarn(1, errno, "Failed write to file %s", name);
172 return(-1);
173 }
174--
1752.49.0
176