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