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 arj format
24  */
25 
26 #include <paxlib.h>
27 #include <codex.h>
28 #include <swap.h>
29 #include <tm.h>
30 
31 #define MAGIC			0xea60
32 
33 #define SUM			"sum-crc-0xedb88320-init-done"
34 
35 typedef struct Ar_s
36 {
37 	Codexdisc_t		codexdisc;
38 	Pax_t*			pax;
39 	Paxarchive_t*		ap;
40 	Sfio_t*			sum;
41 	char			method[64];
42 	unsigned int		index;
43 	unsigned long		checksum;
44 
45 	unsigned char		system;
46 	unsigned char		type;
47 } Ar_t;
48 
49 static int
arj_done(Pax_t * pax,register Paxarchive_t * ap)50 arj_done(Pax_t* pax, register Paxarchive_t* ap)
51 {
52 	register Ar_t*	ar = (Ar_t*)ap->data;
53 
54 	if (!ar)
55 		return -1;
56 	if (ar->sum)
57 		sfdisc(ar->sum, SF_POPDISC);
58 	free(ar);
59 	ap->data = 0;
60 	return 0;
61 }
62 
63 static int
arj_getprologue(Pax_t * pax,Paxformat_t * fp,register Paxarchive_t * ap,Paxfile_t * f,unsigned char * buf,size_t size)64 arj_getprologue(Pax_t* pax, Paxformat_t* fp, register Paxarchive_t* ap, Paxfile_t* f, unsigned char* buf, size_t size)
65 {
66 	register Ar_t*	ar;
67 	register char*	s;
68 	int		n;
69 	int		r;
70 	uint32_t	checksum;
71 	Codexdata_t	sum;
72 
73 	if (size < 4 || swapget(3, buf, 2) != MAGIC || size < ((n = swapget(3, buf+2, 2)) + 8) || n > 2600)
74 		return 0;
75 	if (!(ar = newof(0, Ar_t, 1, 0)))
76 		return paxnospace(pax);
77 	ar->pax = pax;
78 	ar->ap = ap;
79 	ap->data = ar;
80 	codexinit(&ar->codexdisc, pax->errorf);
81 	r = -1;
82 	if (!(ar->sum = codexnull()) || codex(ar->sum, NiL, SUM, 0, &ar->codexdisc, NiL) <= 0)
83 	{
84 		ar->sum = 0;
85 		goto bad;
86 	}
87 	sfwrite(ar->sum, buf + 4, n);
88 	codexdata(ar->sum, &sum);
89 	checksum = swapget(3, buf + 4 + n, 4);
90 	if (checksum != sum.num)
91 	{
92 		r = 0;
93 		goto bad;
94 	}
95 	if (paxseek(pax, ap, n + 8, SEEK_SET, 0) < 0)
96 		goto bad;
97 	while ((s = paxget(pax, ap, 2, NiL)) && (n = swapget(3, s, 2)))
98 		if (paxseek(pax, ap, n + 2, SEEK_CUR, 0) < 0)
99 			goto bad;
100 	return 1;
101  bad:
102 	arj_done(pax, ap);
103 	return r;
104 }
105 
106 static int
arj_getheader(Pax_t * pax,register Paxarchive_t * ap,register Paxfile_t * f)107 arj_getheader(Pax_t* pax, register Paxarchive_t* ap, register Paxfile_t* f)
108 {
109 	register Ar_t*		ar = (Ar_t*)ap->data;
110 	register unsigned char*	buf;
111 	char*			s;
112 	Tm_t			tm;
113 	unsigned long		dostime;
114 	long			n;
115 	int			mode;
116 	uint32_t		checksum;
117 	Codexdata_t		sum;
118 
119 	for (;;)
120 	{
121 		if (!(buf = (unsigned char*)paxget(pax, ap, -4, NiL)) || !(n = swapget(3, buf+2, 2)))
122 			return 0;
123 		if (n < 32 || n > 2600 || swapget(3, buf, 2) != MAGIC || !(buf = (unsigned char*)paxget(pax, ap, n + 4, NiL)))
124 			break;
125 		sfsync(ar->sum);
126 		sfwrite(ar->sum, buf, n);
127 		codexdata(ar->sum, &sum);
128 		checksum = swapget(3, buf + n, 4);
129 		if (checksum != sum.num)
130 			break;
131 		ar->system = buf[3];
132 		ar->type = buf[4];
133 		dostime = swapget(3, buf+8, 4);
134 		f->st->st_size = swapget(3, buf+12, 4);
135 		f->uncompressed = swapget(3, buf+16, 4);
136 		switch (ar->index = buf[5])
137 		{
138 		case 0:
139 			sfsprintf(ar->method, sizeof(ar->method), "copy|%s", SUM);
140 			break;
141 		case 1:
142 		case 2:
143 		case 3:
144 			sfsprintf(ar->method, sizeof(ar->method), "lzh-26624-s1+SIZE=%I*u|%s", sizeof(f->uncompressed), f->uncompressed, SUM);
145 			break;
146 		default:
147 			*ar->method = 0;
148 			break;
149 		}
150 		ar->checksum = swapget(3, buf+20, 4);
151 		mode = swapget(3, buf+26, 2);
152 		s = (char*)buf + buf[0];
153 		f->name = paxstash(pax, &ap->stash.head, NiL, strlen(s) + 1);
154 		strcpy(f->name, s);
155 		while ((s = paxget(pax, ap, 2, NiL)) && (n = swapget(3, s, 2)))
156 			if (paxseek(pax, ap, n + 4, SEEK_CUR, 0) < 0)
157 				goto bad;
158 		f->linkpath = 0;
159 		f->st->st_dev = 0;
160 		f->st->st_ino = 0;
161 		if (ar->system != 3)
162 		{
163 			if (mode & 0x10)
164 				mode = X_IFDIR|X_IRUSR|X_IWUSR|X_IXUSR|X_IRGRP|X_IWGRP|X_IXGRP|X_IROTH|X_IWOTH|X_IXOTH;
165 			else if (mode & 0x01)
166 				mode = X_IFREG|X_IRUSR|X_IRGRP|X_IROTH;
167 			else
168 			{
169 				mode = X_IFREG|X_IRUSR|X_IWUSR|X_IRGRP|X_IWGRP|X_IROTH|X_IWOTH;
170 				if ((s = strrchr(f->name, '.')) && (s[1]=='e' || s[1]=='E') && (s[1]=='x' || s[1]=='X') && (s[1]=='e' || s[1]=='E'))
171 					mode |= X_IXUSR|X_IXGRP|X_IXOTH;
172 			}
173 		}
174 		f->st->st_mode = mode & pax->modemask;
175 		f->st->st_uid = pax->uid;
176 		f->st->st_gid = pax->gid;
177 		f->st->st_nlink = 1;
178 		IDEVICE(f->st, 0);
179 		memset(&tm, 0, sizeof(tm));
180 		tm.tm_year  = ((dostime >> (16+9)) & 0x7f) + 80;
181 		tm.tm_mon   = ((dostime >> (16+5)) & 0x0f) - 1;
182 		tm.tm_mday  = ((dostime >> (16+0)) & 0x1f);
183 		tm.tm_hour  = ((dostime >>     11) & 0x1f);
184 		tm.tm_min   = ((dostime >>      5) & 0x3f);
185 		tm.tm_sec   = ((dostime          ) & 0x1f) * 2;
186 		f->st->st_mtime = f->st->st_ctime = f->st->st_atime = tmtime(&tm, TM_LOCALZONE);
187 		return 1;
188 	}
189  bad:
190 	return paxcorrupt(pax, ap, f, NiL);
191 }
192 
193 static int
arj_getdata(Pax_t * pax,register Paxarchive_t * ap,register Paxfile_t * f,int fd)194 arj_getdata(Pax_t* pax, register Paxarchive_t* ap, register Paxfile_t* f, int fd)
195 {
196 	register Ar_t*	ar = (Ar_t*)ap->data;
197 	Sfio_t*		sp;
198 	off_t		pos;
199 	ssize_t		n;
200 	int		r;
201 	int		pop;
202 	Codexdata_t	sum;
203 
204 	if (!(n = f->st->st_size))
205 		return 1;
206 	pos = paxseek(pax, ap, 0, SEEK_CUR, 0) + f->st->st_size;
207 	r = -1;
208 	if (fd < 0)
209 		r = 1;
210 	else if (sp = paxpart(pax, ap, f->st->st_size))
211 	{
212 		if (!*ar->method || (pop = codex(sp, NiL, ar->method, 0, &ar->codexdisc, NiL)) < 0)
213 			(*pax->errorf)(NiL, pax, 2, "%s: %s: cannot decode method %d", ap->name, f->name, ar->index);
214 		else
215 		{
216 			for (;;)
217 			{
218 				if ((n = sfread(sp, pax->buf, sizeof(pax->buf))) < 0)
219 				{
220 					(*pax->errorf)(NiL, pax, 2, "%s: %s: unexpected EOF", ap->name, f->name);
221 					break;
222 				}
223 				else if (n == 0)
224 				{
225 					if (codexdata(sp, &sum) <= 0)
226 						(*pax->errorf)(NiL, pax, 2, "%s: %s: checksum discipline error", ap->name, f->name);
227 					else if (!paxchecksum(pax, ap, f, ar->checksum, sum.num))
228 						r = 1;
229 					break;
230 				}
231 				if (paxdata(pax, ap, f, fd, pax->buf, n))
232 					break;
233 			}
234 			codexpop(sp, NiL, pop);
235 		}
236 	}
237 	if (paxseek(pax, ap, pos, SEEK_SET, 0) != pos)
238 	{
239 		(*pax->errorf)(NiL, pax, 2, "%s: %s: cannot seek past %s format data", ap->name, f->name, ap->format->name);
240 		r = -1;
241 	}
242 	return r;
243 }
244 
245 Paxformat_t	pax_arj_format =
246 {
247 	"arj",
248 	0,
249 	"arj archive",
250 	0,
251 	PAX_ARCHIVE|PAX_DOS|PAX_NOHARDLINKS|PAX_IN,
252 	PAX_DEFBUFFER,
253 	PAX_DEFBLOCKS,
254 	0,
255 	PAXNEXT(arj),
256 	0,
257 	arj_done,
258 	arj_getprologue,
259 	arj_getheader,
260 	arj_getdata,
261 };
262 
263 PAXLIB(arj)
264