* Copyright (c) 1992 The Regents of the University of California.
* %sccs.include.redist.c%
"@(#) Copyright (c) 1992 The Regents of the University of California.\n\
static char sccsid
[] = "@(#)compress.c 5.26 (Berkeley) %G%";
void compress
__P((char *, char *, int));
void cwarn
__P((const char *, ...));
void cwarnx
__P((const char *, ...));
void decompress
__P((char *, char *, int));
void err
__P((int, const char *, ...));
int permission
__P((char *));
void setfile
__P((char *, struct stat
*));
int eval
, force
, verbose
;
enum {COMPRESS
, DECOMPRESS
} style
;
char *p
, newname
[MAXPATHLEN
];
if ((p
= rindex(argv
[0], '/')) == NULL
)
if (!strcmp(p
, "uncompress"))
else if (!strcmp(p
, "compress"))
errx(1, "unknown program name");
while ((ch
= getopt(argc
, argv
, "b:cdfv")) != EOF
)
bits
= strtol(optarg
, &p
, 10);
errx(1, "illegal bit count -- %s", optarg
);
case 'd': /* Backward compatible. */
usage(style
== COMPRESS
);
(void)compress("/dev/stdin", "/dev/stdout", bits
);
(void)decompress("/dev/stdin", "/dev/stdout", bits
);
if (cat
== 1 && argc
> 1)
errx(1, "the -c option permits only a single file argument");
compress(*argv
, "/dev/stdout", bits
);
if ((p
= rindex(*argv
, '.')) != NULL
&&
cwarnx("%s: name already has trailing .Z",
if (len
> sizeof(newname
) - 3) {
cwarnx("%s: name too long", *argv
);
memmove(newname
, *argv
, len
);
compress(*argv
, newname
, bits
);
if ((p
= rindex(*argv
, '.')) == NULL
||
if (len
> sizeof(newname
) - 3) {
cwarnx("%s: name too long", *argv
);
memmove(newname
, *argv
, len
);
cat
? "/dev/stdout" : *argv
, bits
);
if (len
- 2 > sizeof(newname
) - 1) {
cwarnx("%s: name too long", *argv
);
memmove(newname
, *argv
, len
- 2);
cat
? "/dev/stdout" : newname
, bits
);
exists
= !stat(out
, &sb
);
if (!force
&& exists
&& S_ISREG(sb
.st_mode
) && !permission(out
))
isreg
= oreg
= !exists
|| S_ISREG(sb
.st_mode
);
if ((ifp
= fopen(in
, "r")) == NULL
) {
if (stat(in
, &isb
)) { /* DON'T FSTAT! */
if (!S_ISREG(isb
.st_mode
))
if ((ofp
= zopen(out
, "w", bits
)) == NULL
) {
while ((nr
= fread(buf
, 1, sizeof(buf
), ifp
)) != 0)
if (fwrite(buf
, 1, nr
, ofp
) != nr
) {
if (ferror(ifp
) || fclose(ifp
)) {
if (!force
&& sb
.st_size
>= isb
.st_size
) {
(void)printf("%s: file would grow; left unmodified\n", in
);
(void)printf("%s: ", out
);
if (isb
.st_size
> sb
.st_size
)
(void)printf("%.0f%% compression\n",
((float)sb
.st_size
/ isb
.st_size
) * 100.0);
(void)printf("%.0f%% expansion\n",
((float)isb
.st_size
/ sb
.st_size
) * 100.0);
decompress(in
, out
, bits
)
exists
= !stat(out
, &sb
);
if (!force
&& exists
&& S_ISREG(sb
.st_mode
) && !permission(out
))
isreg
= oreg
= !exists
|| S_ISREG(sb
.st_mode
);
if ((ofp
= fopen(out
, "w")) == NULL
) {
if ((ifp
= zopen(in
, "r", bits
)) == NULL
) {
if (!S_ISREG(sb
.st_mode
))
while ((nr
= fread(buf
, 1, sizeof(buf
), ifp
)) != 0)
if (fwrite(buf
, 1, nr
, ofp
) != nr
) {
if (ferror(ifp
) || fclose(ifp
)) {
register struct stat
*fs
;
static struct timeval tv
[2];
fs
->st_mode
&= S_ISUID
|S_ISGID
|S_IRWXU
|S_IRWXG
|S_IRWXO
;
TIMESPEC_TO_TIMEVAL(&tv
[0], &fs
->st_atimespec
);
TIMESPEC_TO_TIMEVAL(&tv
[1], &fs
->st_mtimespec
);
cwarn("utimes: %s", name
);
* Changing the ownership probably won't succeed, unless we're root
* or POSIX_CHOWN_RESTRICTED is not set. Set uid/gid before setting
* the mode; current BSD behavior is to remove all setuid bits on
* chown. If chown fails, lose setuid/setgid bits.
if (chown(name
, fs
->st_uid
, fs
->st_gid
)) {
cwarn("chown: %s", name
);
fs
->st_mode
&= ~(S_ISUID
|S_ISGID
);
if (chmod(name
, fs
->st_mode
))
cwarn("chown: %s", name
);
if (chflags(name
, fs
->st_flags
))
cwarn("chflags: %s", name
);
if (!isatty(fileno(stderr
)))
(void)fprintf(stderr
, "overwrite %s? ", fname
);
while (ch
!= '\n' && ch
!= EOF
)
"usage: compress [-cfv] [-b bits] [file ...]\n");
"usage: uncompress [-c] [-b bits] [file ...]\n");
cwarnx(const char *fmt
, ...)
cwarn(const char *fmt
, ...)