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