Merge commit 'upstream/1.4'
[debian/gzip] / unzip.c
1 /* unzip.c -- decompress files in gzip or pkzip format.
2
3    Copyright (C) 1997-1999, 2009-2010 Free Software Foundation, Inc.
4    Copyright (C) 1992-1993 Jean-loup Gailly
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3, or (at your option)
9    any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software Foundation,
18    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
19
20 /*
21  * The code in this file is derived from the file funzip.c written
22  * and put in the public domain by Mark Adler.
23  */
24
25 /*
26    This version can extract files in gzip or pkzip format.
27    For the latter, only the first entry is extracted, and it has to be
28    either deflated or stored.
29  */
30
31 #include <config.h>
32 #include "tailor.h"
33 #include "gzip.h"
34 #include "crypt.h"
35
36 /* PKZIP header definitions */
37 #define LOCSIG 0x04034b50L      /* four-byte lead-in (lsb first) */
38 #define LOCFLG 6                /* offset of bit flag */
39 #define  CRPFLG 1               /*  bit for encrypted entry */
40 #define  EXTFLG 8               /*  bit for extended local header */
41 #define LOCHOW 8                /* offset of compression method */
42 /* #define LOCTIM 10               UNUSED file mod time (for decryption) */
43 #define LOCCRC 14               /* offset of crc */
44 #define LOCSIZ 18               /* offset of compressed size */
45 #define LOCLEN 22               /* offset of uncompressed length */
46 #define LOCFIL 26               /* offset of file name field length */
47 #define LOCEXT 28               /* offset of extra field length */
48 #define LOCHDR 30               /* size of local header, including sig */
49 #define EXTHDR 16               /* size of extended local header, inc sig */
50 #define RAND_HEAD_LEN  12       /* length of encryption random header */
51
52
53 /* Globals */
54
55 int decrypt;        /* flag to turn on decryption */
56 char *key;          /* not used--needed to link crypt.c */
57 int pkzip = 0;      /* set for a pkzip file */
58 int ext_header = 0; /* set if extended local header */
59
60 /* ===========================================================================
61  * Check zip file and advance inptr to the start of the compressed data.
62  * Get ofname from the local header if necessary.
63  */
64 int check_zipfile(in)
65     int in;   /* input file descriptors */
66 {
67     uch *h = inbuf + inptr; /* first local header */
68
69     ifd = in;
70
71     /* Check validity of local header, and skip name and extra fields */
72     inptr += LOCHDR + SH(h + LOCFIL) + SH(h + LOCEXT);
73
74     if (inptr > insize || LG(h) != LOCSIG) {
75         fprintf(stderr, "\n%s: %s: not a valid zip file\n",
76                 program_name, ifname);
77         exit_code = ERROR;
78         return ERROR;
79     }
80     method = h[LOCHOW];
81     if (method != STORED && method != DEFLATED) {
82         fprintf(stderr,
83                 "\n%s: %s: first entry not deflated or stored -- use unzip\n",
84                 program_name, ifname);
85         exit_code = ERROR;
86         return ERROR;
87     }
88
89     /* If entry encrypted, decrypt and validate encryption header */
90     if ((decrypt = h[LOCFLG] & CRPFLG) != 0) {
91         fprintf(stderr, "\n%s: %s: encrypted file -- use unzip\n",
92                 program_name, ifname);
93         exit_code = ERROR;
94         return ERROR;
95     }
96
97     /* Save flags for unzip() */
98     ext_header = (h[LOCFLG] & EXTFLG) != 0;
99     pkzip = 1;
100
101     /* Get ofname and time stamp from local header (to be done) */
102     return OK;
103 }
104
105 /* ===========================================================================
106  * Unzip in to out.  This routine works on both gzip and pkzip files.
107  *
108  * IN assertions: the buffer inbuf contains already the beginning of
109  *   the compressed data, from offsets inptr to insize-1 included.
110  *   The magic header has already been checked. The output buffer is cleared.
111  */
112 int unzip(in, out)
113     int in, out;   /* input and output file descriptors */
114 {
115     ulg orig_crc = 0;       /* original crc */
116     ulg orig_len = 0;       /* original uncompressed length */
117     int n;
118     uch buf[EXTHDR];        /* extended local header */
119     int err = OK;
120
121     ifd = in;
122     ofd = out;
123
124     updcrc(NULL, 0);           /* initialize crc */
125
126     if (pkzip && !ext_header) {  /* crc and length at the end otherwise */
127         orig_crc = LG(inbuf + LOCCRC);
128         orig_len = LG(inbuf + LOCLEN);
129     }
130
131     /* Decompress */
132     if (method == DEFLATED)  {
133
134         int res = inflate();
135
136         if (res == 3) {
137             xalloc_die ();
138         } else if (res != 0) {
139             gzip_error ("invalid compressed data--format violated");
140         }
141
142     } else if (pkzip && method == STORED) {
143
144         register ulg n = LG(inbuf + LOCLEN);
145
146         if (n != LG(inbuf + LOCSIZ) - (decrypt ? RAND_HEAD_LEN : 0)) {
147
148             fprintf(stderr, "len %ld, siz %ld\n", n, LG(inbuf + LOCSIZ));
149             gzip_error ("invalid compressed data--length mismatch");
150         }
151         while (n--) {
152             uch c = (uch)get_byte();
153             put_ubyte(c);
154         }
155         flush_window();
156     } else {
157         gzip_error ("internal error, invalid method");
158     }
159
160     /* Get the crc and original length */
161     if (!pkzip) {
162         /* crc32  (see algorithm.doc)
163          * uncompressed input size modulo 2^32
164          */
165         for (n = 0; n < 8; n++) {
166             buf[n] = (uch)get_byte(); /* may cause an error if EOF */
167         }
168         orig_crc = LG(buf);
169         orig_len = LG(buf+4);
170
171     } else if (ext_header) {  /* If extended header, check it */
172         /* signature - 4bytes: 0x50 0x4b 0x07 0x08
173          * CRC-32 value
174          * compressed size 4-bytes
175          * uncompressed size 4-bytes
176          */
177         for (n = 0; n < EXTHDR; n++) {
178             buf[n] = (uch)get_byte(); /* may cause an error if EOF */
179         }
180         orig_crc = LG(buf+4);
181         orig_len = LG(buf+12);
182     }
183
184     /* Validate decompression */
185     if (orig_crc != updcrc(outbuf, 0)) {
186         fprintf(stderr, "\n%s: %s: invalid compressed data--crc error\n",
187                 program_name, ifname);
188         err = ERROR;
189     }
190     if (orig_len != (ulg)(bytes_out & 0xffffffff)) {
191         fprintf(stderr, "\n%s: %s: invalid compressed data--length error\n",
192                 program_name, ifname);
193         err = ERROR;
194     }
195
196     /* Check if there are more entries in a pkzip file */
197     if (pkzip && inptr + 4 < insize && LG(inbuf+inptr) == LOCSIG) {
198         if (to_stdout) {
199             WARN((stderr,
200                   "%s: %s has more than one entry--rest ignored\n",
201                   program_name, ifname));
202         } else {
203             /* Don't destroy the input zip file */
204             fprintf(stderr,
205                     "%s: %s has more than one entry -- unchanged\n",
206                     program_name, ifname);
207             err = ERROR;
208         }
209     }
210     ext_header = pkzip = 0; /* for next file */
211     if (err == OK) return OK;
212     exit_code = ERROR;
213     if (!test) abort_gzip();
214     return err;
215 }