1 /* util.c -- utility functions for gzip support
3 Copyright (C) 1997-1999, 2001-2002, 2006, 2009-2024 Free Software
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)
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, see <https://www.gnu.org/licenses/>. */
38 static int write_buffer (int, voidp
, unsigned int);
40 /* Shift register contents. */
43 /* ===========================================================================
44 * Copy input to output unchanged: zcat == cat with --force.
45 * IN assertion: insize bytes have already been read in inbuf and inptr bytes
46 * already processed or copied.
47 * 'in' and 'out' are the input and output file descriptors.
50 copy (int in
, int out
)
55 while (insize
> inptr
) {
56 write_buf(out
, (char*)inbuf
+ inptr
, insize
- inptr
);
57 got
= read_buffer (in
, (char *) inbuf
, INBUFSIZ
);
61 insize
= (unsigned)got
;
67 /* ===========================================================================
68 * Run a set of bytes through the crc shift register. If s is a NULL
69 * pointer, then initialize the crc shift register contents instead.
70 * Return the current crc in either case.
71 * S points to N bytes to pump through.
74 updcrc (uch
const *s
, unsigned n
)
76 crc
= (s
== NULL
? 0 : crc32_update (crc
, (const char *) s
, n
));
80 /* Return a current CRC value. */
88 /* Set a new CRC value. */
96 /* ===========================================================================
97 * Clear input and output buffers
103 bytes_in
= bytes_out
= 0L;
106 /* ===========================================================================
107 * Fill the input buffer. This is called only when the buffer is empty.
108 * EOF_OK is set if EOF acceptable as a result.
111 fill_inbuf (int eof_ok
)
115 /* Read as much as possible */
118 len
= read_buffer (ifd
, (char *) inbuf
+ insize
, INBUFSIZ
- insize
);
125 } while (insize
< INBUFSIZ
);
128 if (eof_ok
) return EOF
;
133 bytes_in
+= (off_t
)insize
;
138 /* Like the standard read function, except do not attempt to read more
139 than INT_MAX bytes at a time. */
141 read_buffer (int fd
, voidp buf
, unsigned int cnt
)
146 len
= read (fd
, buf
, cnt
);
148 #if defined F_SETFL && O_NONBLOCK && defined EAGAIN
149 /* Input files are opened O_NONBLOCK for security reasons. On some
150 file systems this can cause read to fail with errno == EAGAIN. */
151 if (len
< 0 && errno
== EAGAIN
)
153 int flags
= fcntl (fd
, F_GETFL
);
156 if (! (flags
& O_NONBLOCK
))
158 else if (fcntl (fd
, F_SETFL
, flags
& ~O_NONBLOCK
) != -1)
159 len
= read (fd
, buf
, cnt
);
167 /* Likewise for 'write'. */
169 write_buffer (int fd
, voidp buf
, unsigned int cnt
)
173 return write (fd
, buf
, cnt
);
176 /* ===========================================================================
177 * Write the output buffer outbuf[0..outcnt-1] and update bytes_out.
178 * (used for the compressed data only)
182 if (outcnt
== 0) return;
184 write_buf (ofd
, outbuf
, outcnt
);
188 /* ===========================================================================
189 * Write the output window window[0..outcnt-1] and update crc and bytes_out.
190 * (Used for the decompressed data only.)
194 if (outcnt
== 0) return;
195 updcrc(window
, outcnt
);
197 write_buf (ofd
, window
, outcnt
);
201 /* ===========================================================================
202 * Update the count of output bytes. If testing, do not do any
203 * output. Otherwise, write the buffer, checking for errors.
206 write_buf (int fd
, voidp buf
, unsigned cnt
)
214 while ((n
= write_buffer (fd
, buf
, cnt
)) != cnt
) {
215 if (n
== (unsigned)(-1)) {
219 buf
= (voidp
)((char*)buf
+n
);
223 /* ========================================================================
224 * Put string s in lower case, return s.
231 *t
= tolow ((unsigned char) *t
);
235 /* ========================================================================
236 * Return the base name of a file (remove any directory prefix and
237 * any version suffix). For systems with file names that are not
238 * case sensitive, force the base name to lower case.
241 gzip_base_name (char *fname
)
243 fname
= last_component (fname
);
244 if (casemap('A') == 'a') strlwr(fname
);
248 /* ========================================================================
249 * Unlink a file, working around the unlink readonly bug (if present).
252 xunlink (char *filename
)
254 int r
= unlink (filename
);
256 #ifdef UNLINK_READONLY_BUG
260 if (chmod (filename
, S_IWUSR
) != 0)
266 r
= unlink (filename
);
273 #ifdef NO_MULTIPLE_DOTS
274 /* ========================================================================
275 * Make a file name legal for file systems not allowing file names with
276 * multiple dots or starting with a dot (such as MSDOS), by changing
277 * all dots except the last one into underlines. A target dependent
278 * function can be used instead of this simple function by defining the macro
279 * MAKE_LEGAL_NAME in tailor.h and providing the function in a target
283 make_simple_name (char *name
)
285 char *p
= strrchr(name
, '.');
286 if (p
== NULL
) return;
289 if (*--p
== '.') *p
= '_';
294 /* Convert the value of the environment variable ENVVAR_NAME
295 to a newly allocated argument vector, and set *ARGCP and *ARGVP
296 to the number of arguments and to the vector, respectively.
297 Make the new vector's zeroth element equal to the old **ARGVP.
298 Return a pointer to the newly allocated string storage.
300 If the vector would be empty, do not allocate storage,
301 do not set *ARGCP and *ARGVP, and return NULL. */
303 #define SEPARATOR " \t" /* separators in env variable */
306 int *argcp
, /* pointer to argc */
307 char ***argvp
, /* pointer to argv */
308 char const *envvar_name
) /* name of environment variable */
310 char *p
; /* running pointer through env variable */
311 char **oargv
; /* runs through old argv array */
312 char **nargv
; /* runs through new argv array */
313 int nargc
= 0; /* number of arguments in env variable */
316 env_val
= getenv(envvar_name
);
317 if (env_val
== NULL
) return NULL
;
319 env_val
= xstrdup (env_val
);
321 for (p
= env_val
; *p
; nargc
++ ) { /* move through env_val */
322 p
+= strspn(p
, SEPARATOR
); /* skip leading separators */
323 if (*p
== '\0') break;
325 p
+= strcspn(p
, SEPARATOR
); /* find end of word */
326 if (*p
) *p
++ = '\0'; /* mark it */
333 /* Allocate the new argv array, with an extra element just in case
334 * the original arg list did not end with a NULL.
336 nargv
= xcalloc (*argcp
+ 1, sizeof (char *));
340 /* Copy the program name first */
343 /* Then copy the environment args */
344 for (p
= env_val
; nargc
> 0; nargc
--) {
345 p
+= strspn(p
, SEPARATOR
); /* skip separators */
346 *(nargv
++) = p
; /* store start */
347 while (*p
++) ; /* skip over word */
354 /* ========================================================================
358 gzip_error (char const *m
)
360 fprintf (stderr
, "\n%s: %s: %s\n", program_name
, ifname
, m
);
367 fprintf (stderr
, "\n%s: memory_exhausted\n", program_name
);
371 void warning (char const *m
)
373 WARN ((stderr
, "%s: %s: warning: %s\n", program_name
, ifname
, m
));
378 fprintf (stderr
, "\n%s: %s: %s\n",
379 program_name
, ifname
,
380 errno
? strerror (errno
) : "unexpected end of file");
386 int exitcode
= errno
== EPIPE
? WARNING
: ERROR
;
387 if (! (exitcode
== WARNING
&& quiet
))
388 fprintf (stderr
, "\n%s: %s: %s\n", program_name
, ofname
, strerror (errno
));
389 finish_up_gzip (exitcode
);
392 /* ========================================================================
393 * Display compression ratio on the given stream on 6 characters.
396 display_ratio (off_t num
, off_t den
, FILE *file
)
398 fprintf(file
, "%5.1f%%", den
== 0 ? 0 : 100.0 * num
/ den
);