Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/paxlib/rar/rar.c
1810 views
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 <[email protected]> *
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
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
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
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
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
278