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