# # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # PROG= compress SRCS= compress.c $(SRC)/common/util/getresponse.c OBJS= compress.o getresponse.o include ../Makefile.cmd .KEEP_STATE: CFLAGS += $(CCVERBOSE) CERRWARN += -Wno-parentheses CERRWARN += -Wno-clobbered CPPFLAGS += -D_FILE_OFFSET_BITS=64 -I $(SRC)/common/util LINTFLAGS += -u LDLIBS += -lcmdutils -lsec all: $(PROG) %.o: $(SRC)/common/util/%.c $(COMPILE.c) $(OUTPUT_OPTION) $< $(POST_PROCESS_O) $(PROG): $(OBJS) $(LINK.c) $(OBJS) -o $@ $(LDLIBS) $(POST_PROCESS) install: all $(ROOTPROG) $(RM) $(ROOTBIN)/uncompress $(ROOTBIN)/zcat $(LN) $(ROOTPROG) $(ROOTBIN)/uncompress $(LN) $(ROOTPROG) $(ROOTBIN)/zcat clean: $(RM) $(OBJS) lint: lint_SRCS include ../Makefile.targ Copyright (c) 1986 Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. All advertising materials mentioning features or use of this software must display the following acknowledgement: This product includes software developed by the University of California, Berkeley and its contributors. 4. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. PORTIONS OF COMPRESS COMMAND FUNCTIONALITY /* * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 1986 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. */ /* * Copyright (c) 2018, Joyent, Inc. */ /* * Compress - data compression program */ #define min(a, b) ((a > b) ? b : a) /* * machine variants which require cc -Dmachine: pdp11, z8000, pcxt */ /* * Set USERMEM to the maximum amount of physical user memory available * in bytes. USERMEM is used to determine the maximum BITS that can be used * for compression. * * SACREDMEM is the amount of physical memory saved for others; compress * will hog the rest. */ #ifndef SACREDMEM #define SACREDMEM 0 #endif #ifndef USERMEM #define USERMEM 450000 /* default user memory */ #endif #ifdef USERMEM #if USERMEM >= (433484+SACREDMEM) #define PBITS 16 #else #if USERMEM >= (229600+SACREDMEM) #define PBITS 15 #else #if USERMEM >= (127536+SACREDMEM) #define PBITS 14 #else #if USERMEM >= (73464+SACREDMEM) #define PBITS 13 #else #define PBITS 12 #endif #endif #endif #endif #undef USERMEM #endif /* USERMEM */ #ifdef PBITS /* Preferred BITS for this memory size */ #ifndef BITS #define BITS PBITS #endif /* BITS */ #endif /* PBITS */ #if BITS == 16 #define HSIZE 69001 /* 95% occupancy */ #endif #if BITS == 15 #define HSIZE 35023 /* 94% occupancy */ #endif #if BITS == 14 #define HSIZE 18013 /* 91% occupancy */ #endif #if BITS == 13 #define HSIZE 9001 /* 91% occupancy */ #endif #if BITS <= 12 #define HSIZE 5003 /* 80% occupancy */ #endif #define OUTSTACKSIZE (2< 15 typedef long int code_int; #else typedef int code_int; #endif typedef long int count_int; typedef long long count_long; typedef unsigned char char_type; static char_type magic_header[] = { "\037\235" }; /* 1F 9D */ /* Defines for third byte of header */ #define BIT_MASK 0x1f #define BLOCK_MASK 0x80 /* * Masks 0x40 and 0x20 are free. I think 0x20 should mean that there is * a fourth header byte(for expansion). */ #define INIT_BITS 9 /* initial number of bits/code */ /* * compress.c - File compression ala IEEE Computer, June 1984. */ static char rcs_ident[] = "$Header: compress.c,v 4.0 85/07/30 12:50:00 joe Release $"; #include #include #include #include #include #include #include #include #include #include #include #include "getresponse.h" static int n_bits; /* number of bits/code */ static int maxbits = BITS; /* user settable max # bits/code */ static code_int maxcode; /* maximum code, given n_bits */ /* should NEVER generate this code */ static code_int maxmaxcode = 1 << BITS; #define MAXCODE(n_bits) ((1 << (n_bits)) - 1) static count_int htab [OUTSTACKSIZE]; static unsigned short codetab [OUTSTACKSIZE]; #define htabof(i) htab[i] #define codetabof(i) codetab[i] static code_int hsize = HSIZE; /* for dynamic table sizing */ static off_t fsize; /* file size of input file */ /* * To save much memory, we overlay the table used by compress() with those * used by decompress(). The tab_prefix table is the same size and type * as the codetab. The tab_suffix table needs 2**BITS characters. We * get this from the beginning of htab. The output stack uses the rest * of htab, and contains characters. There is plenty of room for any * possible stack (stack used to be 8000 characters). */ #define tab_prefixof(i) codetabof(i) #define tab_suffixof(i) ((char_type *)(htab))[i] #define de_stack ((char_type *)&tab_suffixof(1< debug * -V = > print Version; debug verbose * -d = > do_decomp * -v = > unquiet * -f = > force overwrite of output file * -n = > no header: useful to uncompress old files * -b maxbits => maxbits. If -b is specified, * then maxbits MUST be given also. * -c = > cat all output to stdout * -C = > generate output compatible with compress 2.0. * if a string is left, must be an input filename. */ #ifdef DEBUG optstr = "b:cCdDfFnqvV/"; #else optstr = "b:cCdfFnqvV/"; #endif while ((ch = getopt(argc, argv, optstr)) != EOF) { /* Process all flags in this arg */ switch (ch) { #ifdef DEBUG case 'D': debug = 1; break; case 'V': verbose = 1; version(); break; #else case 'V': version(); Vflg++; break; #endif /* DEBUG */ case 'v': quiet = 0; vflg++; break; case 'd': do_decomp = 1; dflg++; break; case 'f': case 'F': Fflg++; overwrite = 1; force = 1; break; case 'n': nomagic = 1; break; case 'C': Cflg++; block_compress = 0; break; case 'b': bflg++; p = optarg; if (!p) { (void) fprintf(stderr, gettext( "Missing maxbits\n")); Usage(); exit(1); } maxbits = strtoul(optarg, &p, 10); if (*p) { (void) fprintf(stderr, gettext( "Missing maxbits\n")); Usage(); exit(1); } break; case 'c': cflg++; zcat_flg = 1; break; case 'q': qflg++; quiet = 1; break; case '/': saflg++; break; default: (void) fprintf(stderr, gettext( "Unknown flag: '%c'\n"), optopt); Usage(); exit(1); } } /* while */ /* * Validate zcat syntax */ if (zcat_cmd && (Fflg | Cflg | cflg | bflg | qflg | dflg | nomagic)) { (void) fprintf(stderr, gettext( "Invalid Option\n")); Usage(); exit(1); } /* * Process the file list */ for (; optind < argc; optind++) { if (strcmp(argv[optind], "-") == 0) { dash_count++; } *fileptr++ = argv[optind]; /* Build input file list */ *fileptr = NULL; } if (dash_count > 1) { (void) fprintf(stderr, gettext("%s may only appear once in the file" " list\n"), "\"-\""); exit(1); } if (fileptr - filelist == 0) { *fileptr++ = "-"; *fileptr = NULL; } if (fileptr - filelist > 1 && cflg && !do_decomp) { (void) fprintf(stderr, gettext("compress: only one file may be compressed" " to stdout\n")); exit(1); } if (maxbits < INIT_BITS) maxbits = INIT_BITS; if (maxbits > BITS) maxbits = BITS; maxmaxcode = 1 << maxbits; /* Need to open something to close with freopen later */ if ((infile = fopen("/dev/null", "r")) == NULL) { (void) fprintf(stderr, gettext("Error opening /dev/null for " "input\n")); exit(1); } if ((outfile = fopen("/dev/null", "w")) == NULL) { (void) fprintf(stderr, gettext("Error opening /dev/null for " "output\n")); exit(1); } for (fileptr = filelist; *fileptr; fileptr++) { int jmpval = 0; didnt_shrink = 0; newline_needed = 0; if (do_decomp) { /* DECOMPRESSION */ if (strcmp(*fileptr, "-") == 0) { /* process stdin */ inp = stdin; outp = stdout; use_stdout = 1; *fileptr = "stdin"; /* for error messages */ } else { /* process the named file */ inp = infile; outp = outfile; use_stdout = 0; if (zcat_flg) { use_stdout = 1; outp = stdout; } /* Check for .Z suffix */ if (strcmp(*fileptr + strlen(*fileptr) - 2, ".Z") != 0) { /* No .Z: tack one on */ if (strlcpy(tempname, *fileptr, sizeof (tempname)) >= sizeof (tempname)) { (void) fprintf(stderr, gettext("%s: filename " "too long\n"), *fileptr); perm_stat = 1; continue; } if (addDotZ(tempname, sizeof (tempname)) < 0) { perm_stat = 1; continue; } *fileptr = tempname; } /* Open input file */ if (stat(*fileptr, &statbuf) < 0) { perror(*fileptr); perm_stat = 1; continue; } if ((freopen(*fileptr, "r", inp)) == NULL) { perror(*fileptr); perm_stat = 1; continue; } } /* Check the magic number */ if (nomagic == 0) { if ((getc(inp) != (magic_header[0] & 0xFF)) || (getc(inp) != (magic_header[1] & 0xFF))) { (void) fprintf(stderr, gettext( "%s: not in compressed " "format\n"), *fileptr); perm_stat = 1; continue; } /* set -b from file */ if ((maxbits = getc(inp)) == EOF && ferror(inp)) { perror(*fileptr); perm_stat = 1; continue; } block_compress = maxbits & BLOCK_MASK; maxbits &= BIT_MASK; maxmaxcode = 1 << maxbits; if (maxbits > BITS) { (void) fprintf(stderr, gettext("%s: compressed " "with %d bits, " "can only handle" " %d bits\n"), *fileptr, maxbits, BITS); perm_stat = 1; continue; } } if (!use_stdout) { /* Generate output filename */ if (strlcpy(ofname, *fileptr, sizeof (ofname)) >= sizeof (ofname)) { (void) fprintf(stderr, gettext("%s: filename " "too long\n"), *fileptr); perm_stat = 1; continue; } /* Strip off .Z */ ofname[strlen(*fileptr) - 2] = '\0'; } } else { /* COMPRESSION */ if (strcmp(*fileptr, "-") == 0) { /* process stdin */ inp = stdin; outp = stdout; use_stdout = 1; *fileptr = "stdin"; /* for error messages */ /* Use the largest possible hash table */ hsize = HSIZE; } else { /* process the named file */ inp = infile; outp = outfile; use_stdout = 0; if (zcat_flg) { use_stdout = 1; outp = stdout; } if (strcmp(*fileptr + strlen(*fileptr) - 2, ".Z") == 0) { (void) fprintf(stderr, gettext( "%s: already has .Z " "suffix -- no change\n"), *fileptr); perm_stat = 1; continue; } /* Open input file */ if (stat(*fileptr, &statbuf) < 0) { perror(*fileptr); perm_stat = 1; continue; } if ((freopen(*fileptr, "r", inp)) == NULL) { perror(*fileptr); perm_stat = 1; continue; } fsize = (off_t)statbuf.st_size; /* * tune hash table size for small * files -- ad hoc, * but the sizes match earlier #defines, which * serve as upper bounds on the number of * output codes. */ hsize = HSIZE; if (fsize < (1 << 12)) hsize = min(5003, HSIZE); else if (fsize < (1 << 13)) hsize = min(9001, HSIZE); else if (fsize < (1 << 14)) hsize = min(18013, HSIZE); else if (fsize < (1 << 15)) hsize = min(35023, HSIZE); else if (fsize < 47000) hsize = min(50021, HSIZE); if (!use_stdout) { /* Generate output filename */ if (strlcpy(ofname, *fileptr, sizeof (ofname)) >= sizeof (ofname)) { (void) fprintf(stderr, gettext("%s: filename " "too long\n"), *fileptr); perm_stat = 1; continue; } if (addDotZ(ofname, sizeof (ofname)) < 0) { perm_stat = 1; continue; } } } } /* if (do_decomp) */ /* Check for overwrite of existing file */ if (!overwrite && !use_stdout) { if (stat(ofname, &ostatbuf) == 0) { (void) fprintf(stderr, gettext( "%s already exists;"), ofname); if (bgnd_flag == 0 && isatty(2)) { int cin; (void) fprintf(stderr, gettext( " do you wish to overwr" "ite %s (%s or %s)? "), ofname, yesstr, nostr); (void) fflush(stderr); for (cin = 0; cin < LINE_MAX; cin++) line[cin] = 0; (void) read(2, line, LINE_MAX); if (yes_check(line) == 0) { (void) fprintf(stderr, gettext( "\tnot overwri" "tten\n")); continue; } } else { /* * XPG4: Assertion 1009 * Standard input is not * terminal, and no '-f', * and file exists. */ (void) fprintf(stderr, gettext( "%s: File exists, -f not" " specified, and ru" "nning in the backgro" "und.\n"), *fileptr); perm_stat = 1; continue; } } } if (!use_stdout) { if ((pathconf(ofname, _PC_XATTR_EXISTS) == 1) || (saflg && sysattr_support(ofname, _PC_SATTR_EXISTS) == 1)) { (void) unlink(ofname); } /* Open output file */ if (freopen(ofname, "w", outp) == NULL) { perror(ofname); perm_stat = 1; continue; } precious = 0; if (!quiet) { (void) fprintf(stderr, "%s: ", *fileptr); newline_needed = 1; } } else if (!quiet && !do_decomp) { (void) fprintf(stderr, "%s: ", *fileptr); newline_needed = 1; } /* Actually do the compression/decompression */ if ((jmpval = setjmp(env)) == 0) { /* We'll see how things go */ #ifndef DEBUG if (do_decomp == 0) { compress(); } else { decompress(); } #else if (do_decomp == 0) { compress(); } else if (debug == 0) { decompress(); } else { printcodes(); } if (verbose) { dump_tab(); } #endif } else { /* * Things went badly - clean up and go on. * jmpval's values break down as follows: * 1 == message determined by ferror() values. * 2 == input problem message needed. * 3 == output problem message needed. */ if (ferror(inp) || jmpval == 2) { if (do_decomp) { (void) fprintf(stderr, gettext( "uncompress: %s: corrupt" " input\n"), *fileptr); } else { perror(*fileptr); } } if (ferror(outp) || jmpval == 3) { /* handle output errors */ if (use_stdout) { perror(""); } else { perror(ofname); } } if (ofname[0] != '\0') { if (unlink(ofname) < 0) { perror(ofname); } ofname[0] = '\0'; } perm_stat = 1; continue; } /* Things went well */ if (!use_stdout) { /* Copy stats */ copystat(*fileptr, &statbuf, ofname); precious = 1; if (newline_needed) { (void) putc('\n', stderr); } /* * Print the info. for unchanged file * when no -v */ if (didnt_shrink) { if (!force && perm_stat == 0) { if (quiet) { (void) fprintf(stderr, gettext( "%s: -- file " "unchanged\n"), *fileptr); } perm_stat = 2; } } } else { if (didnt_shrink && !force && perm_stat == 0) { perm_stat = 2; } if (newline_needed) { (void) fprintf(stderr, "\n"); } } } /* for */ return (perm_stat); } static void cinterr(int hshift) { /* we have exceeded the hash table */ (void) fprintf(stderr, "internal error: hashtable exceeded - hsize = %ld\n", hsize); (void) fprintf(stderr, "hshift = %d, %d\n", hshift, (1 << hshift) -1); (void) fprintf(stderr, "maxbits = %d\n", maxbits); (void) fprintf(stderr, "n_bits = %d\n", n_bits); (void) fprintf(stderr, "maxcode = %ld\n", maxcode); longjmp(env, 1); } static code_int adjusti(code_int i, code_int hsize_reg) { while (i < 0) { i += hsize_reg; } while (i >= hsize_reg) { i -= hsize_reg; } return (i); } /* * compress inp to outp * * Algorithm: use open addressing double hashing(no chaining) on the * prefix code / next character combination. We do a variant of Knuth's * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime * secondary probe. Here, the modular division first probe is gives way * to a faster exclusive-or manipulation. Also do block compression with * an adaptive reset, whereby the code table is cleared when the compression * ratio decreases, but after the table fills. The variable-length output * codes are re-sized at this point, and a special CLEAR code is generated * for the decompressor. Late addition: construct the table according to * file size for noticeable speed improvement on small files. Please direct * questions about this implementation to ames!jaw. */ static void compress() { long fcode; code_int i = 0; int c; code_int ent; int disp; code_int hsize_reg; int hshift; int probecnt; count_long in_count; uint32_t inchi, inclo; int maxbits_reg; FILE *fin = inp; #ifdef DEBUG count_long out_count = 0; #endif if (nomagic == 0) { if ((putc(magic_header[0], outp) == EOF || putc(magic_header[1], outp) == EOF || putc((char)(maxbits | block_compress), outp) == EOF) && ferror(outp)) { ioerror(); } } offset = 0; bytes_out = 3; /* includes 3-byte header mojo */ clear_flg = 0; ratio = 0; in_count = 1; inchi = 0; inclo = 1; checkpoint = CHECK_GAP; maxcode = MAXCODE(n_bits = INIT_BITS); free_ent = ((block_compress) ? FIRST : 256); if ((ent = getc(fin)) == EOF && ferror(fin)) { ioerror(); } hshift = 0; for (fcode = (long)hsize; fcode < 65536L; fcode *= 2L) hshift++; hshift = 8 - hshift; /* set hash code range bound */ hsize_reg = hsize; maxbits_reg = maxbits; cl_hash((count_int) hsize_reg); /* clear hash table */ while ((c = getc(fin)) != EOF) { if (++inclo == 0) inchi++; fcode = (long)(((long)c << maxbits_reg) + ent); i = ((c << hshift) ^ ent); /* xor hashing */ if ((unsigned int)i >= hsize_reg) i = adjusti(i, hsize_reg); if (htabof(i) == fcode) { ent = codetabof(i); continue; } else if ((long)htabof(i) < 0) { /* empty slot */ goto nomatch; } /* secondary hash (after G. Knott) */ disp = hsize_reg - i; if (i == 0) { disp = 1; } probecnt = 0; probe: if (++probecnt > hsize_reg) cinterr(hshift); if ((i -= disp) < 0) { while (i < 0) i += hsize_reg; } if (htabof(i) == fcode) { ent = codetabof(i); continue; } if ((long)htabof(i) > 0) { goto probe; } nomatch: output((code_int) ent); #ifdef DEBUG out_count++; #endif ent = c; if (free_ent < maxmaxcode) { codetabof(i) = free_ent++; /* code -> hashtable */ htabof(i) = fcode; } else { in_count = ((long long)inchi<<32|inclo); if ((count_long)in_count >= (count_long)checkpoint && block_compress) { cl_block(in_count); } } } in_count = ((long long)inchi<<32|inclo); if (ferror(fin) != 0) { ioerror(); } /* * Put out the final code. */ output((code_int)ent); #ifdef DEBUG out_count++; #endif output((code_int)-1); /* * Print out stats on stderr */ if (!quiet) { #ifdef DEBUG (void) fprintf(stderr, "%lld chars in, %lld codes (%lld bytes) out, " "compression factor: ", (count_long)in_count, (count_long)out_count, (count_long) bytes_out); prratio(stderr, (count_long)in_count, (count_long)bytes_out); (void) fprintf(stderr, "\n"); (void) fprintf(stderr, "\tCompression as in compact: "); prratio(stderr, (count_long)in_count-(count_long)bytes_out, (count_long)in_count); (void) fprintf(stderr, "\n"); (void) fprintf(stderr, "\tLargest code (of last block) was %d" " (%d bits)\n", free_ent - 1, n_bits); #else /* !DEBUG */ (void) fprintf(stderr, gettext("Compression: ")); prratio(stderr, (count_long)in_count-(count_long)bytes_out, (count_long)in_count); #endif /* DEBUG */ } /* report if no savings */ if ((count_long)bytes_out > (count_long)in_count) { didnt_shrink = 1; } } /* * ************************************************************** * TAG(output) * * Output the given code. * Inputs: * code: A n_bits-bit integer. If == -1, then EOF. This assumes * that n_bits = < (long)wordsize - 1. * Outputs: * Outputs code to the file. * Assumptions: * Chars are 8 bits long. * Algorithm: * Maintain a BITS character long buffer(so that 8 codes will * fit in it exactly). Use the VAX insv instruction to insert each * code in turn. When the buffer fills up empty it and start over. */ static void output(code_int code) { #ifdef DEBUG static int col = 0; #endif /* DEBUG */ int r_off = offset, bits = n_bits; char *bp = buf; #ifdef DEBUG if (verbose) (void) fprintf(stderr, "%5d%c", code, (col += 6) >= 74 ? (col = 0, '\n') : ' '); #endif /* DEBUG */ if (code >= 0) { /* * byte/bit numbering on the VAX is simulated * by the following code */ /* * Get to the first byte. */ bp += (r_off >> 3); r_off &= 7; /* * Since code is always >= 8 bits, only need to mask the first * hunk on the left. */ *bp = (*bp & rmask[r_off]) | (code << r_off) & lmask[r_off]; bp++; bits -= (8 - r_off); code >>= 8 - r_off; /* * Get any 8 bit parts in the middle (<=1 for up to 16 * bits). */ if (bits >= 8) { *bp++ = code; code >>= 8; bits -= 8; } /* Last bits. */ if (bits) *bp = code; offset += n_bits; if (offset == (n_bits << 3)) { bp = buf; bits = n_bits; bytes_out += bits; do { if (putc(*bp, outp) == EOF && ferror(outp)) { ioerror(); } bp++; } while (--bits); offset = 0; } /* * If the next entry is going to be too big for the code size, * then increase it, if possible. */ if (free_ent > maxcode || (clear_flg > 0)) { /* * Write the whole buffer, because the input * side won't discover the size increase until * after it has read it. */ if (offset > 0) { if (fwrite(buf, 1, n_bits, outp) != n_bits) { longjmp(env, 3); } bytes_out += n_bits; } offset = 0; if (clear_flg) { maxcode = MAXCODE(n_bits = INIT_BITS); clear_flg = 0; } else { n_bits++; if (n_bits == maxbits) maxcode = maxmaxcode; else maxcode = MAXCODE(n_bits); } #ifdef DEBUG if (debug) { (void) fprintf(stderr, "\nChange to %d bits\n", n_bits); col = 0; } #endif /* DEBUG */ } } else { /* * At EOF, write the rest of the buffer. */ if (offset > 0) { if (fwrite(buf, 1, (offset + 7) / 8, outp) == 0 && ferror(outp)) { ioerror(); } bytes_out += (offset + 7) / 8; } offset = 0; (void) fflush(outp); #ifdef DEBUG if (verbose) (void) fprintf(stderr, "\n"); #endif /* DEBUG */ if (ferror(outp)) ioerror(); } } /* * Decompress inp to outp. This routine adapts to the codes in the * file building the "string" table on-the-fly; requiring no table to * be stored in the compressed file. The tables used herein are shared * with those of the compress() routine. See the definitions above. */ static void decompress() { char_type *stackp, *stack_lim; int finchar; code_int code, oldcode, incode; FILE *fout = outp; /* * As above, initialize the first 256 entries in the table. */ maxcode = MAXCODE(n_bits = INIT_BITS); for (code = 255; code >= 0; code--) { tab_prefixof(code) = 0; tab_suffixof(code) = (char_type)code; } free_ent = ((block_compress) ? FIRST : 256); finchar = oldcode = getcode(); if (oldcode == -1) /* EOF already? */ return; /* Get out of here */ /* first code must be 8 bits = char */ if (putc((char)finchar, outp) == EOF && ferror(outp)) { /* Crash if can't write */ ioerror(); } stackp = de_stack; stack_lim = stack_max; while ((code = getcode()) > -1) { if ((code == CLEAR) && block_compress) { for (code = 255; code >= 0; code--) tab_prefixof(code) = 0; clear_flg = 1; free_ent = FIRST - 1; if ((code = getcode()) == -1) /* O, untimely death! */ break; } incode = code; /* * Special case for KwKwK string. */ if (code >= free_ent) { if (stackp < stack_lim) { *stackp++ = (char_type) finchar; code = oldcode; } else { /* badness */ longjmp(env, 2); } } /* * Generate output characters in reverse order */ while (code >= 256) { if (stackp < stack_lim) { *stackp++ = tab_suffixof(code); code = tab_prefixof(code); } else { /* badness */ longjmp(env, 2); } } *stackp++ = finchar = tab_suffixof(code); /* * And put them out in forward order */ do { stackp--; (void) putc(*stackp, fout); } while (stackp > de_stack); if (ferror(fout)) ioerror(); /* * Generate the new entry. */ if ((code = free_ent) < maxmaxcode) { tab_prefixof(code) = (unsigned short) oldcode; tab_suffixof(code) = (char_type) finchar; free_ent = code+1; } /* * Remember previous code. */ oldcode = incode; } (void) fflush(outp); if (ferror(outp)) ioerror(); } /* * ************************************************************** * TAG( getcode ) * * Read one code from the standard input. If EOF, return -1. * Inputs: * inp * Outputs: * code or -1 is returned. */ code_int getcode() { code_int code; static int offset = 0, size = 0; static char_type buf[BITS]; int r_off, bits; char_type *bp = buf; if (clear_flg > 0 || offset >= size || free_ent > maxcode) { /* * If the next entry will be too big for the current code * size, then we must increase the size. This implies reading * a new buffer full, too. */ if (free_ent > maxcode) { n_bits++; if (n_bits == maxbits) /* won't get any bigger now */ maxcode = maxmaxcode; else maxcode = MAXCODE(n_bits); } if (clear_flg > 0) { maxcode = MAXCODE(n_bits = INIT_BITS); clear_flg = 0; } size = fread(buf, 1, n_bits, inp); if (size <= 0) { if (feof(inp)) { /* end of file */ return (-1); } else if (ferror(inp)) { ioerror(); } } offset = 0; /* Round size down to integral number of codes */ size = (size << 3) - (n_bits - 1); } r_off = offset; bits = n_bits; /* * Get to the first byte. */ bp += (r_off >> 3); r_off &= 7; /* Get first part (low order bits) */ code = (*bp++ >> r_off); bits -= (8 - r_off); r_off = 8 - r_off; /* now, offset into code word */ /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */ if (bits >= 8) { code |= *bp++ << r_off; r_off += 8; bits -= 8; } /* high order bits. */ code |= (*bp & rmask[bits]) << r_off; offset += n_bits; return (code); } #ifdef DEBUG static void printcodes() { /* * Just print out codes from input file. For debugging. */ code_int code; int col = 0, bits; bits = n_bits = INIT_BITS; maxcode = MAXCODE(n_bits); free_ent = ((block_compress) ? FIRST : 256); while ((code = getcode()) >= 0) { if ((code == CLEAR) && block_compress) { free_ent = FIRST - 1; clear_flg = 1; } else if (free_ent < maxmaxcode) free_ent++; if (bits != n_bits) { (void) fprintf(stderr, "\nChange to %d bits\n", n_bits); bits = n_bits; col = 0; } (void) fprintf(stderr, "%5d%c", code, (col += 6) >= 74 ? (col = 0, '\n') : ' '); } (void) putc('\n', stderr); } #endif /* DEBUG */ #ifdef DEBUG static void dump_tab() /* dump string table */ { int i, first; int ent; int stack_top = STACK_SIZE; int c; if (do_decomp == 0) { /* compressing */ int flag = 1; for (i = 0; i < hsize; i++) { /* build sort pointers */ if ((long)htabof(i) >= 0) { sorttab[codetabof(i)] = i; } } first = block_compress ? FIRST : 256; for (i = first; i < free_ent; i++) { (void) fprintf(stderr, "%5d: \"", i); de_stack[--stack_top] = '\n'; de_stack[--stack_top] = '"'; stack_top = in_stack((htabof(sorttab[i]) >> maxbits) & 0xff, stack_top); for (ent = htabof(sorttab[i]) & ((1 << maxbits) -1); ent > 256; ent = htabof(sorttab[ent]) & ((1<> maxbits, stack_top); } stack_top = in_stack(ent, stack_top); (void) fwrite(&de_stack[stack_top], 1, STACK_SIZE - stack_top, stderr); stack_top = STACK_SIZE; } } else if (!debug) { /* decompressing */ for (i = 0; i < free_ent; i++) { ent = i; c = tab_suffixof(ent); if (isascii(c) && isprint(c)) (void) fprintf(stderr, "%5d: %5d/'%c' \"", ent, tab_prefixof(ent), c); else (void) fprintf(stderr, "%5d: %5d/\\%03o \"", ent, tab_prefixof(ent), c); de_stack[--stack_top] = '\n'; de_stack[--stack_top] = '"'; for (; ent != NULL; ent = (ent >= FIRST ? tab_prefixof(ent) : NULL)) { stack_top = in_stack(tab_suffixof(ent), stack_top); } (void) fwrite(&de_stack[stack_top], 1, STACK_SIZE - stack_top, stderr); stack_top = STACK_SIZE; } } } #endif /* DEBUG */ #ifdef DEBUG static int in_stack(int c, int stack_top) { if ((isascii(c) && isprint(c) && c != '\\') || c == ' ') { de_stack[--stack_top] = c; } else { switch (c) { case '\n': de_stack[--stack_top] = 'n'; break; case '\t': de_stack[--stack_top] = 't'; break; case '\b': de_stack[--stack_top] = 'b'; break; case '\f': de_stack[--stack_top] = 'f'; break; case '\r': de_stack[--stack_top] = 'r'; break; case '\\': de_stack[--stack_top] = '\\'; break; default: de_stack[--stack_top] = '0' + c % 8; de_stack[--stack_top] = '0' + (c / 8) % 8; de_stack[--stack_top] = '0' + c / 64; break; } de_stack[--stack_top] = '\\'; } return (stack_top); } #endif /* DEBUG */ static void ioerror() { longjmp(env, 1); } static void copystat(char *ifname, struct stat *ifstat, char *ofname) { mode_t mode; struct utimbuf timep; acl_t *aclp = NULL; int error; int sattr_exist = 0; int xattr_exist = 0; if (pathconf(ifname, _PC_XATTR_EXISTS) == 1) xattr_exist = 1; if (saflg && sysattr_support(ifname, _PC_SATTR_EXISTS) == 1) sattr_exist = 1; if (fclose(outp)) { perror(ofname); if (!quiet) { (void) fprintf(stderr, gettext(" -- file unchanged")); newline_needed = 1; } perm_stat = 1; } else if (ifstat == NULL) { /* Get stat on input file */ perror(ifname); return; } else if ((ifstat->st_mode & S_IFMT /* 0170000 */) != S_IFREG /* 0100000 */) { if (quiet) { (void) fprintf(stderr, "%s: ", ifname); } (void) fprintf(stderr, gettext( " -- not a regular file: unchanged")); newline_needed = 1; perm_stat = 1; } else if (ifstat->st_nlink > 1) { if (quiet) { (void) fprintf(stderr, "%s: ", ifname); } (void) fprintf(stderr, gettext( " -- has %d other links: unchanged"), (uint_t)ifstat->st_nlink - 1); newline_needed = 1; perm_stat = 1; } else if (didnt_shrink && !force) { /* No compression: remove file.Z */ if (!quiet) { (void) fprintf(stderr, gettext( " -- file unchanged")); newline_needed = 1; } } else if ((xattr_exist || sattr_exist) && (mv_xattrs(progname, ifname, ofname, sattr_exist, 0) != 0)) { (void) fprintf(stderr, gettext( "%s: -- cannot preserve extended attributes or " "system attributes, file unchanged"), ifname); newline_needed = 1; /* Move attributes back ... */ xattr_exist = 0; sattr_exist = 0; if (pathconf(ofname, _PC_XATTR_EXISTS) == 1) xattr_exist = 1; if (saflg && sysattr_support(ofname, _PC_SATTR_EXISTS) == 1) sattr_exist = 1; if (sattr_exist || xattr_exist) (void) mv_xattrs(progname, ofname, ifname, sattr_exist, 1); perm_stat = 1; } else { /* ***** Successful Compression ***** */ mode = ifstat->st_mode & 07777; if (chmod(ofname, mode)) { /* Copy modes */ if (errno == EPERM) { (void) fprintf(stderr, gettext("failed to chmod %s" "- permisssion denied\n"), ofname); } perror(ofname); } error = acl_get(ifname, ACL_NO_TRIVIAL, &aclp); if (error != 0) { (void) fprintf(stderr, gettext( "%s: failed to retrieve acl : %s\n"), ifname, acl_strerror(error)); perm_stat = 1; } if (aclp && (acl_set(ofname, aclp) < 0)) { (void) fprintf(stderr, gettext("%s: failed to set acl " "entries\n"), ofname); perm_stat = 1; } if (aclp) { acl_free(aclp); aclp = NULL; } /* Copy ownership */ (void) chown(ofname, ifstat->st_uid, ifstat->st_gid); timep.actime = ifstat->st_atime; timep.modtime = ifstat->st_mtime; /* Update last accessed and modified times */ (void) utime(ofname, &timep); if (unlink(ifname)) { /* Remove input file */ if (errno == EPERM) { (void) fprintf(stderr, gettext("failed to remove %s" "- permisssion denied\n"), ifname); } perror(ifname); } if (!quiet) { (void) fprintf(stderr, gettext( " -- replaced with %s"), ofname); newline_needed = 1; } return; /* Successful return */ } /* Unsuccessful return -- one of the tests failed */ if (ofname[0] != '\0') { if (unlink(ofname)) { if (errno == EPERM) { (void) fprintf(stderr, gettext("failed to remove %s" "- permisssion denied\n"), ifname); } perror(ofname); } ofname[0] = '\0'; } } static void onintr() { if (!precious && !use_stdout && ofname[0] != '\0') (void) unlink(ofname); exit(1); } static void oops() /* wild pointer -- assume bad input */ { if (do_decomp) { (void) fprintf(stderr, gettext("uncompress: corrupt input\n")); } if (!use_stdout && ofname[0] != '\0') { (void) unlink(ofname); } exit(1); } static void cl_block(count_long in_count) /* table clear for block compress */ { count_long rat; checkpoint = (count_long)in_count + (count_long)CHECK_GAP; #ifdef DEBUG if (debug) { (void) fprintf(stderr, "count: %lld, ratio: ", (count_long)in_count); prratio(stderr, (count_long)in_count, (count_long)bytes_out); (void) fprintf(stderr, "\n"); } #endif /* DEBUG */ /* shift will overflow */ if ((count_long)in_count > 0x007fffffffffffffLL) { rat = (count_long)bytes_out >> 8; if (rat == 0) { /* Don't divide by zero */ rat = 0x7fffffffffffffffLL; } else { rat = (count_long)in_count / (count_long)rat; } } else { /* 8 fractional bits */ rat = ((count_long)in_count << 8) /(count_long)bytes_out; } if (rat > ratio) { ratio = rat; } else { ratio = 0; #ifdef DEBUG if (verbose) dump_tab(); /* dump string table */ #endif cl_hash((count_int) hsize); free_ent = FIRST; clear_flg = 1; output((code_int) CLEAR); #ifdef DEBUG if (debug) (void) fprintf(stderr, "clear\n"); #endif /* DEBUG */ } } static void cl_hash(count_int hsize) /* reset code table */ { count_int *htab_p = htab+hsize; long i; long m1 = -1; i = hsize - 16; do { /* might use Sys V memset(3) here */ *(htab_p-16) = m1; *(htab_p-15) = m1; *(htab_p-14) = m1; *(htab_p-13) = m1; *(htab_p-12) = m1; *(htab_p-11) = m1; *(htab_p-10) = m1; *(htab_p-9) = m1; *(htab_p-8) = m1; *(htab_p-7) = m1; *(htab_p-6) = m1; *(htab_p-5) = m1; *(htab_p-4) = m1; *(htab_p-3) = m1; *(htab_p-2) = m1; *(htab_p-1) = m1; htab_p -= 16; } while ((i -= 16) >= 0); for (i += 16; i > 0; i--) *--htab_p = m1; } static void prratio(FILE *stream, count_long num, count_long den) { int q; /* store percentage */ q = (int)(10000LL * (count_long)num / (count_long)den); if (q < 0) { (void) putc('-', stream); q = -q; } (void) fprintf(stream, "%d%s%02d%%", q / 100, localeconv()->decimal_point, q % 100); } static void version() { (void) fprintf(stderr, "%s, Berkeley 5.9 5/11/86\n", rcs_ident); (void) fprintf(stderr, "Options: "); #ifdef DEBUG (void) fprintf(stderr, "DEBUG, "); #endif (void) fprintf(stderr, "BITS = %d\n", BITS); } static void Usage() { #ifdef DEBUG (void) fprintf(stderr, "Usage: compress [-dDVfc/] [-b maxbits] [file ...]\n"); #else if (strcmp(progname, "compress") == 0) { (void) fprintf(stderr, gettext( "Usage: compress [-fv/] [-b maxbits] [file ...]\n"\ " compress c [-fv] [-b maxbits] [file]\n")); } else if (strcmp(progname, "uncompress") == 0) (void) fprintf(stderr, gettext( "Usage: uncompress [-fv] [-c || -/] [file ...]\n")); else if (strcmp(progname, "zcat") == 0) (void) fprintf(stderr, gettext("Usage: zcat [file ...]\n")); #endif /* DEBUG */ } static char * local_basename(char *path) { char *p; char *ret = (char *)path; while ((p = (char *)strpbrk(ret, "/")) != NULL) ret = p + 1; return (ret); } static int addDotZ(char *fn, size_t fnsize) { char *fn_dup; char *dir; long int max_name; long int max_path; fn_dup = strdup(fn); dir = dirname(fn_dup); max_name = pathconf(dir, _PC_NAME_MAX); max_path = pathconf(dir, _PC_PATH_MAX); free(fn_dup); /* Check for component length too long */ if ((strlen(local_basename(fn)) + 2) > (size_t)max_name) { (void) fprintf(stderr, gettext("%s: filename too long to tack on .Z:" " %s\n"), progname, fn); return (-1); } /* Check for path length too long */ if ((strlen(fn) + 2) > (size_t)max_path - 1) { (void) fprintf(stderr, gettext("%s: Pathname too long to tack on .Z:" " %s\n"), progname, fn); return (-1); } if (strlcat(fn, ".Z", fnsize) >= fnsize) { (void) fprintf(stderr, gettext("%s: Buffer overflow adding .Z to %s\n"), progname, fn); return (-1); } return (0); } #!/bin/sh # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" echo_file usr/src/common/util/getresponse.c echo_file usr/src/common/util/getresponse.h