Annotation of embedaddon/php/ext/zip/lib/zip_dirent.c, revision 1.1.1.2
1.1 misho 1: /*
2: zip_dirent.c -- read directory entry (local or central), clean dirent
3: Copyright (C) 1999-2009 Dieter Baron and Thomas Klausner
4:
5: This file is part of libzip, a library to manipulate ZIP archives.
6: The authors can be contacted at <libzip@nih.at>
7:
8: Redistribution and use in source and binary forms, with or without
9: modification, are permitted provided that the following conditions
10: are met:
11: 1. Redistributions of source code must retain the above copyright
12: notice, this list of conditions and the following disclaimer.
13: 2. Redistributions in binary form must reproduce the above copyright
14: notice, this list of conditions and the following disclaimer in
15: the documentation and/or other materials provided with the
16: distribution.
17: 3. The names of the authors may not be used to endorse or promote
18: products derived from this software without specific prior
19: written permission.
20:
21: THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
22: OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23: WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24: ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
25: DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27: GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28: INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
29: IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30: OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
31: IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32: */
33:
34:
35:
36: #include <stdio.h>
37: #include <stdlib.h>
38: #include <string.h>
39: #include <errno.h>
40: #include <sys/types.h>
41: #include <sys/stat.h>
42:
43: #include "zipint.h"
44:
45: static time_t _zip_d2u_time(int, int);
46: static char *_zip_readfpstr(FILE *, unsigned int, int, struct zip_error *);
47: static char *_zip_readstr(unsigned char **, int, int, struct zip_error *);
48: static void _zip_write2(unsigned short, FILE *);
49: static void _zip_write4(unsigned int, FILE *);
50:
51:
52:
53: void
54: _zip_cdir_free(struct zip_cdir *cd)
55: {
56: int i;
57:
58: if (!cd)
59: return;
60:
61: for (i=0; i<cd->nentry; i++)
62: _zip_dirent_finalize(cd->entry+i);
63: free(cd->comment);
64: free(cd->entry);
65: free(cd);
66: }
67:
68:
69:
70: int
71: _zip_cdir_grow(struct zip_cdir *cd, int nentry, struct zip_error *error)
72: {
73: struct zip_dirent *entry;
74:
75: if (nentry < cd->nentry) {
76: _zip_error_set(error, ZIP_ER_INTERNAL, 0);
77: return -1;
78: }
79:
80: if ((entry=((struct zip_dirent *)
81: realloc(cd->entry, sizeof(*(cd->entry))*nentry))) == NULL) {
82: _zip_error_set(error, ZIP_ER_MEMORY, 0);
83: return -1;
84: }
85:
86: cd->nentry = nentry;
87: cd->entry = entry;
88:
89: return 0;
90: }
91:
92:
93:
94: struct zip_cdir *
95: _zip_cdir_new(int nentry, struct zip_error *error)
96: {
97: struct zip_cdir *cd;
98:
99: if ((cd=(struct zip_cdir *)malloc(sizeof(*cd))) == NULL) {
100: _zip_error_set(error, ZIP_ER_MEMORY, 0);
101: return NULL;
102: }
103:
104: if ((cd->entry=(struct zip_dirent *)malloc(sizeof(*(cd->entry))*nentry))
105: == NULL) {
106: _zip_error_set(error, ZIP_ER_MEMORY, 0);
107: free(cd);
108: return NULL;
109: }
110:
111: /* entries must be initialized by caller */
112:
113: cd->nentry = nentry;
114: cd->size = cd->offset = 0;
115: cd->comment = NULL;
116: cd->comment_len = 0;
117:
118: return cd;
119: }
120:
121:
122:
123: int
124: _zip_cdir_write(struct zip_cdir *cd, FILE *fp, struct zip_error *error)
125: {
126: int i;
127:
128: cd->offset = ftello(fp);
129:
130: for (i=0; i<cd->nentry; i++) {
131: if (_zip_dirent_write(cd->entry+i, fp, 0, error) != 0)
132: return -1;
133: }
134:
135: cd->size = ftello(fp) - cd->offset;
136:
137: /* clearerr(fp); */
138: fwrite(EOCD_MAGIC, 1, 4, fp);
139: _zip_write4(0, fp);
140: _zip_write2((unsigned short)cd->nentry, fp);
141: _zip_write2((unsigned short)cd->nentry, fp);
142: _zip_write4(cd->size, fp);
143: _zip_write4(cd->offset, fp);
144: _zip_write2(cd->comment_len, fp);
145: fwrite(cd->comment, 1, cd->comment_len, fp);
146:
147: if (ferror(fp)) {
148: _zip_error_set(error, ZIP_ER_WRITE, errno);
149: return -1;
150: }
151:
152: return 0;
153: }
154:
155:
156:
157: void
158: _zip_dirent_finalize(struct zip_dirent *zde)
159: {
1.1.1.2 ! misho 160: if (zde->filename_len > 0) {
! 161: free(zde->filename);
! 162: }
1.1 misho 163: zde->filename = NULL;
1.1.1.2 ! misho 164: if (zde->extrafield_len > 0) {
! 165: free(zde->extrafield);
! 166: }
1.1 misho 167: zde->extrafield = NULL;
1.1.1.2 ! misho 168: if (zde->comment_len > 0) {
! 169: free(zde->comment);
! 170: }
1.1 misho 171: zde->comment = NULL;
172: }
173:
174:
175:
176: void
177: _zip_dirent_init(struct zip_dirent *de)
178: {
179: de->version_madeby = 0;
180: de->version_needed = 20; /* 2.0 */
181: de->bitflags = 0;
182: de->comp_method = 0;
183: de->last_mod = 0;
184: de->crc = 0;
185: de->comp_size = 0;
186: de->uncomp_size = 0;
187: de->filename = NULL;
188: de->filename_len = 0;
189: de->extrafield = NULL;
190: de->extrafield_len = 0;
191: de->comment = NULL;
192: de->comment_len = 0;
193: de->disk_number = 0;
194: de->int_attrib = 0;
195: de->ext_attrib = 0;
196: de->offset = 0;
197: }
198:
199:
200:
201: /* _zip_dirent_read(zde, fp, bufp, left, localp, error):
202: Fills the zip directory entry zde.
203:
204: If bufp is non-NULL, data is taken from there and bufp is advanced
205: by the amount of data used; otherwise data is read from fp as needed.
206:
207: if leftp is non-NULL, no more bytes than specified by it are used,
208: and *leftp is reduced by the number of bytes used.
209:
210: If local != 0, it reads a local header instead of a central
211: directory entry.
212:
213: Returns 0 if successful. On error, error is filled in and -1 is
214: returned.
215:
216: XXX: leftp and file position undefined on error.
217: */
218:
219: int
220: _zip_dirent_read(struct zip_dirent *zde, FILE *fp,
1.1.1.2 ! misho 221: unsigned char **bufp, zip_uint32_t *leftp, int local,
1.1 misho 222: struct zip_error *error)
223: {
224: unsigned char buf[CDENTRYSIZE];
225: unsigned char *cur;
226: unsigned short dostime, dosdate;
1.1.1.2 ! misho 227: zip_uint32_t size;
1.1 misho 228:
229: if (local)
230: size = LENTRYSIZE;
231: else
232: size = CDENTRYSIZE;
233:
234: if (leftp && (*leftp < size)) {
235: _zip_error_set(error, ZIP_ER_NOZIP, 0);
236: return -1;
237: }
238:
239: if (bufp) {
240: /* use data from buffer */
241: cur = *bufp;
242: }
243: else {
244: /* read entry from disk */
245: if ((fread(buf, 1, size, fp)<size)) {
246: _zip_error_set(error, ZIP_ER_READ, errno);
247: return -1;
248: }
249: cur = buf;
250: }
251:
252: if (memcmp(cur, (local ? LOCAL_MAGIC : CENTRAL_MAGIC), 4) != 0) {
253: _zip_error_set(error, ZIP_ER_NOZIP, 0);
254: return -1;
255: }
256: cur += 4;
257:
258:
259: /* convert buffercontents to zip_dirent */
260:
261: if (!local)
262: zde->version_madeby = _zip_read2(&cur);
263: else
264: zde->version_madeby = 0;
265: zde->version_needed = _zip_read2(&cur);
266: zde->bitflags = _zip_read2(&cur);
267: zde->comp_method = _zip_read2(&cur);
268:
269: /* convert to time_t */
270: dostime = _zip_read2(&cur);
271: dosdate = _zip_read2(&cur);
272: zde->last_mod = _zip_d2u_time(dostime, dosdate);
273:
274: zde->crc = _zip_read4(&cur);
275: zde->comp_size = _zip_read4(&cur);
276: zde->uncomp_size = _zip_read4(&cur);
277:
278: zde->filename_len = _zip_read2(&cur);
279: zde->extrafield_len = _zip_read2(&cur);
280:
281: if (local) {
282: zde->comment_len = 0;
283: zde->disk_number = 0;
284: zde->int_attrib = 0;
285: zde->ext_attrib = 0;
286: zde->offset = 0;
287: } else {
288: zde->comment_len = _zip_read2(&cur);
289: zde->disk_number = _zip_read2(&cur);
290: zde->int_attrib = _zip_read2(&cur);
291: zde->ext_attrib = _zip_read4(&cur);
292: zde->offset = _zip_read4(&cur);
293: }
294:
295: zde->filename = NULL;
296: zde->extrafield = NULL;
297: zde->comment = NULL;
298:
299: size += zde->filename_len+zde->extrafield_len+zde->comment_len;
300:
301: if (leftp && (*leftp < size)) {
302: _zip_error_set(error, ZIP_ER_NOZIP, 0);
303: return -1;
304: }
305:
306: if (bufp) {
307: if (zde->filename_len) {
308: zde->filename = _zip_readstr(&cur, zde->filename_len, 1, error);
309: if (!zde->filename)
310: return -1;
311: }
312:
313: if (zde->extrafield_len) {
314: zde->extrafield = _zip_readstr(&cur, zde->extrafield_len, 0,
315: error);
316: if (!zde->extrafield)
317: return -1;
318: }
319:
320: if (zde->comment_len) {
321: zde->comment = _zip_readstr(&cur, zde->comment_len, 0, error);
322: if (!zde->comment)
323: return -1;
324: }
325: }
326: else {
327: if (zde->filename_len) {
328: zde->filename = _zip_readfpstr(fp, zde->filename_len, 1, error);
329: if (!zde->filename)
330: return -1;
331: }
332:
333: if (zde->extrafield_len) {
334: zde->extrafield = _zip_readfpstr(fp, zde->extrafield_len, 0,
335: error);
336: if (!zde->extrafield)
337: return -1;
338: }
339:
340: if (zde->comment_len) {
341: zde->comment = _zip_readfpstr(fp, zde->comment_len, 0, error);
342: if (!zde->comment)
343: return -1;
344: }
345: }
346:
347: if (bufp)
348: *bufp = cur;
349: if (leftp)
350: *leftp -= size;
351:
352: return 0;
353: }
354:
355:
356:
357: /* _zip_dirent_torrent_normalize(de);
358: Set values suitable for torrentzip.
359: */
360:
361: void
362: _zip_dirent_torrent_normalize(struct zip_dirent *de)
363: {
364: static struct tm torrenttime;
365: static time_t last_mod = 0;
366:
367: if (last_mod == 0) {
368: #ifdef HAVE_STRUCT_TM_TM_ZONE
369: time_t now;
370: struct tm *l;
371: #endif
372:
373: torrenttime.tm_sec = 0;
374: torrenttime.tm_min = 32;
375: torrenttime.tm_hour = 23;
376: torrenttime.tm_mday = 24;
377: torrenttime.tm_mon = 11;
378: torrenttime.tm_year = 96;
379: torrenttime.tm_wday = 0;
380: torrenttime.tm_yday = 0;
381: torrenttime.tm_isdst = 0;
382:
383: #ifdef HAVE_STRUCT_TM_TM_ZONE
384: time(&now);
385: l = localtime(&now);
386: torrenttime.tm_gmtoff = l->tm_gmtoff;
387: torrenttime.tm_zone = l->tm_zone;
388: #endif
389:
390: last_mod = mktime(&torrenttime);
391: }
392:
393: de->version_madeby = 0;
394: de->version_needed = 20; /* 2.0 */
395: de->bitflags = 2; /* maximum compression */
396: de->comp_method = ZIP_CM_DEFLATE;
397: de->last_mod = last_mod;
398:
399: de->disk_number = 0;
400: de->int_attrib = 0;
401: de->ext_attrib = 0;
402: de->offset = 0;
403:
404: free(de->extrafield);
405: de->extrafield = NULL;
406: de->extrafield_len = 0;
407: free(de->comment);
408: de->comment = NULL;
409: de->comment_len = 0;
410: }
411:
412:
413:
414: /* _zip_dirent_write(zde, fp, localp, error):
415: Writes zip directory entry zde to file fp.
416:
417: If localp != 0, it writes a local header instead of a central
418: directory entry.
419:
420: Returns 0 if successful. On error, error is filled in and -1 is
421: returned.
422: */
423:
424: int
425: _zip_dirent_write(struct zip_dirent *zde, FILE *fp, int localp,
426: struct zip_error *error)
427: {
428: unsigned short dostime, dosdate;
429:
430: fwrite(localp ? LOCAL_MAGIC : CENTRAL_MAGIC, 1, 4, fp);
431:
432: if (!localp)
433: _zip_write2(zde->version_madeby, fp);
434: _zip_write2(zde->version_needed, fp);
435: _zip_write2(zde->bitflags, fp);
436: _zip_write2(zde->comp_method, fp);
437:
438: _zip_u2d_time(zde->last_mod, &dostime, &dosdate);
439: _zip_write2(dostime, fp);
440: _zip_write2(dosdate, fp);
441:
442: _zip_write4(zde->crc, fp);
443: _zip_write4(zde->comp_size, fp);
444: _zip_write4(zde->uncomp_size, fp);
445:
446: _zip_write2(zde->filename_len, fp);
447: _zip_write2(zde->extrafield_len, fp);
448:
449: if (!localp) {
450: _zip_write2(zde->comment_len, fp);
451: _zip_write2(zde->disk_number, fp);
452: _zip_write2(zde->int_attrib, fp);
453: _zip_write4(zde->ext_attrib, fp);
454: _zip_write4(zde->offset, fp);
455: }
456:
457: if (zde->filename_len)
458: fwrite(zde->filename, 1, zde->filename_len, fp);
459:
460: if (zde->extrafield_len)
461: fwrite(zde->extrafield, 1, zde->extrafield_len, fp);
462:
463: if (!localp) {
464: if (zde->comment_len)
465: fwrite(zde->comment, 1, zde->comment_len, fp);
466: }
467:
468: if (ferror(fp)) {
469: _zip_error_set(error, ZIP_ER_WRITE, errno);
470: return -1;
471: }
472:
473: return 0;
474: }
475:
476:
477:
478: static time_t
479: _zip_d2u_time(int dtime, int ddate)
480: {
1.1.1.2 ! misho 481: struct tm tm;
1.1 misho 482:
1.1.1.2 ! misho 483: memset(&tm, 0, sizeof(tm));
! 484:
1.1 misho 485: /* let mktime decide if DST is in effect */
486: tm.tm_isdst = -1;
487:
488: tm.tm_year = ((ddate>>9)&127) + 1980 - 1900;
489: tm.tm_mon = ((ddate>>5)&15) - 1;
490: tm.tm_mday = ddate&31;
491:
492: tm.tm_hour = (dtime>>11)&31;
493: tm.tm_min = (dtime>>5)&63;
494: tm.tm_sec = (dtime<<1)&62;
495:
496: return mktime(&tm);
497: }
498:
499:
500:
501: unsigned short
502: _zip_read2(unsigned char **a)
503: {
504: unsigned short ret;
505:
506: ret = (*a)[0]+((*a)[1]<<8);
507: *a += 2;
508:
509: return ret;
510: }
511:
512:
513:
514: unsigned int
515: _zip_read4(unsigned char **a)
516: {
517: unsigned int ret;
518:
519: ret = ((((((*a)[3]<<8)+(*a)[2])<<8)+(*a)[1])<<8)+(*a)[0];
520: *a += 4;
521:
522: return ret;
523: }
524:
525:
526:
527: static char *
528: _zip_readfpstr(FILE *fp, unsigned int len, int nulp, struct zip_error *error)
529: {
530: char *r, *o;
531:
532: r = (char *)malloc(nulp ? len+1 : len);
533: if (!r) {
534: _zip_error_set(error, ZIP_ER_MEMORY, 0);
535: return NULL;
536: }
537:
538: if (fread(r, 1, len, fp)<len) {
539: free(r);
540: _zip_error_set(error, ZIP_ER_READ, errno);
541: return NULL;
542: }
543:
544: if (nulp) {
545: /* replace any in-string NUL characters with spaces */
546: r[len] = 0;
547: for (o=r; o<r+len; o++)
548: if (*o == '\0')
549: *o = ' ';
550: }
551:
552: return r;
553: }
554:
555:
556:
557: static char *
558: _zip_readstr(unsigned char **buf, int len, int nulp, struct zip_error *error)
559: {
560: char *r, *o;
561:
562: r = (char *)malloc(nulp ? len+1 : len);
563: if (!r) {
564: _zip_error_set(error, ZIP_ER_MEMORY, 0);
565: return NULL;
566: }
567:
568: memcpy(r, *buf, len);
569: *buf += len;
570:
571: if (nulp) {
572: /* replace any in-string NUL characters with spaces */
573: r[len] = 0;
574: for (o=r; o<r+len; o++)
575: if (*o == '\0')
576: *o = ' ';
577: }
578:
579: return r;
580: }
581:
582:
583:
584: static void
585: _zip_write2(unsigned short i, FILE *fp)
586: {
587: putc(i&0xff, fp);
588: putc((i>>8)&0xff, fp);
589:
590: return;
591: }
592:
593:
594:
595: static void
596: _zip_write4(unsigned int i, FILE *fp)
597: {
598: putc(i&0xff, fp);
599: putc((i>>8)&0xff, fp);
600: putc((i>>16)&0xff, fp);
601: putc((i>>24)&0xff, fp);
602:
603: return;
604: }
605:
606:
607:
1.1.1.2 ! misho 608: void
1.1 misho 609: _zip_u2d_time(time_t time, unsigned short *dtime, unsigned short *ddate)
610: {
611: struct tm *tm;
612:
613: tm = localtime(&time);
614: *ddate = ((tm->tm_year+1900-1980)<<9) + ((tm->tm_mon+1)<<5)
615: + tm->tm_mday;
616: *dtime = ((tm->tm_hour)<<11) + ((tm->tm_min)<<5)
617: + ((tm->tm_sec)>>1);
618:
619: return;
620: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>