source: freewrt/tools/paxmirabilis/src/ar.c@ a569125

freewrt_1_0 freewrt_2_0
Last change on this file since a569125 was a569125, checked in by Thorsten Glaser <tg@…>, 14 years ago

even FreeWRT 1.0-stable deserves paxmirabilis-20120216 compiled with LTO ☺

git-svn-id: svn://www.freewrt.org/branches/freewrt_1_0@3981 afb5a338-a214-0410-bd46-81f09a774fd1

  • Property mode set to 100644
File size: 7.9 KB
Line 
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 "pax.h"
39#include "extern.h"
40#include "options.h"
41#include "ar.h"
42
43__RCSID("$MirOS: src/bin/pax/ar.c,v 1.6 2012/02/16 17:41:40 tg Exp $");
44
45/*
46 * Routines for reading and writing Unix Archiver format libraries
47 */
48
49static /*const*/ char magic[8] = {
50 0x21, 0x3C, 0x61, 0x72, 0x63, 0x68, 0x3E, 0x0A
51};
52
53
54/*
55 * initialisation for ar write
56 * returns 0 if ok, -1 otherwise
57 */
58int
59uar_stwr(int is_app)
60{
61 return (is_app ? 0 : wr_rdbuf(magic, 8));
62}
63
64/*
65 * check for ar magic
66 * returns 0 if ok, -1 otherwise
67 */
68int
69uar_ismagic(char *buf)
70{
71 return (memcmp(buf, magic, 8) ? -1 : 0);
72}
73
74/*
75 * used during format identification, but we differ
76 */
77int
78uar_id(char *buf __attribute__((__unused__)),
79 int len __attribute__((__unused__)))
80{
81 errx(1, "internal error: %s should never have been called",
82 "uar_id");
83}
84
85/* internal parsing functions */
86static uint64_t
87uar_atoi64(const char *buf, size_t len)
88{
89 char c;
90 uint64_t res = 0;
91
92 loop:
93 if (!len-- || (c = *buf++) < '0' || c > '9')
94 return (res);
95 res = (res * 10) + (c - '0');
96 goto loop;
97}
98
99static uint32_t
100uar_atoi32(const char *buf, size_t len)
101{
102 char c;
103 uint32_t res = 0;
104
105 loop:
106 if (!len-- || (c = *buf++) < '0' || c > '9')
107 return (res);
108 res = (res * 10) + (c - '0');
109 goto loop;
110}
111
112static uint32_t
113uar_otoi32(const char *buf, size_t len)
114{
115 char c;
116 uint32_t res = 0;
117
118 loop:
119 if (!len-- || (c = *buf++) < '0' || c > '7')
120 return (res);
121 res = (res << 3) | (c & 7);
122 goto loop;
123}
124
125/*
126 * parse header
127 */
128int
129uar_rd(ARCHD *arcn, char *buf)
130{
131 HD_AR *h = (HD_AR *)buf;
132 uint64_t i;
133
134 if (h->ar_magic[0] != 0x60 || h->ar_magic[1] != 0x0A)
135 return (-1);
136
137 memset(arcn, 0, sizeof(*arcn));
138 arcn->org_name = arcn->name;
139 arcn->sb.st_nlink = 1;
140 arcn->type = PAX_REG;
141
142 arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime =
143 uar_atoi64(h->ar_mtime, sizeof(h->ar_mtime));
144 arcn->sb.st_uid = uar_atoi32(h->ar_uid, sizeof(h->ar_uid));
145 arcn->sb.st_gid = uar_atoi32(h->ar_gid, sizeof(h->ar_gid));
146 arcn->sb.st_mode = uar_otoi32(h->ar_mode, sizeof(h->ar_mode)) |
147 S_IFREG;
148 i = uar_atoi64(h->ar_size, sizeof(h->ar_size));
149 arcn->pad = i & 1;
150
151 if (h->ar_name[0] == 0x23 &&
152 h->ar_name[1] == 0x31 &&
153 h->ar_name[2] == 0x2F) {
154 arcn->nlen = uar_atoi32(&(h->ar_name[3]),
155 sizeof(h->ar_name) - 3);
156 if (arcn->nlen > PAXPATHLEN)
157 /*XXX just skip over this file */
158 return (-1);
159 if (rd_wrbuf(arcn->name, arcn->nlen) != arcn->nlen)
160 return (-1);
161 i -= arcn->nlen;
162 } else {
163 register char c;
164
165 /*arcn->nlen = 0;*/
166 while (arcn->nlen < (int)sizeof(h->ar_name)) {
167 c = h->ar_name[arcn->nlen];
168 if (c == ' ' || c == '/' || c == '\0')
169 break;
170 arcn->name[arcn->nlen++] = c;
171 }
172 }
173 arcn->name[arcn->nlen] = '\0';
174 arcn->sb.st_size = i;
175 arcn->skip = i;
176 return (0);
177}
178
179/* internal emission functions */
180static char *
181uar_itoa64(char *dst, uint64_t num)
182{
183 if (num >= 10)
184 dst = uar_itoa64(dst, num / 10);
185 *dst++ = '0' + (num % 10);
186 return (dst);
187}
188
189static char *
190uar_itoa32(char *dst, uint32_t num)
191{
192 if (num >= 10)
193 dst = uar_itoa32(dst, num / 10);
194 *dst++ = '0' + (num % 10);
195 return (dst);
196}
197
198static char *
199uar_itoo32(char *dst, uint32_t num)
200{
201 if (num & ~7)
202 dst = uar_itoo32(dst, num >> 3);
203 *dst++ = '0' | (num & 7);
204 return (dst);
205}
206
207/*
208 * write a header
209 */
210int
211uar_wr(ARCHD *arcn)
212{
213 HD_AR h;
214 u_long t_uid, t_gid;
215 time_t t_mtime = 0;
216 char *extname;
217 size_t n;
218 u_long t_mode[sizeof(arcn->sb.st_mode) <= sizeof(u_long) ? 1 : -1];
219
220 anonarch_init();
221
222 switch (arcn->type) {
223 case PAX_CTG:
224 case PAX_REG:
225 case PAX_HRG:
226 /* regular files, more or less */
227 break;
228 case PAX_DIR:
229 /* directory, ignore silently */
230 return (1);
231 default:
232 paxwarn(1, "ar can only archive regular files, which %s is not",
233 arcn->org_name);
234 return (1);
235 }
236
237 /* trim trailing slashes */
238 n = strlen(arcn->name) - 1;
239 while (n && arcn->name[n] == '/')
240 --n;
241 arcn->name[++n] = '\0';
242 /* find out basename */
243 if ((extname = strrchr(arcn->name, '/')) == NULL)
244 extname = arcn->name;
245 else
246 ++extname;
247
248 t_uid = (anonarch & ANON_UIDGID) ? 0UL : (u_long)arcn->sb.st_uid;
249 t_gid = (anonarch & ANON_UIDGID) ? 0UL : (u_long)arcn->sb.st_gid;
250 t_mode[0] = arcn->sb.st_mode;
251 if (!(anonarch & ANON_MTIME))
252 t_mtime = arcn->sb.st_mtime;
253
254 if (sizeof(time_t) > 4 && t_mtime > (time_t)999999999999ULL) {
255 paxwarn(1, "%s overflow for %s", "mtime", arcn->org_name);
256 t_mtime = (time_t)999999999999ULL;
257 }
258 if (t_uid > 999999UL) {
259 paxwarn(1, "%s overflow for %s", "uid", arcn->org_name);
260 t_uid = 999999UL;
261 }
262 if (t_gid > 999999UL) {
263 paxwarn(1, "%s overflow for %s", "gid", arcn->org_name);
264 t_gid = 999999UL;
265 }
266 if (t_mode[0] > 077777777UL) {
267 paxwarn(1, "%s overflow for %s", "mode", arcn->org_name);
268 t_mode[0] &= 077777777UL;
269 }
270 if ((uint64_t)arcn->sb.st_size > ((uint64_t)9999999999ULL)) {
271 paxwarn(1, "%s overflow for %s", "size", arcn->org_name);
272 return (1);
273 }
274
275 if (anonarch & ANON_DEBUG)
276 paxwarn(0, "writing mode %8lo user %ld:%ld "
277 "mtime %08lX name '%s'", t_mode[0],
278 t_uid, t_gid, (u_long)t_mtime, extname);
279
280 memset(&h, ' ', sizeof(HD_AR));
281
282 if ((n = strlen(extname)) <= sizeof(h.ar_name)) {
283 while (n)
284 if (extname[--n] == ' ')
285 break;
286 if (n == 0) {
287 memcpy(h.ar_name, extname, strlen(extname));
288 extname = NULL;
289 goto got_name;
290 }
291 }
292 n = strlen(extname);
293 /* assert: n <= PAXPATHLEN <= 9999999999999 */
294 h.ar_name[0] = 0x23;
295 h.ar_name[1] = 0x31;
296 h.ar_name[2] = 0x2F;
297 uar_itoa32(&(h.ar_name[3]), n);
298 got_name:
299 uar_itoa64(h.ar_mtime, t_mtime);
300 uar_itoa32(h.ar_uid, t_uid);
301 uar_itoa32(h.ar_gid, t_gid);
302 uar_itoo32(h.ar_mode, t_mode[0]);
303 uar_itoa64(h.ar_size, arcn->sb.st_size +
304 (extname ? strlen(extname) : 0));
305 h.ar_magic[0] = 0x60;
306 h.ar_magic[1] = 0x0A;
307 arcn->pad = (arcn->sb.st_size + (extname ? strlen(extname) : 0)) & 1;
308
309 if (wr_rdbuf((void *)&h, sizeof(HD_AR)) < 0)
310 return (-1);
311 if (extname) {
312 if (wr_rdbuf(extname, strlen(extname)) < 0)
313 return (-1);
314 }
315 /* so let the data follow */
316 return (0);
317}
318
319/*
320 * return size of trailer
321 */
322off_t
323uar_endrd(void)
324{
325 return (0);
326}
327
328/*
329 * another artefact of paxtar integration
330 */
331int
332uar_trail(ARCHD *ignore __attribute__((__unused__)),
333 char *buf __attribute__((__unused__)),
334 int in_resync __attribute__((__unused__)),
335 int *cnt __attribute__((__unused__)))
336{
337 errx(1, "internal error: %s should never have been called",
338 "uar_trail");
339}
Note: See TracBrowser for help on using the repository browser.