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