1 /*-
2  * Copyright (c) 2011 Thorsten Glaser.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  * 3. Neither the name of the University nor the names of its contributors
13  *    may be used to endorse or promote products derived from this software
14  *    without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/param.h>
30 #include <sys/time.h>
31 #include <sys/stat.h>
32 #include <err.h>
33 #include <string.h>
34 #include <stdint.h>
35 #include <stdio.h>
36 #include <unistd.h>
37 #include <stdlib.h>
38 #include <time.h>
39 #include "pax.h"
40 #include "extern.h"
41 #include "options.h"
42 #include "ar.h"
43 
44 __RCSID("$MirOS: src/bin/pax/ar.c,v 1.7 2012/05/20 16:13:15 tg Exp $");
45 
46 /*
47  * Routines for reading and writing Unix Archiver format libraries
48  */
49 
50 static /*const*/ char magic[8] = {
51 	0x21, 0x3C, 0x61, 0x72, 0x63, 0x68, 0x3E, 0x0A
52 };
53 
54 
55 /*
56  * initialisation for ar write
57  * returns 0 if ok, -1 otherwise
58  */
59 int
uar_stwr(int is_app)60 uar_stwr(int is_app)
61 {
62 	return (is_app ? 0 : wr_rdbuf(magic, 8));
63 }
64 
65 /*
66  * check for ar magic
67  * returns 0 if ok, -1 otherwise
68  */
69 int
uar_ismagic(char * buf)70 uar_ismagic(char *buf)
71 {
72 	return (memcmp(buf, magic, 8) ? -1 : 0);
73 }
74 
75 /*
76  * used during format identification, but we differ
77  */
78 int
uar_id(char * buf,int len)79 uar_id(char *buf __attribute__((__unused__)),
80     int len __attribute__((__unused__)))
81 {
82 	errx(1, "internal error: %s should never have been called",
83 	    "uar_id");
84 }
85 
86 /* internal parsing functions */
87 static uint64_t
uar_atoi64(const char * buf,size_t len)88 uar_atoi64(const char *buf, size_t len)
89 {
90 	char c;
91 	uint64_t res = 0;
92 
93  loop:
94 	if (!len-- || (c = *buf++) < '0' || c > '9')
95 		return (res);
96 	res = (res * 10) + (c - '0');
97 	goto loop;
98 }
99 
100 static uint32_t
uar_atoi32(const char * buf,size_t len)101 uar_atoi32(const char *buf, size_t len)
102 {
103 	char c;
104 	uint32_t res = 0;
105 
106  loop:
107 	if (!len-- || (c = *buf++) < '0' || c > '9')
108 		return (res);
109 	res = (res * 10) + (c - '0');
110 	goto loop;
111 }
112 
113 static uint32_t
uar_otoi32(const char * buf,size_t len)114 uar_otoi32(const char *buf, size_t len)
115 {
116 	char c;
117 	uint32_t res = 0;
118 
119  loop:
120 	if (!len-- || (c = *buf++) < '0' || c > '7')
121 		return (res);
122 	res = (res << 3) | (c & 7);
123 	goto loop;
124 }
125 
126 /*
127  * parse header
128  */
129 int
uar_rd(ARCHD * arcn,char * buf)130 uar_rd(ARCHD *arcn, char *buf)
131 {
132 	HD_AR *h = (HD_AR *)buf;
133 	uint64_t i;
134 
135 	if (h->ar_magic[0] != 0x60 || h->ar_magic[1] != 0x0A)
136 		return (-1);
137 
138 	memset(arcn, 0, sizeof(*arcn));
139 	arcn->org_name = arcn->name;
140 	arcn->sb.st_nlink = 1;
141 	arcn->type = PAX_REG;
142 
143 	arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime =
144 	    uar_atoi64(h->ar_mtime, sizeof(h->ar_mtime));
145 	arcn->sb.st_uid = uar_atoi32(h->ar_uid, sizeof(h->ar_uid));
146 	arcn->sb.st_gid = uar_atoi32(h->ar_gid, sizeof(h->ar_gid));
147 	arcn->sb.st_mode = uar_otoi32(h->ar_mode, sizeof(h->ar_mode)) |
148 	    S_IFREG;
149 	i = uar_atoi64(h->ar_size, sizeof(h->ar_size));
150 	arcn->pad = i & 1;
151 
152 	if (h->ar_name[0] == 0x23 &&
153 	    h->ar_name[1] == 0x31 &&
154 	    h->ar_name[2] == 0x2F) {
155 		arcn->nlen = uar_atoi32(&(h->ar_name[3]),
156 		    sizeof(h->ar_name) - 3);
157 		if (arcn->nlen > PAXPATHLEN)
158 			/*XXX just skip over this file */
159 			return (-1);
160 		if (rd_wrbuf(arcn->name, arcn->nlen) != arcn->nlen)
161 			return (-1);
162 		i -= arcn->nlen;
163 	} else {
164 		register char c;
165 
166 		/*arcn->nlen = 0;*/
167 		while (arcn->nlen < (int)sizeof(h->ar_name)) {
168 			c = h->ar_name[arcn->nlen];
169 			if (c == ' ' || c == '/' || c == '\0')
170 				break;
171 			arcn->name[arcn->nlen++] = c;
172 		}
173 	}
174 	arcn->name[arcn->nlen] = '\0';
175 	arcn->sb.st_size = i;
176 	arcn->skip = i;
177 	return (0);
178 }
179 
180 /* internal emission functions */
181 static char *
uar_itoa64(char * dst,uint64_t num)182 uar_itoa64(char *dst, uint64_t num)
183 {
184 	if (num >= 10)
185 		dst = uar_itoa64(dst, num / 10);
186 	*dst++ = '0' + (num % 10);
187 	return (dst);
188 }
189 
190 static char *
uar_itoa32(char * dst,uint32_t num)191 uar_itoa32(char *dst, uint32_t num)
192 {
193 	if (num >= 10)
194 		dst = uar_itoa32(dst, num / 10);
195 	*dst++ = '0' + (num % 10);
196 	return (dst);
197 }
198 
199 static char *
uar_itoo32(char * dst,uint32_t num)200 uar_itoo32(char *dst, uint32_t num)
201 {
202 	if (num & ~7)
203 		dst = uar_itoo32(dst, num >> 3);
204 	*dst++ = '0' | (num & 7);
205 	return (dst);
206 }
207 
208 /*
209  * write a header
210  */
211 int
uar_wr(ARCHD * arcn)212 uar_wr(ARCHD *arcn)
213 {
214 	HD_AR h;
215 	u_long t_uid, t_gid;
216 	time_t t_mtime = 0;
217 	char *extname;
218 	size_t n;
219 	u_long t_mode[sizeof(arcn->sb.st_mode) <= sizeof(u_long) ? 1 : -1];
220 
221 	anonarch_init();
222 
223 	switch (arcn->type) {
224 	case PAX_CTG:
225 	case PAX_REG:
226 	case PAX_HRG:
227 		/* regular files, more or less */
228 		break;
229 	case PAX_DIR:
230 		/* directory, ignore silently */
231 		return (1);
232 	default:
233 		paxwarn(1, "ar can only archive regular files, which %s is not",
234 		    arcn->org_name);
235 		return (1);
236 	}
237 
238 	/* trim trailing slashes */
239 	n = strlen(arcn->name) - 1;
240 	while (n && arcn->name[n] == '/')
241 		--n;
242 	arcn->name[++n] = '\0';
243 	/* find out basename */
244 	if ((extname = strrchr(arcn->name, '/')) == NULL)
245 		extname = arcn->name;
246 	else
247 		++extname;
248 
249 	t_uid = (anonarch & ANON_UIDGID) ? 0UL : (u_long)arcn->sb.st_uid;
250 	t_gid = (anonarch & ANON_UIDGID) ? 0UL : (u_long)arcn->sb.st_gid;
251 	t_mode[0] = arcn->sb.st_mode;
252 	if (!(anonarch & ANON_MTIME))
253 		t_mtime = arcn->sb.st_mtime;
254 
255 	if (sizeof(time_t) > 4 && t_mtime > (time_t)999999999999ULL) {
256 		paxwarn(1, "%s overflow for %s", "mtime", arcn->org_name);
257 		t_mtime = (time_t)999999999999ULL;
258 	}
259 	if (t_uid > 999999UL) {
260 		paxwarn(1, "%s overflow for %s", "uid", arcn->org_name);
261 		t_uid = 999999UL;
262 	}
263 	if (t_gid > 999999UL) {
264 		paxwarn(1, "%s overflow for %s", "gid", arcn->org_name);
265 		t_gid = 999999UL;
266 	}
267 	if (t_mode[0] > 077777777UL) {
268 		paxwarn(1, "%s overflow for %s", "mode", arcn->org_name);
269 		t_mode[0] &= 077777777UL;
270 	}
271 	if ((uint64_t)arcn->sb.st_size > ((uint64_t)9999999999ULL)) {
272 		paxwarn(1, "%s overflow for %s", "size", arcn->org_name);
273 		return (1);
274 	}
275 
276 	if (anonarch & ANON_DEBUG)
277 		paxwarn(0, "writing mode %8lo user %ld:%ld "
278 		    "mtime %08lX name '%s'", t_mode[0],
279 		    t_uid, t_gid, (u_long)t_mtime, extname);
280 
281 	memset(&h, ' ', sizeof(HD_AR));
282 
283 	if ((n = strlen(extname)) <= sizeof(h.ar_name)) {
284 		while (n)
285 			if (extname[--n] == ' ')
286 				break;
287 		if (n == 0) {
288 			memcpy(h.ar_name, extname, strlen(extname));
289 			extname = NULL;
290 			goto got_name;
291 		}
292 	}
293 	n = strlen(extname);
294 	/* assert: n <= PAXPATHLEN <= 9999999999999 */
295 	h.ar_name[0] = 0x23;
296 	h.ar_name[1] = 0x31;
297 	h.ar_name[2] = 0x2F;
298 	uar_itoa32(&(h.ar_name[3]), n);
299  got_name:
300 	uar_itoa64(h.ar_mtime, t_mtime);
301 	uar_itoa32(h.ar_uid, t_uid);
302 	uar_itoa32(h.ar_gid, t_gid);
303 	uar_itoo32(h.ar_mode, t_mode[0]);
304 	uar_itoa64(h.ar_size, arcn->sb.st_size +
305 	    (extname ? strlen(extname) : 0));
306 	h.ar_magic[0] = 0x60;
307 	h.ar_magic[1] = 0x0A;
308 	arcn->pad = (arcn->sb.st_size + (extname ? strlen(extname) : 0)) & 1;
309 
310 	if (wr_rdbuf((void *)&h, sizeof(HD_AR)) < 0)
311 		return (-1);
312 	if (extname) {
313 		if (wr_rdbuf(extname, strlen(extname)) < 0)
314 			return (-1);
315 	}
316 	/* so let the data follow */
317 	return (0);
318 }
319 
320 /*
321  * return size of trailer
322  */
323 off_t
uar_endrd(void)324 uar_endrd(void)
325 {
326 	return (0);
327 }
328 
329 /*
330  * another artefact of paxtar integration
331  */
332 int
uar_trail(ARCHD * ignore,char * buf,int in_resync,int * cnt)333 uar_trail(ARCHD *ignore __attribute__((__unused__)),
334     char *buf __attribute__((__unused__)),
335     int in_resync __attribute__((__unused__)),
336     int *cnt __attribute__((__unused__)))
337 {
338 	errx(1, "internal error: %s should never have been called",
339 	    "uar_trail");
340 }
341