[BACK]Return to compress.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / compress

Annotation of src/usr.bin/compress/compress.c, Revision 1.1.1.1

1.1       deraadt     1: /*     $NetBSD: compress.c,v 1.9 1995/03/26 09:44:38 glass Exp $       */
                      2:
                      3: /*-
                      4:  * Copyright (c) 1992, 1993
                      5:  *     The Regents of the University of California.  All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  * 3. All advertising materials mentioning features or use of this software
                     16:  *    must display the following acknowledgement:
                     17:  *     This product includes software developed by the University of
                     18:  *     California, Berkeley and its contributors.
                     19:  * 4. Neither the name of the University nor the names of its contributors
                     20:  *    may be used to endorse or promote products derived from this software
                     21:  *    without specific prior written permission.
                     22:  *
                     23:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     24:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     25:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     26:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     27:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     28:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     29:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     30:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     31:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     32:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     33:  * SUCH DAMAGE.
                     34:  */
                     35:
                     36: #ifndef lint
                     37: static char copyright[] =
                     38: "@(#) Copyright (c) 1992, 1993\n\
                     39:        The Regents of the University of California.  All rights reserved.\n";
                     40: #endif /* not lint */
                     41:
                     42: #ifndef lint
                     43: #if 0
                     44: static char sccsid[] = "@(#)compress.c 8.2 (Berkeley) 1/7/94";
                     45: #else
                     46: static char rcsid[] = "$NetBSD: compress.c,v 1.9 1995/03/26 09:44:38 glass Exp $";
                     47: #endif
                     48: #endif /* not lint */
                     49:
                     50: #include <sys/param.h>
                     51: #include <sys/time.h>
                     52: #include <sys/stat.h>
                     53:
                     54: #include <err.h>
                     55: #include <errno.h>
                     56: #include <stdio.h>
                     57: #include <stdlib.h>
                     58: #include <string.h>
                     59: #include <unistd.h>
                     60:
                     61: #ifdef __STDC__
                     62: #include <stdarg.h>
                     63: #else
                     64: #include <varargs.h>
                     65: #endif
                     66:
                     67: void   compress __P((char *, char *, int));
                     68: void   cwarn __P((const char *, ...));
                     69: void   cwarnx __P((const char *, ...));
                     70: void   decompress __P((char *, char *, int));
                     71: int    permission __P((char *));
                     72: void   setfile __P((char *, struct stat *));
                     73: void   usage __P((int));
                     74:
                     75: extern FILE *zopen __P((const char *fname, const char *mode, int bits));
                     76:
                     77: int eval, force, verbose;
                     78:
                     79: int
                     80: main(argc, argv)
                     81:        int argc;
                     82:        char *argv[];
                     83: {
                     84:        enum {COMPRESS, DECOMPRESS} style;
                     85:        size_t len;
                     86:        int bits, cat, ch;
                     87:        char *p, newname[MAXPATHLEN];
                     88:
                     89:        if ((p = rindex(argv[0], '/')) == NULL)
                     90:                p = argv[0];
                     91:        else
                     92:                ++p;
                     93:        if (!strcmp(p, "uncompress"))
                     94:                style = DECOMPRESS;
                     95:        else if (!strcmp(p, "compress"))
                     96:                style = COMPRESS;
                     97:        else
                     98:                errx(1, "unknown program name");
                     99:
                    100:        bits = cat = 0;
                    101:        while ((ch = getopt(argc, argv, "b:cdfv")) != EOF)
                    102:                switch(ch) {
                    103:                case 'b':
                    104:                        bits = strtol(optarg, &p, 10);
                    105:                        if (*p)
                    106:                                errx(1, "illegal bit count -- %s", optarg);
                    107:                        break;
                    108:                case 'c':
                    109:                        cat = 1;
                    110:                        break;
                    111:                case 'd':               /* Backward compatible. */
                    112:                        style = DECOMPRESS;
                    113:                        break;
                    114:                case 'f':
                    115:                        force = 1;
                    116:                        break;
                    117:                case 'v':
                    118:                        verbose = 1;
                    119:                        break;
                    120:                case '?':
                    121:                default:
                    122:                        usage(style == COMPRESS);
                    123:                }
                    124:        argc -= optind;
                    125:        argv += optind;
                    126:
                    127:        if (argc == 0) {
                    128:                switch(style) {
                    129:                case COMPRESS:
                    130:                        (void)compress("/dev/stdin", "/dev/stdout", bits);
                    131:                        break;
                    132:                case DECOMPRESS:
                    133:                        (void)decompress("/dev/stdin", "/dev/stdout", bits);
                    134:                        break;
                    135:                }
                    136:                exit (eval);
                    137:        }
                    138:
                    139:        if (cat == 1 && argc > 1)
                    140:                errx(1, "the -c option permits only a single file argument");
                    141:
                    142:        for (; *argv; ++argv)
                    143:                switch(style) {
                    144:                case COMPRESS:
                    145:                        if (cat) {
                    146:                                compress(*argv, "/dev/stdout", bits);
                    147:                                break;
                    148:                        }
                    149:                        if ((p = rindex(*argv, '.')) != NULL &&
                    150:                            !strcmp(p, ".Z")) {
                    151:                                cwarnx("%s: name already has trailing .Z",
                    152:                                    *argv);
                    153:                                break;
                    154:                        }
                    155:                        len = strlen(*argv);
                    156:                        if (len > sizeof(newname) - 3) {
                    157:                                cwarnx("%s: name too long", *argv);
                    158:                                break;
                    159:                        }
                    160:                        memmove(newname, *argv, len);
                    161:                        newname[len] = '.';
                    162:                        newname[len + 1] = 'Z';
                    163:                        newname[len + 2] = '\0';
                    164:                        compress(*argv, newname, bits);
                    165:                        break;
                    166:                case DECOMPRESS:
                    167:                        len = strlen(*argv);
                    168:                        if ((p = rindex(*argv, '.')) == NULL ||
                    169:                            strcmp(p, ".Z")) {
                    170:                                if (len > sizeof(newname) - 3) {
                    171:                                        cwarnx("%s: name too long", *argv);
                    172:                                        break;
                    173:                                }
                    174:                                memmove(newname, *argv, len);
                    175:                                newname[len] = '.';
                    176:                                newname[len + 1] = 'Z';
                    177:                                newname[len + 2] = '\0';
                    178:                                decompress(newname,
                    179:                                    cat ? "/dev/stdout" : *argv, bits);
                    180:                        } else {
                    181:                                if (len - 2 > sizeof(newname) - 1) {
                    182:                                        cwarnx("%s: name too long", *argv);
                    183:                                        break;
                    184:                                }
                    185:                                memmove(newname, *argv, len - 2);
                    186:                                newname[len - 2] = '\0';
                    187:                                decompress(*argv,
                    188:                                    cat ? "/dev/stdout" : newname, bits);
                    189:                        }
                    190:                        break;
                    191:                }
                    192:        exit (eval);
                    193: }
                    194:
                    195: void
                    196: compress(in, out, bits)
                    197:        char *in, *out;
                    198:        int bits;
                    199: {
                    200:        register int nr;
                    201:        struct stat isb, sb;
                    202:        FILE *ifp, *ofp;
                    203:        int exists, isreg, oreg;
                    204:        u_char buf[1024];
                    205:
                    206:        exists = !stat(out, &sb);
                    207:        if (!force && exists && S_ISREG(sb.st_mode) && !permission(out))
                    208:                return;
                    209:        isreg = oreg = !exists || S_ISREG(sb.st_mode);
                    210:
                    211:        ifp = ofp = NULL;
                    212:        if ((ifp = fopen(in, "r")) == NULL) {
                    213:                cwarn("%s", in);
                    214:                return;
                    215:        }
                    216:        if (stat(in, &isb)) {           /* DON'T FSTAT! */
                    217:                cwarn("%s", in);
                    218:                goto err;
                    219:        }
                    220:        if (!S_ISREG(isb.st_mode))
                    221:                isreg = 0;
                    222:
                    223:        if ((ofp = zopen(out, "w", bits)) == NULL) {
                    224:                cwarn("%s", out);
                    225:                goto err;
                    226:        }
                    227:        while ((nr = fread(buf, 1, sizeof(buf), ifp)) != 0)
                    228:                if (fwrite(buf, 1, nr, ofp) != nr) {
                    229:                        cwarn("%s", out);
                    230:                        goto err;
                    231:                }
                    232:
                    233:        if (ferror(ifp) || fclose(ifp)) {
                    234:                cwarn("%s", in);
                    235:                goto err;
                    236:        }
                    237:        ifp = NULL;
                    238:
                    239:        if (fclose(ofp)) {
                    240:                cwarn("%s", out);
                    241:                goto err;
                    242:        }
                    243:        ofp = NULL;
                    244:
                    245:        if (isreg) {
                    246:                if (stat(out, &sb)) {
                    247:                        cwarn("%s", out);
                    248:                        goto err;
                    249:                }
                    250:
                    251:                if (!force && sb.st_size >= isb.st_size) {
                    252:                        if (verbose)
                    253:                (void)printf("%s: file would grow; left unmodified\n", in);
                    254:                        if (unlink(out))
                    255:                                cwarn("%s", out);
                    256:                        goto err;
                    257:                }
                    258:
                    259:                setfile(out, &isb);
                    260:
                    261:                if (unlink(in))
                    262:                        cwarn("%s", in);
                    263:
                    264:                if (verbose) {
                    265:                        (void)printf("%s: ", out);
                    266:                        if (isb.st_size > sb.st_size)
                    267:                                (void)printf("%.0f%% compression\n",
                    268:                                    ((float)sb.st_size / isb.st_size) * 100.0);
                    269:                        else
                    270:                                (void)printf("%.0f%% expansion\n",
                    271:                                    ((float)isb.st_size / sb.st_size) * 100.0);
                    272:                }
                    273:        }
                    274:        return;
                    275:
                    276: err:   if (ofp) {
                    277:                if (oreg)
                    278:                        (void)unlink(out);
                    279:                (void)fclose(ofp);
                    280:        }
                    281:        if (ifp)
                    282:                (void)fclose(ifp);
                    283: }
                    284:
                    285: void
                    286: decompress(in, out, bits)
                    287:        char *in, *out;
                    288:        int bits;
                    289: {
                    290:        register int nr;
                    291:        struct stat sb;
                    292:        FILE *ifp, *ofp;
                    293:        int exists, isreg, oreg;
                    294:        u_char buf[1024];
                    295:
                    296:        exists = !stat(out, &sb);
                    297:        if (!force && exists && S_ISREG(sb.st_mode) && !permission(out))
                    298:                return;
                    299:        isreg = oreg = !exists || S_ISREG(sb.st_mode);
                    300:
                    301:        ifp = ofp = NULL;
                    302:        if ((ofp = fopen(out, "w")) == NULL) {
                    303:                cwarn("%s", out);
                    304:                return;
                    305:        }
                    306:
                    307:        if ((ifp = zopen(in, "r", bits)) == NULL) {
                    308:                cwarn("%s", in);
                    309:                goto err;
                    310:        }
                    311:        if (stat(in, &sb)) {
                    312:                cwarn("%s", in);
                    313:                goto err;
                    314:        }
                    315:        if (!S_ISREG(sb.st_mode))
                    316:                isreg = 0;
                    317:
                    318:        while ((nr = fread(buf, 1, sizeof(buf), ifp)) != 0)
                    319:                if (fwrite(buf, 1, nr, ofp) != nr) {
                    320:                        cwarn("%s", out);
                    321:                        goto err;
                    322:                }
                    323:
                    324:        if (ferror(ifp) || fclose(ifp)) {
                    325:                cwarn("%s", in);
                    326:                goto err;
                    327:        }
                    328:        ifp = NULL;
                    329:
                    330:        if (fclose(ofp)) {
                    331:                cwarn("%s", out);
                    332:                goto err;
                    333:        }
                    334:
                    335:        if (isreg) {
                    336:                setfile(out, &sb);
                    337:
                    338:                if (unlink(in))
                    339:                        cwarn("%s", in);
                    340:        }
                    341:        return;
                    342:
                    343: err:   if (ofp) {
                    344:                if (oreg)
                    345:                        (void)unlink(out);
                    346:                (void)fclose(ofp);
                    347:        }
                    348:        if (ifp)
                    349:                (void)fclose(ifp);
                    350: }
                    351:
                    352: void
                    353: setfile(name, fs)
                    354:        char *name;
                    355:        register struct stat *fs;
                    356: {
                    357:        static struct timeval tv[2];
                    358:
                    359:        fs->st_mode &= S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
                    360:
                    361:        TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atimespec);
                    362:        TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtimespec);
                    363:        if (utimes(name, tv))
                    364:                cwarn("utimes: %s", name);
                    365:
                    366:        /*
                    367:         * Changing the ownership probably won't succeed, unless we're root
                    368:         * or POSIX_CHOWN_RESTRICTED is not set.  Set uid/gid before setting
                    369:         * the mode; current BSD behavior is to remove all setuid bits on
                    370:         * chown.  If chown fails, lose setuid/setgid bits.
                    371:         */
                    372:        if (chown(name, fs->st_uid, fs->st_gid)) {
                    373:                if (errno != EPERM)
                    374:                        cwarn("chown: %s", name);
                    375:                fs->st_mode &= ~(S_ISUID|S_ISGID);
                    376:        }
                    377:        if (chmod(name, fs->st_mode))
                    378:                cwarn("chown: %s", name);
                    379:
                    380:        if (chflags(name, fs->st_flags))
                    381:                cwarn("chflags: %s", name);
                    382: }
                    383:
                    384: int
                    385: permission(fname)
                    386:        char *fname;
                    387: {
                    388:        int ch, first;
                    389:
                    390:        if (!isatty(fileno(stderr)))
                    391:                return (0);
                    392:        (void)fprintf(stderr, "overwrite %s? ", fname);
                    393:        first = ch = getchar();
                    394:        while (ch != '\n' && ch != EOF)
                    395:                ch = getchar();
                    396:        return (first == 'y');
                    397: }
                    398:
                    399: void
                    400: usage(iscompress)
                    401:        int iscompress;
                    402: {
                    403:        if (iscompress)
                    404:                (void)fprintf(stderr,
                    405:                    "usage: compress [-cfv] [-b bits] [file ...]\n");
                    406:        else
                    407:                (void)fprintf(stderr,
                    408:                    "usage: uncompress [-c] [-b bits] [file ...]\n");
                    409:        exit(1);
                    410: }
                    411:
                    412: void
                    413: #if __STDC__
                    414: cwarnx(const char *fmt, ...)
                    415: #else
                    416: cwarnx(fmt, va_alist)
                    417:        int eval;
                    418:        const char *fmt;
                    419:        va_dcl
                    420: #endif
                    421: {
                    422:        va_list ap;
                    423: #if __STDC__
                    424:        va_start(ap, fmt);
                    425: #else
                    426:        va_start(ap);
                    427: #endif
                    428:        vwarnx(fmt, ap);
                    429:        va_end(ap);
                    430:        eval = 1;
                    431: }
                    432:
                    433: void
                    434: #if __STDC__
                    435: cwarn(const char *fmt, ...)
                    436: #else
                    437: cwarn(fmt, va_alist)
                    438:        int eval;
                    439:        const char *fmt;
                    440:        va_dcl
                    441: #endif
                    442: {
                    443:        va_list ap;
                    444: #if __STDC__
                    445:        va_start(ap, fmt);
                    446: #else
                    447:        va_start(ap);
                    448: #endif
                    449:        vwarn(fmt, ap);
                    450:        va_end(ap);
                    451:        eval = 1;
                    452: }