update standards version
[debian/gzip] / util.c
1 /* util.c -- utility functions for gzip support
2
3    Copyright (C) 1997-1999, 2001-2002, 2006, 2009-2013 Free Software
4    Foundation, Inc.
5    Copyright (C) 1992-1993 Jean-loup Gailly
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3, or (at your option)
10    any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software Foundation,
19    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
20
21 #include <config.h>
22 #include <ctype.h>
23 #include <errno.h>
24
25 #include "tailor.h"
26
27 #include <limits.h>
28 #include <unistd.h>
29 #include <fcntl.h>
30 #include <stdlib.h>
31 #include <errno.h>
32
33 #include "gzip.h"
34 #include <xalloc.h>
35
36 #ifndef CHAR_BIT
37 #  define CHAR_BIT 8
38 #endif
39
40 static int write_buffer (int, voidp, unsigned int);
41
42 static const ulg crc_32_tab[];   /* crc table, defined below */
43
44 /* ===========================================================================
45  * Copy input to output unchanged: zcat == cat with --force.
46  * IN assertion: insize bytes have already been read in inbuf and inptr bytes
47  * already processed or copied.
48  */
49 int copy(in, out)
50     int in, out;   /* input and output file descriptors */
51 {
52     int got;
53
54     errno = 0;
55     while (insize > inptr) {
56         write_buf(out, (char*)inbuf + inptr, insize - inptr);
57         bytes_out += insize - inptr;
58         got = read_buffer (in, (char *) inbuf, INBUFSIZ);
59         if (got == -1)
60             read_error();
61         bytes_in += got;
62         insize = (unsigned)got;
63         inptr = 0;
64     }
65     return OK;
66 }
67
68 /* ===========================================================================
69  * Run a set of bytes through the crc shift register.  If s is a NULL
70  * pointer, then initialize the crc shift register contents instead.
71  * Return the current crc in either case.
72  */
73 ulg updcrc(s, n)
74     uch *s;                 /* pointer to bytes to pump through */
75     unsigned n;             /* number of bytes in s[] */
76 {
77     register ulg c;         /* temporary variable */
78
79     static ulg crc = (ulg)0xffffffffL; /* shift register contents */
80
81     if (s == NULL) {
82         c = 0xffffffffL;
83     } else {
84         c = crc;
85         if (n) do {
86             c = crc_32_tab[((int)c ^ (*s++)) & 0xff] ^ (c >> 8);
87         } while (--n);
88     }
89     crc = c;
90     return c ^ 0xffffffffL;       /* (instead of ~c for 64-bit machines) */
91 }
92
93 /* ===========================================================================
94  * Clear input and output buffers
95  */
96 void clear_bufs()
97 {
98     outcnt = 0;
99     insize = inptr = 0;
100     bytes_in = bytes_out = 0L;
101 }
102
103 /* ===========================================================================
104  * Fill the input buffer. This is called only when the buffer is empty.
105  */
106 int fill_inbuf(eof_ok)
107     int eof_ok;          /* set if EOF acceptable as a result */
108 {
109     int len;
110
111     /* Read as much as possible */
112     insize = 0;
113     do {
114         len = read_buffer (ifd, (char *) inbuf + insize, INBUFSIZ - insize);
115         if (len == 0) break;
116         if (len == -1) {
117           read_error();
118           break;
119         }
120         insize += len;
121     } while (insize < INBUFSIZ);
122
123     if (insize == 0) {
124         if (eof_ok) return EOF;
125         flush_window();
126         errno = 0;
127         read_error();
128     }
129     bytes_in += (off_t)insize;
130     inptr = 1;
131     return inbuf[0];
132 }
133
134 /* Like the standard read function, except do not attempt to read more
135    than INT_MAX bytes at a time.  */
136 int
137 read_buffer (fd, buf, cnt)
138      int fd;
139      voidp buf;
140      unsigned int cnt;
141 {
142   int len;
143   if (INT_MAX < cnt)
144     cnt = INT_MAX;
145   len = read (fd, buf, cnt);
146
147 #if defined F_SETFL && O_NONBLOCK && defined EAGAIN
148   /* Input files are opened O_NONBLOCK for security reasons.  On some
149      file systems this can cause read to fail with errno == EAGAIN.  */
150   if (len < 0 && errno == EAGAIN)
151     {
152       int flags = fcntl (fd, F_GETFL);
153       if (0 <= flags)
154         {
155           if (! (flags & O_NONBLOCK))
156             errno = EAGAIN;
157           else if (fcntl (fd, F_SETFL, flags & ~O_NONBLOCK) != -1)
158             len = read (fd, buf, cnt);
159         }
160     }
161 #endif
162
163   return len;
164 }
165
166 /* Likewise for 'write'.  */
167 static int
168 write_buffer (fd, buf, cnt)
169      int fd;
170      voidp buf;
171      unsigned int cnt;
172 {
173   if (INT_MAX < cnt)
174     cnt = INT_MAX;
175   return write (fd, buf, cnt);
176 }
177
178 /* ===========================================================================
179  * Write the output buffer outbuf[0..outcnt-1] and update bytes_out.
180  * (used for the compressed data only)
181  */
182 void flush_outbuf()
183 {
184     if (outcnt == 0) return;
185
186     write_buf(ofd, (char *)outbuf, outcnt);
187     bytes_out += (off_t)outcnt;
188     outcnt = 0;
189 }
190
191 /* ===========================================================================
192  * Write the output window window[0..outcnt-1] and update crc and bytes_out.
193  * (Used for the decompressed data only.)
194  */
195 void flush_window()
196 {
197     if (outcnt == 0) return;
198     updcrc(window, outcnt);
199
200     if (!test) {
201         write_buf(ofd, (char *)window, outcnt);
202     }
203     bytes_out += (off_t)outcnt;
204     outcnt = 0;
205 }
206
207 /* ===========================================================================
208  * Does the same as write(), but also handles partial pipe writes and checks
209  * for error return.
210  */
211 void write_buf(fd, buf, cnt)
212     int       fd;
213     voidp     buf;
214     unsigned  cnt;
215 {
216     unsigned  n;
217
218     while ((n = write_buffer (fd, buf, cnt)) != cnt) {
219         if (n == (unsigned)(-1)) {
220             write_error();
221         }
222         cnt -= n;
223         buf = (voidp)((char*)buf+n);
224     }
225 }
226
227 /* ========================================================================
228  * Put string s in lower case, return s.
229  */
230 char *strlwr(s)
231     char *s;
232 {
233     char *t;
234     for (t = s; *t; t++)
235       *t = tolow ((unsigned char) *t);
236     return s;
237 }
238
239 /* ========================================================================
240  * Return the base name of a file (remove any directory prefix and
241  * any version suffix). For systems with file names that are not
242  * case sensitive, force the base name to lower case.
243  */
244 char *
245 gzip_base_name (fname)
246     char *fname;
247 {
248     char *p;
249
250     if ((p = strrchr(fname, PATH_SEP))  != NULL) fname = p+1;
251 #ifdef PATH_SEP2
252     if ((p = strrchr(fname, PATH_SEP2)) != NULL) fname = p+1;
253 #endif
254 #ifdef PATH_SEP3
255     if ((p = strrchr(fname, PATH_SEP3)) != NULL) fname = p+1;
256 #endif
257 #ifdef SUFFIX_SEP
258     if ((p = strrchr(fname, SUFFIX_SEP)) != NULL) *p = '\0';
259 #endif
260     if (casemap('A') == 'a') strlwr(fname);
261     return fname;
262 }
263
264 /* ========================================================================
265  * Unlink a file, working around the unlink readonly bug (if present).
266  */
267 int xunlink (filename)
268      char *filename;
269 {
270   int r = unlink (filename);
271
272 #ifdef UNLINK_READONLY_BUG
273   if (r != 0)
274     {
275       int e = errno;
276       if (chmod (filename, S_IWUSR) != 0)
277         {
278           errno = e;
279           return -1;
280         }
281
282       r = unlink (filename);
283     }
284 #endif
285
286   return r;
287 }
288
289 /* ========================================================================
290  * Make a file name legal for file systems not allowing file names with
291  * multiple dots or starting with a dot (such as MSDOS), by changing
292  * all dots except the last one into underlines.  A target dependent
293  * function can be used instead of this simple function by defining the macro
294  * MAKE_LEGAL_NAME in tailor.h and providing the function in a target
295  * dependent module.
296  */
297 void make_simple_name(name)
298     char *name;
299 {
300     char *p = strrchr(name, '.');
301     if (p == NULL) return;
302     if (p == name) p++;
303     do {
304         if (*--p == '.') *p = '_';
305     } while (p != name);
306 }
307
308 /* ========================================================================
309  * Add an environment variable (if any) before argv, and update argc.
310  * Return the expanded environment variable to be freed later, or NULL
311  * if no options were added to argv.
312  */
313 #define SEPARATOR       " \t"   /* separators in env variable */
314
315 char *add_envopt(
316     int *argcp,          /* pointer to argc */
317     char ***argvp,       /* pointer to argv */
318     char const *envvar_name) /* name of environment variable */
319 {
320     char *p;             /* running pointer through env variable */
321     char **oargv;        /* runs through old argv array */
322     char **nargv;        /* runs through new argv array */
323     int  oargc = *argcp; /* old argc */
324     int  nargc = 0;      /* number of arguments in env variable */
325     char *env_val;
326
327     env_val = getenv(envvar_name);
328     if (env_val == NULL) return NULL;
329
330     env_val = xstrdup (env_val);
331
332     for (p = env_val; *p; nargc++ ) {        /* move through env_val */
333         p += strspn(p, SEPARATOR);           /* skip leading separators */
334         if (*p == '\0') break;
335
336         p += strcspn(p, SEPARATOR);          /* find end of word */
337         if (*p) *p++ = '\0';                 /* mark it */
338     }
339     if (nargc == 0) {
340         free(env_val);
341         return NULL;
342     }
343     *argcp += nargc;
344     /* Allocate the new argv array, with an extra element just in case
345      * the original arg list did not end with a NULL.
346      */
347     nargv = xcalloc (*argcp + 1, sizeof (char *));
348     oargv  = *argvp;
349     *argvp = nargv;
350
351     /* Copy the program name first */
352     if (oargc-- < 0)
353       gzip_error ("argc<=0");
354     *(nargv++) = *(oargv++);
355
356     /* Then copy the environment args */
357     for (p = env_val; nargc > 0; nargc--) {
358         p += strspn(p, SEPARATOR);           /* skip separators */
359         *(nargv++) = p;                      /* store start */
360         while (*p++) ;                       /* skip over word */
361     }
362
363     /* Finally copy the old args and add a NULL (usual convention) */
364     while (oargc--) *(nargv++) = *(oargv++);
365     *nargv = NULL;
366     return env_val;
367 }
368
369 /* ========================================================================
370  * Error handlers.
371  */
372 void
373 gzip_error (char const *m)
374 {
375     fprintf (stderr, "\n%s: %s: %s\n", program_name, ifname, m);
376     abort_gzip();
377 }
378
379 void
380 xalloc_die ()
381 {
382   fprintf (stderr, "\n%s: memory_exhausted\n", program_name);
383   abort_gzip ();
384 }
385
386 void warning (char const *m)
387 {
388     WARN ((stderr, "%s: %s: warning: %s\n", program_name, ifname, m));
389 }
390
391 void read_error()
392 {
393     int e = errno;
394     fprintf (stderr, "\n%s: ", program_name);
395     if (e != 0) {
396         errno = e;
397         perror(ifname);
398     } else {
399         fprintf(stderr, "%s: unexpected end of file\n", ifname);
400     }
401     abort_gzip();
402 }
403
404 void write_error()
405 {
406     int e = errno;
407     fprintf (stderr, "\n%s: ", program_name);
408     errno = e;
409     perror(ofname);
410     abort_gzip();
411 }
412
413 /* ========================================================================
414  * Display compression ratio on the given stream on 6 characters.
415  */
416 void display_ratio(num, den, file)
417     off_t num;
418     off_t den;
419     FILE *file;
420 {
421     fprintf(file, "%5.1f%%", den == 0 ? 0 : 100.0 * num / den);
422 }
423
424 /* ========================================================================
425  * Print an off_t.  There's no completely portable way to use printf,
426  * so we do it ourselves.
427  */
428 void fprint_off(file, offset, width)
429     FILE *file;
430     off_t offset;
431     int width;
432 {
433     char buf[CHAR_BIT * sizeof (off_t)];
434     char *p = buf + sizeof buf;
435
436     /* Don't negate offset here; it might overflow.  */
437     if (offset < 0) {
438         do
439           *--p = '0' - offset % 10;
440         while ((offset /= 10) != 0);
441
442         *--p = '-';
443     } else {
444         do
445           *--p = '0' + offset % 10;
446         while ((offset /= 10) != 0);
447     }
448
449     width -= buf + sizeof buf - p;
450     while (0 < width--) {
451         putc (' ', file);
452     }
453     for (;  p < buf + sizeof buf;  p++)
454         putc (*p, file);
455 }
456
457 /* ========================================================================
458  * Table of CRC-32's of all single-byte values (made by makecrc.c)
459  */
460 static const ulg crc_32_tab[] = {
461   0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
462   0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
463   0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
464   0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
465   0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
466   0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
467   0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
468   0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
469   0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
470   0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
471   0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
472   0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
473   0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
474   0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
475   0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
476   0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
477   0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
478   0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
479   0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
480   0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
481   0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
482   0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
483   0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
484   0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
485   0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
486   0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
487   0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
488   0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
489   0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
490   0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
491   0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
492   0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
493   0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
494   0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
495   0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
496   0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
497   0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
498   0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
499   0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
500   0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
501   0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
502   0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
503   0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
504   0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
505   0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
506   0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
507   0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
508   0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
509   0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
510   0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
511   0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
512   0x2d02ef8dL
513 };