xref: /freebsd/usr.bin/compress/compress.c (revision 0b8224d1cc9dc6c9778ba04a75b2c8d47e5d7481)
19b50d902SRodney W. Grimes /*-
28a16b7a1SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
38a16b7a1SPedro F. Giffuni  *
49b50d902SRodney W. Grimes  * Copyright (c) 1992, 1993
59b50d902SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
69b50d902SRodney W. Grimes  *
79b50d902SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
89b50d902SRodney W. Grimes  * modification, are permitted provided that the following conditions
99b50d902SRodney W. Grimes  * are met:
109b50d902SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
119b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
129b50d902SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
139b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
149b50d902SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
15fbbd9655SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
169b50d902SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
179b50d902SRodney W. Grimes  *    without specific prior written permission.
189b50d902SRodney W. Grimes  *
199b50d902SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
209b50d902SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
219b50d902SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
229b50d902SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
239b50d902SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
249b50d902SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
259b50d902SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
269b50d902SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
279b50d902SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
289b50d902SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
299b50d902SRodney W. Grimes  * SUCH DAMAGE.
309b50d902SRodney W. Grimes  */
319b50d902SRodney W. Grimes 
329b50d902SRodney W. Grimes #include <sys/param.h>
339b50d902SRodney W. Grimes #include <sys/stat.h>
34eb2fc780SGarrett Wollman #include <sys/time.h>
359b50d902SRodney W. Grimes 
369b50d902SRodney W. Grimes #include <err.h>
379b50d902SRodney W. Grimes #include <errno.h>
38d6b3ef63SJilles Tjoelker #include <fcntl.h>
397ddea7b8SWarner Losh #include <stdarg.h>
409b50d902SRodney W. Grimes #include <stdio.h>
419b50d902SRodney W. Grimes #include <stdlib.h>
429b50d902SRodney W. Grimes #include <string.h>
439b50d902SRodney W. Grimes #include <unistd.h>
449b50d902SRodney W. Grimes 
451f36dc1fSBruce Evans #include "zopen.h"
461f36dc1fSBruce Evans 
47305700d9SEd Schouten static void	compress(const char *, const char *, int);
48305700d9SEd Schouten static void	cwarn(const char *, ...) __printflike(1, 2);
49305700d9SEd Schouten static void	cwarnx(const char *, ...) __printflike(1, 2);
50305700d9SEd Schouten static void	decompress(const char *, const char *, int);
51305700d9SEd Schouten static int	permission(const char *);
52305700d9SEd Schouten static void	setfile(const char *, struct stat *);
53305700d9SEd Schouten static void	usage(int);
549b50d902SRodney W. Grimes 
55305700d9SEd Schouten static int eval, force, verbose;
569b50d902SRodney W. Grimes 
579b50d902SRodney W. Grimes int
main(int argc,char * argv[])5847e9e6a1SDavid Malone main(int argc, char *argv[])
599b50d902SRodney W. Grimes {
60d52ae819SBruce Evans 	enum {COMPRESS, DECOMPRESS} style;
619b50d902SRodney W. Grimes 	size_t len;
629b50d902SRodney W. Grimes 	int bits, cat, ch;
639b50d902SRodney W. Grimes 	char *p, newname[MAXPATHLEN];
649b50d902SRodney W. Grimes 
65d52ae819SBruce Evans 	cat = 0;
66b3608ae1SEd Schouten 	if ((p = strrchr(argv[0], '/')) == NULL)
679b50d902SRodney W. Grimes 		p = argv[0];
689b50d902SRodney W. Grimes 	else
699b50d902SRodney W. Grimes 		++p;
709b50d902SRodney W. Grimes 	if (!strcmp(p, "uncompress"))
719b50d902SRodney W. Grimes 		style = DECOMPRESS;
729b50d902SRodney W. Grimes 	else if (!strcmp(p, "compress"))
739b50d902SRodney W. Grimes 		style = COMPRESS;
747c0704e4SMike Smith 	else if (!strcmp(p, "zcat")) {
757c0704e4SMike Smith 		cat = 1;
76d52ae819SBruce Evans 		style = DECOMPRESS;
777c0704e4SMike Smith 	} else
789b50d902SRodney W. Grimes 		errx(1, "unknown program name");
799b50d902SRodney W. Grimes 
80d52ae819SBruce Evans 	bits = 0;
811c8af878SWarner Losh 	while ((ch = getopt(argc, argv, "b:cdfv")) != -1)
829b50d902SRodney W. Grimes 		switch(ch) {
839b50d902SRodney W. Grimes 		case 'b':
849b50d902SRodney W. Grimes 			bits = strtol(optarg, &p, 10);
859b50d902SRodney W. Grimes 			if (*p)
869b50d902SRodney W. Grimes 				errx(1, "illegal bit count -- %s", optarg);
879b50d902SRodney W. Grimes 			break;
889b50d902SRodney W. Grimes 		case 'c':
899b50d902SRodney W. Grimes 			cat = 1;
909b50d902SRodney W. Grimes 			break;
919b50d902SRodney W. Grimes 		case 'd':		/* Backward compatible. */
929b50d902SRodney W. Grimes 			style = DECOMPRESS;
939b50d902SRodney W. Grimes 			break;
949b50d902SRodney W. Grimes 		case 'f':
959b50d902SRodney W. Grimes 			force = 1;
969b50d902SRodney W. Grimes 			break;
979b50d902SRodney W. Grimes 		case 'v':
989b50d902SRodney W. Grimes 			verbose = 1;
999b50d902SRodney W. Grimes 			break;
1009b50d902SRodney W. Grimes 		case '?':
1019b50d902SRodney W. Grimes 		default:
1029b50d902SRodney W. Grimes 			usage(style == COMPRESS);
1039b50d902SRodney W. Grimes 		}
1049b50d902SRodney W. Grimes 	argc -= optind;
1059b50d902SRodney W. Grimes 	argv += optind;
1069b50d902SRodney W. Grimes 
1079b50d902SRodney W. Grimes 	if (argc == 0) {
1089b50d902SRodney W. Grimes 		switch(style) {
1099b50d902SRodney W. Grimes 		case COMPRESS:
1109b50d902SRodney W. Grimes 			(void)compress("/dev/stdin", "/dev/stdout", bits);
1119b50d902SRodney W. Grimes 			break;
1129b50d902SRodney W. Grimes 		case DECOMPRESS:
1139b50d902SRodney W. Grimes 			(void)decompress("/dev/stdin", "/dev/stdout", bits);
1149b50d902SRodney W. Grimes 			break;
1159b50d902SRodney W. Grimes 		}
1169b50d902SRodney W. Grimes 		exit (eval);
1179b50d902SRodney W. Grimes 	}
1189b50d902SRodney W. Grimes 
119f084f766SJilles Tjoelker 	if (cat == 1 && style == COMPRESS && argc > 1)
1209b50d902SRodney W. Grimes 		errx(1, "the -c option permits only a single file argument");
1219b50d902SRodney W. Grimes 
1229b50d902SRodney W. Grimes 	for (; *argv; ++argv)
1239b50d902SRodney W. Grimes 		switch(style) {
1249b50d902SRodney W. Grimes 		case COMPRESS:
125b4771590STim J. Robbins 			if (strcmp(*argv, "-") == 0) {
126b4771590STim J. Robbins 				compress("/dev/stdin", "/dev/stdout", bits);
127b4771590STim J. Robbins 				break;
128b4771590STim J. Robbins 			} else if (cat) {
1299b50d902SRodney W. Grimes 				compress(*argv, "/dev/stdout", bits);
1309b50d902SRodney W. Grimes 				break;
1319b50d902SRodney W. Grimes 			}
132b3608ae1SEd Schouten 			if ((p = strrchr(*argv, '.')) != NULL &&
1339b50d902SRodney W. Grimes 			    !strcmp(p, ".Z")) {
1349b50d902SRodney W. Grimes 				cwarnx("%s: name already has trailing .Z",
1359b50d902SRodney W. Grimes 				    *argv);
1369b50d902SRodney W. Grimes 				break;
1379b50d902SRodney W. Grimes 			}
1389b50d902SRodney W. Grimes 			len = strlen(*argv);
1399b50d902SRodney W. Grimes 			if (len > sizeof(newname) - 3) {
1409b50d902SRodney W. Grimes 				cwarnx("%s: name too long", *argv);
1419b50d902SRodney W. Grimes 				break;
1429b50d902SRodney W. Grimes 			}
1439b50d902SRodney W. Grimes 			memmove(newname, *argv, len);
1449b50d902SRodney W. Grimes 			newname[len] = '.';
1459b50d902SRodney W. Grimes 			newname[len + 1] = 'Z';
1469b50d902SRodney W. Grimes 			newname[len + 2] = '\0';
1479b50d902SRodney W. Grimes 			compress(*argv, newname, bits);
1489b50d902SRodney W. Grimes 			break;
1499b50d902SRodney W. Grimes 		case DECOMPRESS:
150b4771590STim J. Robbins 			if (strcmp(*argv, "-") == 0) {
151b4771590STim J. Robbins 				decompress("/dev/stdin", "/dev/stdout", bits);
152b4771590STim J. Robbins 				break;
153b4771590STim J. Robbins 			}
1549b50d902SRodney W. Grimes 			len = strlen(*argv);
155b3608ae1SEd Schouten 			if ((p = strrchr(*argv, '.')) == NULL ||
1569b50d902SRodney W. Grimes 			    strcmp(p, ".Z")) {
1579b50d902SRodney W. Grimes 				if (len > sizeof(newname) - 3) {
1589b50d902SRodney W. Grimes 					cwarnx("%s: name too long", *argv);
1599b50d902SRodney W. Grimes 					break;
1609b50d902SRodney W. Grimes 				}
1619b50d902SRodney W. Grimes 				memmove(newname, *argv, len);
1629b50d902SRodney W. Grimes 				newname[len] = '.';
1639b50d902SRodney W. Grimes 				newname[len + 1] = 'Z';
1649b50d902SRodney W. Grimes 				newname[len + 2] = '\0';
1659b50d902SRodney W. Grimes 				decompress(newname,
1669b50d902SRodney W. Grimes 				    cat ? "/dev/stdout" : *argv, bits);
1679b50d902SRodney W. Grimes 			} else {
1689b50d902SRodney W. Grimes 				if (len - 2 > sizeof(newname) - 1) {
1699b50d902SRodney W. Grimes 					cwarnx("%s: name too long", *argv);
1709b50d902SRodney W. Grimes 					break;
1719b50d902SRodney W. Grimes 				}
1729b50d902SRodney W. Grimes 				memmove(newname, *argv, len - 2);
1739b50d902SRodney W. Grimes 				newname[len - 2] = '\0';
1749b50d902SRodney W. Grimes 				decompress(*argv,
1759b50d902SRodney W. Grimes 				    cat ? "/dev/stdout" : newname, bits);
1769b50d902SRodney W. Grimes 			}
1779b50d902SRodney W. Grimes 			break;
1789b50d902SRodney W. Grimes 		}
1799b50d902SRodney W. Grimes 	exit (eval);
1809b50d902SRodney W. Grimes }
1819b50d902SRodney W. Grimes 
182305700d9SEd Schouten static void
compress(const char * in,const char * out,int bits)18347e9e6a1SDavid Malone compress(const char *in, const char *out, int bits)
1849b50d902SRodney W. Grimes {
185cb08795bSMark Murray 	size_t nr;
1869b50d902SRodney W. Grimes 	struct stat isb, sb;
1879b50d902SRodney W. Grimes 	FILE *ifp, *ofp;
1889b50d902SRodney W. Grimes 	int exists, isreg, oreg;
1899b50d902SRodney W. Grimes 	u_char buf[1024];
1909b50d902SRodney W. Grimes 
1919b50d902SRodney W. Grimes 	exists = !stat(out, &sb);
1929b50d902SRodney W. Grimes 	if (!force && exists && S_ISREG(sb.st_mode) && !permission(out))
1939b50d902SRodney W. Grimes 		return;
1949b50d902SRodney W. Grimes 	isreg = oreg = !exists || S_ISREG(sb.st_mode);
1959b50d902SRodney W. Grimes 
1969b50d902SRodney W. Grimes 	ifp = ofp = NULL;
1979b50d902SRodney W. Grimes 	if ((ifp = fopen(in, "r")) == NULL) {
1989b50d902SRodney W. Grimes 		cwarn("%s", in);
1999b50d902SRodney W. Grimes 		return;
2009b50d902SRodney W. Grimes 	}
2019b50d902SRodney W. Grimes 	if (stat(in, &isb)) {		/* DON'T FSTAT! */
2029b50d902SRodney W. Grimes 		cwarn("%s", in);
2039b50d902SRodney W. Grimes 		goto err;
2049b50d902SRodney W. Grimes 	}
2059b50d902SRodney W. Grimes 	if (!S_ISREG(isb.st_mode))
2069b50d902SRodney W. Grimes 		isreg = 0;
2079b50d902SRodney W. Grimes 
2089b50d902SRodney W. Grimes 	if ((ofp = zopen(out, "w", bits)) == NULL) {
2099b50d902SRodney W. Grimes 		cwarn("%s", out);
2109b50d902SRodney W. Grimes 		goto err;
2119b50d902SRodney W. Grimes 	}
2129b50d902SRodney W. Grimes 	while ((nr = fread(buf, 1, sizeof(buf), ifp)) != 0)
2139b50d902SRodney W. Grimes 		if (fwrite(buf, 1, nr, ofp) != nr) {
2149b50d902SRodney W. Grimes 			cwarn("%s", out);
2159b50d902SRodney W. Grimes 			goto err;
2169b50d902SRodney W. Grimes 		}
2179b50d902SRodney W. Grimes 
2189b50d902SRodney W. Grimes 	if (ferror(ifp) || fclose(ifp)) {
2199b50d902SRodney W. Grimes 		cwarn("%s", in);
2209b50d902SRodney W. Grimes 		goto err;
2219b50d902SRodney W. Grimes 	}
2229b50d902SRodney W. Grimes 	ifp = NULL;
2239b50d902SRodney W. Grimes 
2249b50d902SRodney W. Grimes 	if (fclose(ofp)) {
2259b50d902SRodney W. Grimes 		cwarn("%s", out);
2269b50d902SRodney W. Grimes 		goto err;
2279b50d902SRodney W. Grimes 	}
2289b50d902SRodney W. Grimes 	ofp = NULL;
2299b50d902SRodney W. Grimes 
2309b50d902SRodney W. Grimes 	if (isreg) {
2319b50d902SRodney W. Grimes 		if (stat(out, &sb)) {
2329b50d902SRodney W. Grimes 			cwarn("%s", out);
2339b50d902SRodney W. Grimes 			goto err;
2349b50d902SRodney W. Grimes 		}
2359b50d902SRodney W. Grimes 
2369b50d902SRodney W. Grimes 		if (!force && sb.st_size >= isb.st_size) {
2379b50d902SRodney W. Grimes 			if (verbose)
238783b4710STim J. Robbins 		(void)fprintf(stderr, "%s: file would grow; left unmodified\n",
239783b4710STim J. Robbins 		    in);
2406c1b63bbSTim J. Robbins 			eval = 2;
2419b50d902SRodney W. Grimes 			if (unlink(out))
2429b50d902SRodney W. Grimes 				cwarn("%s", out);
2439b50d902SRodney W. Grimes 			goto err;
2449b50d902SRodney W. Grimes 		}
2459b50d902SRodney W. Grimes 
2469b50d902SRodney W. Grimes 		setfile(out, &isb);
2479b50d902SRodney W. Grimes 
2489b50d902SRodney W. Grimes 		if (unlink(in))
2499b50d902SRodney W. Grimes 			cwarn("%s", in);
2509b50d902SRodney W. Grimes 
2519b50d902SRodney W. Grimes 		if (verbose) {
252783b4710STim J. Robbins 			(void)fprintf(stderr, "%s: ", out);
2539b50d902SRodney W. Grimes 			if (isb.st_size > sb.st_size)
254783b4710STim J. Robbins 				(void)fprintf(stderr, "%.0f%% compression\n",
2559b50d902SRodney W. Grimes 				    ((float)sb.st_size / isb.st_size) * 100.0);
2569b50d902SRodney W. Grimes 			else
257783b4710STim J. Robbins 				(void)fprintf(stderr, "%.0f%% expansion\n",
2589b50d902SRodney W. Grimes 				    ((float)isb.st_size / sb.st_size) * 100.0);
2599b50d902SRodney W. Grimes 		}
2609b50d902SRodney W. Grimes 	}
2619b50d902SRodney W. Grimes 	return;
2629b50d902SRodney W. Grimes 
2639b50d902SRodney W. Grimes err:	if (ofp) {
2649b50d902SRodney W. Grimes 		if (oreg)
2659b50d902SRodney W. Grimes 			(void)unlink(out);
2669b50d902SRodney W. Grimes 		(void)fclose(ofp);
2679b50d902SRodney W. Grimes 	}
2689b50d902SRodney W. Grimes 	if (ifp)
2699b50d902SRodney W. Grimes 		(void)fclose(ifp);
2709b50d902SRodney W. Grimes }
2719b50d902SRodney W. Grimes 
272305700d9SEd Schouten static void
decompress(const char * in,const char * out,int bits)27347e9e6a1SDavid Malone decompress(const char *in, const char *out, int bits)
2749b50d902SRodney W. Grimes {
275cb08795bSMark Murray 	size_t nr;
2769b50d902SRodney W. Grimes 	struct stat sb;
2779b50d902SRodney W. Grimes 	FILE *ifp, *ofp;
2789b50d902SRodney W. Grimes 	int exists, isreg, oreg;
2799b50d902SRodney W. Grimes 	u_char buf[1024];
2809b50d902SRodney W. Grimes 
2819b50d902SRodney W. Grimes 	exists = !stat(out, &sb);
2829b50d902SRodney W. Grimes 	if (!force && exists && S_ISREG(sb.st_mode) && !permission(out))
2839b50d902SRodney W. Grimes 		return;
2849b50d902SRodney W. Grimes 	isreg = oreg = !exists || S_ISREG(sb.st_mode);
2859b50d902SRodney W. Grimes 
2869b50d902SRodney W. Grimes 	ifp = ofp = NULL;
2879b50d902SRodney W. Grimes 	if ((ifp = zopen(in, "r", bits)) == NULL) {
2889b50d902SRodney W. Grimes 		cwarn("%s", in);
28933ffdd81STom Rhodes 		return;
2909b50d902SRodney W. Grimes 	}
2919b50d902SRodney W. Grimes 	if (stat(in, &sb)) {
2929b50d902SRodney W. Grimes 		cwarn("%s", in);
2939b50d902SRodney W. Grimes 		goto err;
2949b50d902SRodney W. Grimes 	}
2959b50d902SRodney W. Grimes 	if (!S_ISREG(sb.st_mode))
2969b50d902SRodney W. Grimes 		isreg = 0;
2979b50d902SRodney W. Grimes 
29833ffdd81STom Rhodes 	/*
29933ffdd81STom Rhodes 	 * Try to read the first few uncompressed bytes from the input file
30033ffdd81STom Rhodes 	 * before blindly truncating the output file.
30133ffdd81STom Rhodes 	 */
30233ffdd81STom Rhodes 	if ((nr = fread(buf, 1, sizeof(buf), ifp)) == 0) {
30333ffdd81STom Rhodes 		cwarn("%s", in);
30433ffdd81STom Rhodes 		(void)fclose(ifp);
30533ffdd81STom Rhodes 		return;
30633ffdd81STom Rhodes 	}
30733ffdd81STom Rhodes 	if ((ofp = fopen(out, "w")) == NULL ||
30833ffdd81STom Rhodes 	    (nr != 0 && fwrite(buf, 1, nr, ofp) != nr)) {
30933ffdd81STom Rhodes 		cwarn("%s", out);
310*b63800acSOleksandr Tymoshenko 		if (ofp)
311*b63800acSOleksandr Tymoshenko 			(void)fclose(ofp);
31233ffdd81STom Rhodes 		(void)fclose(ifp);
31333ffdd81STom Rhodes 		return;
31433ffdd81STom Rhodes 	}
31533ffdd81STom Rhodes 
3169b50d902SRodney W. Grimes 	while ((nr = fread(buf, 1, sizeof(buf), ifp)) != 0)
3179b50d902SRodney W. Grimes 		if (fwrite(buf, 1, nr, ofp) != nr) {
3189b50d902SRodney W. Grimes 			cwarn("%s", out);
3199b50d902SRodney W. Grimes 			goto err;
3209b50d902SRodney W. Grimes 		}
3219b50d902SRodney W. Grimes 
3229b50d902SRodney W. Grimes 	if (ferror(ifp) || fclose(ifp)) {
3239b50d902SRodney W. Grimes 		cwarn("%s", in);
3249b50d902SRodney W. Grimes 		goto err;
3259b50d902SRodney W. Grimes 	}
3269b50d902SRodney W. Grimes 	ifp = NULL;
3279b50d902SRodney W. Grimes 
3289b50d902SRodney W. Grimes 	if (fclose(ofp)) {
3299b50d902SRodney W. Grimes 		cwarn("%s", out);
3309b50d902SRodney W. Grimes 		goto err;
3319b50d902SRodney W. Grimes 	}
3329b50d902SRodney W. Grimes 
3339b50d902SRodney W. Grimes 	if (isreg) {
3349b50d902SRodney W. Grimes 		setfile(out, &sb);
3359b50d902SRodney W. Grimes 
3369b50d902SRodney W. Grimes 		if (unlink(in))
3379b50d902SRodney W. Grimes 			cwarn("%s", in);
3389b50d902SRodney W. Grimes 	}
3399b50d902SRodney W. Grimes 	return;
3409b50d902SRodney W. Grimes 
3419b50d902SRodney W. Grimes err:	if (ofp) {
3429b50d902SRodney W. Grimes 		if (oreg)
3439b50d902SRodney W. Grimes 			(void)unlink(out);
3449b50d902SRodney W. Grimes 		(void)fclose(ofp);
3459b50d902SRodney W. Grimes 	}
3469b50d902SRodney W. Grimes 	if (ifp)
3479b50d902SRodney W. Grimes 		(void)fclose(ifp);
3489b50d902SRodney W. Grimes }
3499b50d902SRodney W. Grimes 
350305700d9SEd Schouten static void
setfile(const char * name,struct stat * fs)35147e9e6a1SDavid Malone setfile(const char *name, struct stat *fs)
3529b50d902SRodney W. Grimes {
353d6b3ef63SJilles Tjoelker 	static struct timespec tspec[2];
3549b50d902SRodney W. Grimes 
3559b50d902SRodney W. Grimes 	fs->st_mode &= S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
3569b50d902SRodney W. Grimes 
357d6b3ef63SJilles Tjoelker 	tspec[0] = fs->st_atim;
358d6b3ef63SJilles Tjoelker 	tspec[1] = fs->st_mtim;
359d6b3ef63SJilles Tjoelker 	if (utimensat(AT_FDCWD, name, tspec, 0))
360d6b3ef63SJilles Tjoelker 		cwarn("utimensat: %s", name);
3619b50d902SRodney W. Grimes 
3629b50d902SRodney W. Grimes 	/*
3639b50d902SRodney W. Grimes 	 * Changing the ownership probably won't succeed, unless we're root
3649b50d902SRodney W. Grimes 	 * or POSIX_CHOWN_RESTRICTED is not set.  Set uid/gid before setting
3659b50d902SRodney W. Grimes 	 * the mode; current BSD behavior is to remove all setuid bits on
3669b50d902SRodney W. Grimes 	 * chown.  If chown fails, lose setuid/setgid bits.
3679b50d902SRodney W. Grimes 	 */
3689b50d902SRodney W. Grimes 	if (chown(name, fs->st_uid, fs->st_gid)) {
3699b50d902SRodney W. Grimes 		if (errno != EPERM)
3709b50d902SRodney W. Grimes 			cwarn("chown: %s", name);
3719b50d902SRodney W. Grimes 		fs->st_mode &= ~(S_ISUID|S_ISGID);
3729b50d902SRodney W. Grimes 	}
373da94aa4eSTim Vanderhoek 	if (chmod(name, fs->st_mode) && errno != EOPNOTSUPP)
374fae643c5SPhilippe Charnier 		cwarn("chmod: %s", name);
3759b50d902SRodney W. Grimes 
376da94aa4eSTim Vanderhoek 	if (chflags(name, fs->st_flags) && errno != EOPNOTSUPP)
3779b50d902SRodney W. Grimes 		cwarn("chflags: %s", name);
3789b50d902SRodney W. Grimes }
3799b50d902SRodney W. Grimes 
380305700d9SEd Schouten static int
permission(const char * fname)38147e9e6a1SDavid Malone permission(const char *fname)
3829b50d902SRodney W. Grimes {
3839b50d902SRodney W. Grimes 	int ch, first;
3849b50d902SRodney W. Grimes 
3859b50d902SRodney W. Grimes 	if (!isatty(fileno(stderr)))
3869b50d902SRodney W. Grimes 		return (0);
3879b50d902SRodney W. Grimes 	(void)fprintf(stderr, "overwrite %s? ", fname);
3889b50d902SRodney W. Grimes 	first = ch = getchar();
3899b50d902SRodney W. Grimes 	while (ch != '\n' && ch != EOF)
3909b50d902SRodney W. Grimes 		ch = getchar();
3919b50d902SRodney W. Grimes 	return (first == 'y');
3929b50d902SRodney W. Grimes }
3939b50d902SRodney W. Grimes 
394305700d9SEd Schouten static void
usage(int iscompress)39547e9e6a1SDavid Malone usage(int iscompress)
3969b50d902SRodney W. Grimes {
3979b50d902SRodney W. Grimes 	if (iscompress)
3989b50d902SRodney W. Grimes 		(void)fprintf(stderr,
3999b50d902SRodney W. Grimes 		    "usage: compress [-cfv] [-b bits] [file ...]\n");
4009b50d902SRodney W. Grimes 	else
4019b50d902SRodney W. Grimes 		(void)fprintf(stderr,
4029b50d902SRodney W. Grimes 		    "usage: uncompress [-c] [-b bits] [file ...]\n");
4039b50d902SRodney W. Grimes 	exit(1);
4049b50d902SRodney W. Grimes }
4059b50d902SRodney W. Grimes 
406305700d9SEd Schouten static void
cwarnx(const char * fmt,...)4079b50d902SRodney W. Grimes cwarnx(const char *fmt, ...)
4089b50d902SRodney W. Grimes {
4099b50d902SRodney W. Grimes 	va_list ap;
4107ddea7b8SWarner Losh 
4119b50d902SRodney W. Grimes 	va_start(ap, fmt);
4129b50d902SRodney W. Grimes 	vwarnx(fmt, ap);
4139b50d902SRodney W. Grimes 	va_end(ap);
4149b50d902SRodney W. Grimes 	eval = 1;
4159b50d902SRodney W. Grimes }
4169b50d902SRodney W. Grimes 
417305700d9SEd Schouten static void
cwarn(const char * fmt,...)4189b50d902SRodney W. Grimes cwarn(const char *fmt, ...)
4199b50d902SRodney W. Grimes {
4209b50d902SRodney W. Grimes 	va_list ap;
4217ddea7b8SWarner Losh 
4229b50d902SRodney W. Grimes 	va_start(ap, fmt);
4239b50d902SRodney W. Grimes 	vwarn(fmt, ap);
4249b50d902SRodney W. Grimes 	va_end(ap);
4259b50d902SRodney W. Grimes 	eval = 1;
4269b50d902SRodney W. Grimes }
427