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