Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/paxlib/zip/zip.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 zip format
24
*/
25
26
#include <paxlib.h>
27
#include <codex.h>
28
#include <dt.h>
29
#include <swap.h>
30
#include <tm.h>
31
#include <vmalloc.h>
32
33
#define SUM "sum-crc-0xedb88320-init-done"
34
35
#define ZIP_HEADER 46 /* largest header size */
36
#define ZIP_COPY 0 /* no need to unzip */
37
38
#define ZIP_CEN_HEADER 46 /* central header size */
39
#define ZIP_CEN_MAGIC 0x504b0102L /* central header magic */
40
#define ZIP_CEN_VEM 4 /* version made by */
41
#define ZIP_CEN_VER 6 /* version needed to extract */
42
#define ZIP_CEN_FLG 8 /* encrypt, deflate flags */
43
#define ZIP_CEN_METHOD 10 /* compression method */
44
#define ZIP_CEN_TIM 12 /* DOS format modify time */
45
#define ZIP_CEN_DAT 14 /* DOS format modify date */
46
#define ZIP_CEN_CRC 16 /* uncompressed data crc-32 */
47
#define ZIP_CEN_SIZ 20 /* compressed data size */
48
#define ZIP_CEN_LEN 24 /* uncompressed data size */
49
#define ZIP_CEN_NAM 28 /* length of filename */
50
#define ZIP_CEN_EXT 30 /* length of extra field */
51
#define ZIP_CEN_COM 32 /* file comment length */
52
#define ZIP_CEN_DSK 34 /* disk number start */
53
#define ZIP_CEN_ATT 36 /* internal file attributes */
54
#define ZIP_CEN_ATX 38 /* external file attributes */
55
#define ZIP_CEN_OFF 42 /* local header relative offset */
56
57
#define ZIP_LOC_HEADER 30 /* local header size */
58
#define ZIP_LOC_MAGIC 0x504b0304L /* local header magic */
59
#define ZIP_LOC_VER 4 /* version needed to extract */
60
#define ZIP_LOC_FLG 6 /* encrypt, deflate flags */
61
#define ZIP_LOC_METHOD 8 /* compression method */
62
#define ZIP_LOC_TIM 10 /* DOS format modify time */
63
#define ZIP_LOC_DAT 12 /* DOS format modify date */
64
#define ZIP_LOC_CRC 14 /* uncompressed data crc-32 */
65
#define ZIP_LOC_SIZ 18 /* compressed data size */
66
#define ZIP_LOC_LEN 22 /* uncompressed data size */
67
#define ZIP_LOC_NAM 26 /* length of filename */
68
#define ZIP_LOC_EXT 28 /* length of extra field */
69
70
#define ZIP_END_HEADER 22 /* end header size */
71
#define ZIP_END_MAGIC 0x504b0506L /* end header magic */
72
#define ZIP_END_DSK 4 /* number of this disk */
73
#define ZIP_END_BEG 6 /* number of the starting disk */
74
#define ZIP_END_SUB 8 /* entries on this disk */
75
#define ZIP_END_TOT 10 /* total number of entries */
76
#define ZIP_END_SIZ 12 /* central directory total size */
77
#define ZIP_END_OFF 16 /* central offset starting disk */
78
#define ZIP_END_COM 20 /* length of zip file comment */
79
80
#define ZIP_EXT_HEADER 16 /* ext header size */
81
#define ZIP_EXT_MAGIC 0x504b0708L /* ext header magic */
82
#define ZIP_EXT_SIZ 8 /* compressed data size */
83
#define ZIP_EXT_LEN 12 /* uncompressed data size */
84
85
typedef struct Ar_s
86
{
87
Codexdisc_t codexdisc;
88
Dtdisc_t memdisc;
89
Pax_t* pax;
90
Paxarchive_t* ap;
91
char method[128];
92
unsigned int index;
93
unsigned long checksum;
94
off_t end;
95
Dt_t* mem;
96
Vmalloc_t* vm;
97
} Ar_t;
98
99
typedef struct Mem_s
100
{
101
Dtlink_t link;
102
off_t encoded;
103
off_t decoded;
104
unsigned long checksum;
105
char name[1];
106
} Mem_t;
107
108
static int
109
zip_done(Pax_t* pax, register Paxarchive_t* ap)
110
{
111
register Ar_t* ar = (Ar_t*)ap->data;
112
113
if (!ar || !ar->vm)
114
return -1;
115
vmclose(ar->vm);
116
ap->data = 0;
117
return 0;
118
}
119
120
static int
121
zip_getprologue(Pax_t* pax, Paxformat_t* fp, register Paxarchive_t* ap, Paxfile_t* f, unsigned char* buf, size_t size)
122
{
123
register Ar_t* ar;
124
unsigned long magic;
125
unsigned char* hdr;
126
int n;
127
int ext;
128
int com;
129
off_t pos;
130
Mem_t* mem;
131
Vmalloc_t* vm;
132
133
if (size < ZIP_LOC_HEADER || (magic = (unsigned long)swapget(0, buf, 4)) != ZIP_LOC_MAGIC && magic != ZIP_CEN_MAGIC)
134
return 0;
135
if (!(vm = vmopen(Vmdcheap, Vmbest, 0)))
136
return paxnospace(pax);
137
if (!(ar = vmnewof(vm, 0, Ar_t, 1, 0)))
138
{
139
vmclose(vm);
140
return paxnospace(pax);
141
}
142
ap->data = ar;
143
ar->vm = vm;
144
ar->memdisc.key = offsetof(Mem_t, name);
145
if (paxseek(pax, ap, -(off_t)ZIP_END_HEADER, SEEK_END, 1) > 0 &&
146
(hdr = paxget(pax, ap, ZIP_END_HEADER, NiL)) &&
147
swapget(0, &hdr[0], 4) == ZIP_END_MAGIC)
148
{
149
if (!(ar->mem = dtnew(ar->vm, &ar->memdisc, Dtset)))
150
{
151
zip_done(pax, ap);
152
return paxnospace(pax);
153
}
154
pos = swapget(3, &hdr[ZIP_END_OFF], 4);
155
if (paxseek(pax, ap, pos, SEEK_SET, 1) != pos)
156
{
157
(*pax->errorf)(NiL, pax, 2, "%s: %s central header seek error", ap->name, fp->name);
158
zip_done(pax, ap);
159
return -1;
160
}
161
ar->end = pos;
162
while ((hdr = paxget(pax, ap, -ZIP_CEN_HEADER, NiL)) && swapget(0, &hdr[0], 4) == ZIP_CEN_MAGIC)
163
{
164
n = swapget(3, &hdr[ZIP_CEN_NAM], 2);
165
if (!(mem = vmnewof(ar->vm, 0, Mem_t, 1, n)))
166
{
167
zip_done(pax, ap);
168
return paxnospace(pax);
169
}
170
mem->encoded = swapget(3, &hdr[ZIP_CEN_SIZ], 4);
171
mem->decoded = swapget(3, &hdr[ZIP_CEN_LEN], 4);
172
mem->checksum = swapget(3, &hdr[ZIP_CEN_CRC], 4);
173
ext = swapget(3, &hdr[ZIP_CEN_EXT], 2);
174
com = swapget(3, &hdr[ZIP_CEN_COM], 2);
175
if (paxread(pax, ap, mem->name, (off_t)n, (off_t)0, 0) <= 0)
176
{
177
(*pax->errorf)(NiL, pax, 2, "%s: invalid %s format verification header name [size=%I*u]", ap->name, fp->name, sizeof(n), n);
178
zip_done(pax, ap);
179
return -1;
180
}
181
if (mem->name[n - 1] == '/')
182
n--;
183
mem->name[n] = 0;
184
if (ext && paxread(pax, ap, NiL, (off_t)ext, (off_t)0, 0) <= 0)
185
{
186
(*pax->errorf)(NiL, pax, 2, "%s: %s: invalid %s format verification header extended data [size=%I*u]", ap->name, mem->name, fp->name, sizeof(ext), ext);
187
zip_done(pax, ap);
188
return -1;
189
}
190
if (com && paxread(pax, ap, NiL, (off_t)com, (off_t)0, 0) <= 0)
191
{
192
(*pax->errorf)(NiL, pax, 2, "%s: %s: invalid %s format verification header comment data [size=%I*u]", ap->name, mem->name, fp->name, sizeof(com), com);
193
zip_done(pax, ap);
194
return -1;
195
}
196
dtinsert(ar->mem, mem);
197
}
198
if (paxseek(pax, ap, (off_t)0, SEEK_SET, 1))
199
{
200
(*pax->errorf)(NiL, pax, 2, "%s: %s central header reposition error", ap->name, fp->name);
201
zip_done(pax, ap);
202
return -1;
203
}
204
}
205
ar->pax = pax;
206
ar->ap = ap;
207
codexinit(&ar->codexdisc, pax->errorf);
208
return 1;
209
}
210
211
static int
212
zip_getheader(Pax_t* pax, register Paxarchive_t* ap, register Paxfile_t* f)
213
{
214
register Ar_t* ar = (Ar_t*)ap->data;
215
unsigned char* hdr;
216
Mem_t* mem;
217
long n;
218
ssize_t num;
219
int i;
220
int m;
221
Tm_t tm;
222
223
while (hdr = paxget(pax, ap, -(num = ZIP_LOC_HEADER), NiL))
224
{
225
switch ((long)swapget(0, hdr, 4))
226
{
227
case ZIP_LOC_MAGIC:
228
n = swapget(3, &hdr[ZIP_LOC_NAM], 2);
229
m = swapget(3, &hdr[ZIP_LOC_EXT], 2);
230
paxunread(pax, ap, hdr, num);
231
num += n + m;
232
if (!(hdr = paxget(pax, ap, -num, NiL)))
233
break;
234
f->name = paxstash(pax, &ap->stash.head, NiL, n);
235
memcpy(f->name, hdr + ZIP_LOC_HEADER, n);
236
if (n > 0 && f->name[n - 1] == '/' || !n && f->name[0] == '/')
237
{
238
if (n)
239
n--;
240
f->st->st_mode = (X_IFDIR|X_IRUSR|X_IWUSR|X_IXUSR|X_IRGRP|X_IWGRP|X_IXGRP|X_IROTH|X_IWOTH|X_IXOTH);
241
}
242
else
243
f->st->st_mode = (X_IFREG|X_IRUSR|X_IWUSR|X_IRGRP|X_IWGRP|X_IROTH|X_IWOTH);
244
f->st->st_mode &= pax->modemask;
245
f->name[n] = 0;
246
f->st->st_dev = 0;
247
f->st->st_ino = 0;
248
f->st->st_uid = pax->uid;
249
f->st->st_gid = pax->gid;
250
f->st->st_nlink = 1;
251
IDEVICE(f->st, 0);
252
n = swapget(3, &hdr[ZIP_LOC_TIM], 4);
253
memset(&tm, 0, sizeof(tm));
254
tm.tm_year = ((n>>25)&0377) + 80;
255
tm.tm_mon = ((n>>21)&017) - 1;
256
tm.tm_mday = ((n>>16)&037);
257
tm.tm_hour = ((n>>11)&037);
258
tm.tm_min = ((n>>5)&077);
259
tm.tm_sec = ((n<<1)&037);
260
f->st->st_mtime = tmtime(&tm, TM_LOCALZONE);
261
f->linktype = PAX_NOLINK;
262
f->linkpath = 0;
263
if (ar->mem && (mem = (Mem_t*)dtmatch(ar->mem, f->name)))
264
{
265
f->st->st_size = mem->encoded;
266
f->uncompressed = mem->decoded;
267
ar->checksum = mem->checksum;
268
}
269
else
270
{
271
f->st->st_size = swapget(3, &hdr[ZIP_LOC_SIZ], 4);
272
f->uncompressed = swapget(3, &hdr[ZIP_LOC_LEN], 4);
273
ar->checksum = swapget(3, &hdr[ZIP_LOC_CRC], 4);
274
}
275
i = 0;
276
if (swapget(3, &hdr[ZIP_LOC_FLG], 2) & 0x0001)
277
i += sfsprintf(ar->method, sizeof(ar->method), "crypt-zip+SIZE=%I*u|", sizeof(f->st->st_size), f->st->st_size);
278
if (!f->st->st_size || (m = swapget(3, &hdr[ZIP_LOC_METHOD], 2)) == ZIP_COPY || (pax->test & 2))
279
i += sfsprintf(ar->method + i, sizeof(ar->method) - i, "copy");
280
else
281
i += sfsprintf(ar->method + i, sizeof(ar->method) - i, "zip-%u+SIZE=%I*u", m, sizeof(f->uncompressed), f->uncompressed);
282
sfsprintf(ar->method + i, sizeof(ar->method) - i, "|%s", SUM);
283
if (error_info.trace)
284
(*pax->errorf)(NiL, pax, -1, "archive=%s name=%s method=%s", ap->name, f->name, ar->method);
285
return 1;
286
case ZIP_EXT_MAGIC:
287
paxunread(pax, ap, hdr, num);
288
if (paxread(pax, ap, NiL, (off_t)ZIP_EXT_HEADER, (off_t)0, 0) <= 0)
289
{
290
(*pax->errorf)(NiL, pax, 2, "%s: invalid %s format verification header", ap->name, ap->format->name);
291
return 0;
292
}
293
break;
294
default:
295
paxunread(pax, ap, hdr, num);
296
if (paxseek(pax, ap, (off_t)0, SEEK_CUR, 0) == ar->end)
297
paxseek(pax, ap, (off_t)0, SEEK_END, 1);
298
return 0;
299
}
300
}
301
return 0;
302
}
303
304
static int
305
zip_getdata(Pax_t* pax, register Paxarchive_t* ap, register Paxfile_t* f, int fd)
306
{
307
register Ar_t* ar = (Ar_t*)ap->data;
308
Sfio_t* sp;
309
off_t pos;
310
ssize_t n;
311
int r;
312
int pop;
313
Codexdata_t sum;
314
315
if (!f->st->st_size)
316
return 1;
317
pos = paxseek(pax, ap, 0, SEEK_CUR, 0) + f->st->st_size;
318
r = -1;
319
if (fd < 0)
320
r = 1;
321
else if (sp = paxpart(pax, ap, f->st->st_size))
322
{
323
if ((pop = codex(sp, NiL, ar->method, 0, &ar->codexdisc, NiL)) < 0)
324
(*pax->errorf)(NiL, pax, 2, "%s: %s: cannot decode method %s", ap->name, f->name, ar->method);
325
else
326
{
327
for (;;)
328
{
329
if ((n = sfread(sp, pax->buf, sizeof(pax->buf))) < 0)
330
{
331
(*pax->errorf)(NiL, pax, 2, "%s: %s: unexpected EOF", ap->name, f->name);
332
break;
333
}
334
else if (n == 0)
335
{
336
if (codexdata(sp, &sum) <= 0)
337
(*pax->errorf)(NiL, pax, 2, "%s: %s: checksum discipline error", ap->name, f->name);
338
else if (!paxchecksum(pax, ap, f, ar->checksum, sum.num))
339
r = 1;
340
break;
341
}
342
if (paxdata(pax, ap, f, fd, pax->buf, n))
343
break;
344
}
345
codexpop(sp, NiL, pop);
346
}
347
}
348
if (paxseek(pax, ap, pos, SEEK_SET, 0) != pos)
349
{
350
(*pax->errorf)(NiL, pax, 2, "%s: %s: cannot seek past %s format data", ap->name, f->name, ap->format->name);
351
r = -1;
352
}
353
return r;
354
}
355
356
Paxformat_t pax_zip_format =
357
{
358
"zip",
359
0,
360
"zip 2.1 / PKZIP 2.04g archive.",
361
0,
362
PAX_ARCHIVE|PAX_DOS|PAX_NOHARDLINKS|PAX_KEEPSIZE|PAX_IN,
363
PAX_DEFBUFFER,
364
PAX_DEFBLOCKS,
365
0,
366
PAXNEXT(zip),
367
0,
368
zip_done,
369
zip_getprologue,
370
zip_getheader,
371
zip_getdata,
372
};
373
374
PAXLIB(zip)
375
376