1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 2003-2011 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                 Eclipse Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *          http://www.eclipse.org/org/documents/epl-v10.html           *
11 *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *                 Glenn Fowler <gsf@research.att.com>                  *
18 *                                                                      *
19 ***********************************************************************/
20 #pragma prototyped
21 
22 /*
23  * pax zoo format
24  *
25  * header layout snarfed from the public domain unzoo.c
26  */
27 
28 #include <paxlib.h>
29 #include <codex.h>
30 #include <sum.h>
31 #include <swap.h>
32 #include <tm.h>
33 
34 #define MAGIC		0xfdc4a7dc
35 #define SUM		"sum-crc-0xa001"
36 
37 typedef struct Ar_s
38 {
39 	Codexdisc_t	codexdisc;
40 	Pax_t*		pax;
41 	Paxarchive_t*	ap;
42 	char		method[64];
43 	unsigned int	index;
44 	unsigned long	checksum;
45 
46 	unsigned long	head;		/* next member header offset	*/
47 	unsigned long	data;		/* current member data offset	*/
48 	unsigned char	majver;		/* major version		*/
49 	unsigned char	minver;		/* minor version		*/
50 } Ar_t;
51 
52 static int
zoo_done(Pax_t * pax,register Paxarchive_t * ap)53 zoo_done(Pax_t* pax, register Paxarchive_t* ap)
54 {
55 	register Ar_t*	ar = (Ar_t*)ap->data;
56 
57 	if (!ar)
58 		return -1;
59 	free(ar);
60 	ap->data = 0;
61 	return 0;
62 }
63 
64 static int
zoo_getprologue(Pax_t * pax,Paxformat_t * fp,register Paxarchive_t * ap,Paxfile_t * f,unsigned char * buf,size_t size)65 zoo_getprologue(Pax_t* pax, Paxformat_t* fp, register Paxarchive_t* ap, Paxfile_t* f, unsigned char* buf, size_t size)
66 {
67 	register Ar_t*		ar;
68 
69 	if (size < 34 || swapget(3, buf + 20, 4) != MAGIC)
70 		return 0;
71 	if (!(ar = newof(0, Ar_t, 1, 0)))
72 	{
73 		if (ar)
74 			free(ar);
75 		return paxnospace(pax);
76 	}
77 	ar->pax = pax;
78 	ar->ap = ap;
79 	ar->head = swapget(3, buf + 24, 4);
80 	ar->majver = buf[32];
81 	ar->minver = buf[33];
82 	ap->data = ar;
83 	if (ar->head > 34 && size < 42)
84 	{
85 		zoo_done(pax, ap);
86 		return paxcorrupt(pax, ap, NiL, "unexpected EOF");
87 	}
88 	codexinit(&ar->codexdisc, pax->errorf);
89 	return 1;
90 }
91 
92 static int
zoo_getheader(Pax_t * pax,register Paxarchive_t * ap,register Paxfile_t * f)93 zoo_getheader(Pax_t* pax, register Paxarchive_t* ap, register Paxfile_t* f)
94 {
95 	register Ar_t*		ar = (Ar_t*)ap->data;
96 	register unsigned char*	buf;
97 	register char*		s;
98 	Tm_t			tm;
99 	long			n;
100 	int			i;
101 	int			mode;
102 	int			dosdate;
103 	int			dostime;
104 	int			doszone;
105 	int			ext;
106 	int			extdir;
107 	int			extname;
108 	int			system;
109 	char			name[14];
110 
111 	for (;;)
112 	{
113 		if (paxseek(pax, ap, ar->head, SEEK_SET, 1) != ar->head ||
114 		    !(buf = paxget(pax, ap, 38, NiL)) ||
115 		    swapget(3, buf, 4) != MAGIC)
116 			break;
117 		if (!(ar->head = swapget(3, buf+6, 4)))
118 			return 0;
119 		if (buf[30])
120 			continue;
121 		ar->data = swapget(3, buf+10, 4);
122 		dosdate = swapget(3, buf+14, 2);
123 		dostime = swapget(3, buf+16, 2);
124 		ar->checksum = swapget(3, buf+18, 2);
125 		f->uncompressed = swapget(3, buf+20, 4);
126 		f->st->st_size = swapget(3, buf+24, 4);
127 		ar->majver = buf[28];
128 		ar->minver = buf[29];
129 		switch (ar->index = buf[5])
130 		{
131 		case 0:
132 			sfsprintf(ar->method, sizeof(ar->method), "copy|%s", SUM);
133 			break;
134 		case 1:
135 			sfsprintf(ar->method, sizeof(ar->method), "lzd+SIZE=%I*u|%s", sizeof(f->uncompressed), f->uncompressed, SUM);
136 			s = "lzd";
137 			break;
138 		case 2:
139 			sfsprintf(ar->method, sizeof(ar->method), "lzh-8k-s1+SIZE=%I*u|%s", sizeof(f->uncompressed), f->uncompressed, SUM);
140 			break;
141 		default:
142 			*ar->method = 0;
143 			break;
144 		}
145 		if (paxread(pax, ap, name, sizeof(name) - 1, 0, 1) != (sizeof(name) - 1))
146 			break;
147 		name[sizeof(name) - 1] = 0;
148 		if (buf[4] == 2)
149 		{
150 			if (!(buf = paxget(pax, ap, 5, NiL)))
151 				break;
152 			ext = swapget(3, buf+0, 2);
153 			doszone = buf[2];
154 		}
155 		else
156 		{
157 			ext = 0;
158 			doszone = 127;
159 		}
160 		if (ext > 0)
161 		{
162 			if (!(buf = paxget(pax, ap, 1, NiL)))
163 				break;
164 			extname = buf[0];
165 		}
166 		else
167 			extname = 0;
168 		if (ext > 1)
169 		{
170 			if (!(buf = paxget(pax, ap, 1, NiL)))
171 				break;
172 			extdir = buf[0];
173 		}
174 		else
175 			extdir = 0;
176 		if (n = extdir + extname)
177 		{
178 			if (!extname)
179 				n += (i = strlen(name));
180 			f->name = paxstash(pax, &ap->stash.head, NiL, n + 1);
181 			if (!extname)
182 			{
183 				memcpy(f->name + extdir, name, i);
184 				f->name[extdir + i] = 0;
185 			}
186 			else if (paxread(pax, ap, f->name + extdir, extname, 0, 1) != extname)
187 				break;
188 			else
189 				f->name[extdir + extname + 1] = 0;
190 			if (extdir)
191 			{
192 				if (paxread(pax, ap, f->name, extdir, 0, 1) != extdir)
193 					break;
194 				f->name[extdir - 1] = '/';
195 			}
196 		}
197 		else
198 			f->name = paxstash(pax, &ap->stash.head, name, 0);
199 		if (ext > n+2)
200 		{
201 			if (!(buf = paxget(pax, ap, 2, NiL)))
202 				break;
203 			system = swapget(3, buf, 2);
204 		}
205 		else
206 			system = 0;
207 		if (ext > n+4)
208 		{
209 			if (!(buf = paxget(pax, ap, 3, NiL)))
210 				break;
211 			mode = (buf[2] << 16) | (buf[1] << 8) | buf[0];
212 		}
213 		else
214 			mode = 0;
215 		if (ext > n+7 && !(buf = paxget(pax, ap, 3, NiL)))
216 			break;
217 		f->linkpath = 0;
218 		f->st->st_dev = 0;
219 		f->st->st_ino = 0;
220 		if (system == 0 || system == 2)
221 		{
222 			if (mode & 0x10)
223 				mode = X_IFDIR|X_IRUSR|X_IWUSR|X_IXUSR|X_IRGRP|X_IWGRP|X_IXGRP|X_IROTH|X_IWOTH|X_IXOTH;
224 			else if (mode & 0x01)
225 				mode = X_IFREG|X_IRUSR|X_IRGRP|X_IROTH;
226 			else
227 			{
228 				mode = X_IFREG|X_IRUSR|X_IWUSR|X_IRGRP|X_IWGRP|X_IROTH|X_IWOTH;
229 				if ((s = strrchr(f->name, '.')) && (s[1]=='e' || s[1]=='E') && (s[1]=='x' || s[1]=='X') && (s[1]=='e' || s[1]=='E'))
230 					mode |= X_IXUSR|X_IXGRP|X_IXOTH;
231 			}
232 		}
233 		f->st->st_mode = mode & pax->modemask;
234 		f->st->st_uid = pax->uid;
235 		f->st->st_gid = pax->gid;
236 		f->st->st_nlink = 1;
237 		IDEVICE(f->st, 0);
238 		memset(&tm, 0, sizeof(tm));
239 		tm.tm_year = ((dosdate >>  9) & 0x7f) + 80;
240 		tm.tm_mon =  ((dosdate >>  5) & 0x0f) - 1;
241 		tm.tm_mday = ((dosdate	    ) & 0x1f);
242 		tm.tm_hour = ((dostime >> 11) & 0x1f);
243 		tm.tm_min =  ((dostime >>  5) & 0x3f);
244 		tm.tm_sec =  ((dostime	    ) & 0x1f) * 2;
245 		if (doszone < 127)
246 			tm.tm_sec += 15 * 60 * doszone;
247 		else if (doszone > 127)
248 			tm.tm_sec += 15 * 60 * (doszone - 256);
249 		f->st->st_mtime = f->st->st_ctime = f->st->st_atime = tmtime(&tm, TM_LOCALZONE);
250 		return 1;
251 	}
252 	return paxcorrupt(pax, ap, f, NiL);
253 }
254 
255 static int
zoo_getdata(Pax_t * pax,register Paxarchive_t * ap,register Paxfile_t * f,int fd)256 zoo_getdata(Pax_t* pax, register Paxarchive_t* ap, register Paxfile_t* f, int fd)
257 {
258 	register Ar_t*	ar = (Ar_t*)ap->data;
259 	Sfio_t*		sp;
260 	ssize_t		n;
261 	int		r;
262 	int		pop;
263 	Codexdata_t	sum;
264 
265 	if (fd < 0 || !f->st->st_size)
266 		return 1;
267 	if (paxseek(pax, ap, ar->data, SEEK_SET, 0) != ar->data)
268 		return paxcorrupt(pax, ap, f, "cannot seek to data");
269 	if (!*ar->method || ar->majver > 2 || ar->majver == 2 && ar->minver > 1)
270 	{
271 		(*pax->errorf)(NiL, pax, 2, "%s: %s: cannot extract %s method=%d version=%d.%d data", ap->name, f->name, ap->format->name, ar->index, ar->majver, ar->minver);
272 		return -1;
273 	}
274 	r = -1;
275 	if (sp = paxpart(pax, ap, f->st->st_size))
276 	{
277 		if ((pop = codex(sp, NiL, ar->method, 0, &ar->codexdisc, NiL)) < 0)
278 			(*pax->errorf)(NiL, pax, 2, "%s: %s: cannot decode method %s", ap->name, f->name, ar->method);
279 		else
280 		{
281 			for (;;)
282 			{
283 				if ((n = sfread(sp, pax->buf, sizeof(pax->buf))) < 0)
284 				{
285 					(*pax->errorf)(NiL, pax, 2, "%s: %s: unexpected EOF", ap->name, f->name);
286 					break;
287 				}
288 				else if (n == 0)
289 				{
290 					if (codexdata(sp, &sum) <= 0)
291 						(*pax->errorf)(NiL, pax, 2, "%s: %s: checksum discipline error", ap->name, f->name);
292 					else if (!paxchecksum(pax, ap, f, ar->checksum, sum.num))
293 						r = 1;
294 					break;
295 				}
296 				if (paxdata(pax, ap, f, fd, pax->buf, n))
297 					break;
298 			}
299 			codexpop(sp, NiL, pop);
300 		}
301 	}
302 	return r;
303 }
304 
305 Paxformat_t	pax_zoo_format =
306 {
307 	"zoo",
308 	0,
309 	"zoo archive",
310 	0,
311 	PAX_ARCHIVE|PAX_DOS|PAX_NOHARDLINKS|PAX_IN,
312 	PAX_DEFBUFFER,
313 	PAX_DEFBLOCKS,
314 	0,
315 	PAXNEXT(zoo),
316 	0,
317 	zoo_done,
318 	zoo_getprologue,
319 	zoo_getheader,
320 	zoo_getdata,
321 };
322 
323 PAXLIB(zoo)
324