1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 22 /* All Rights Reserved */ 23 24 25 /* 26 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 27 * Use is subject to license terms. 28 */ 29 30 /* 31 * Huffman decompressor 32 * Usage: pcat filename... 33 * or unpack filename... 34 */ 35 36 #include <setjmp.h> 37 #include <signal.h> 38 #include <locale.h> 39 #include <utime.h> 40 #include <sys/param.h> 41 #include <sys/acl.h> 42 #include <aclutils.h> 43 #include <libcmdutils.h> 44 45 static struct utimbuf u_times; 46 static jmp_buf env; 47 static struct stat status; 48 static char *argv0, *argvk; 49 50 /* rmflg, when set it's ok to rm arvk file on caught signals */ 51 static int rmflg = 0; 52 53 #define SUF0 '.' 54 #define SUF1 'z' 55 #define US 037 56 #define RS 036 57 58 /* variables associated with i/o */ 59 static char filename[MAXPATHLEN]; 60 61 static short infile; 62 static short outfile; 63 static short inleft; 64 static short is_eof = 0; 65 static char *inp; 66 static char *outp; 67 static char inbuff[BUFSIZ]; 68 static char outbuff[BUFSIZ]; 69 70 /* the dictionary */ 71 static long origsize; 72 static short maxlev; 73 static short intnodes[25]; 74 static char *tree[25]; 75 static char characters[256]; 76 static char *eof; 77 78 static void putch(char c); 79 static int expand(); 80 static int decode(); 81 static int getwdsize(); 82 static int getch(); 83 static int getdict(); 84 85 /* Extended system attribute support */ 86 87 static int saflg = 0; 88 89 90 /* read in the dictionary portion and build decoding structures */ 91 /* return 1 if successful, 0 otherwise */ 92 int 93 getdict() 94 { 95 register int c, i, nchildren; 96 97 /* 98 * check two-byte header 99 * get size of original file, 100 * get number of levels in maxlev, 101 * get number of leaves on level i in intnodes[i], 102 * set tree[i] to point to leaves for level i 103 */ 104 eof = &characters[0]; 105 106 inbuff[6] = 25; 107 inleft = read(infile, &inbuff[0], BUFSIZ); 108 if (inleft < 0) { 109 (void) fprintf(stderr, gettext( 110 "%s: %s: read error: "), argv0, filename); 111 perror(""); 112 return (0); 113 } 114 if (inbuff[0] != US) 115 goto goof; 116 117 if (inbuff[1] == US) { /* oldstyle packing */ 118 if (setjmp(env)) 119 return (0); 120 return (expand()); 121 } 122 if (inbuff[1] != RS) 123 goto goof; 124 125 inp = &inbuff[2]; 126 origsize = 0; 127 for (i = 0; i < 4; i++) 128 origsize = origsize*256 + ((*inp++) & 0377); 129 maxlev = *inp++ & 0377; 130 if (maxlev > 24) { 131 goof: (void) fprintf(stderr, gettext( 132 "%s: %s: not in packed format\n"), argv0, filename); 133 return (0); 134 } 135 for (i = 1; i <= maxlev; i++) 136 intnodes[i] = *inp++ & 0377; 137 for (i = 1; i <= maxlev; i++) { 138 tree[i] = eof; 139 for (c = intnodes[i]; c > 0; c--) { 140 if (eof >= &characters[255]) 141 goto goof; 142 *eof++ = *inp++; 143 } 144 } 145 *eof++ = *inp++; 146 intnodes[maxlev] += 2; 147 inleft -= inp - &inbuff[0]; 148 if (inleft < 0) 149 goto goof; 150 151 /* 152 * convert intnodes[i] to be number of 153 * internal nodes possessed by level i 154 */ 155 156 nchildren = 0; 157 for (i = maxlev; i >= 1; i--) { 158 c = intnodes[i]; 159 intnodes[i] = nchildren /= 2; 160 nchildren += c; 161 } 162 return (decode()); 163 } 164 165 /* unpack the file */ 166 /* return 1 if successful, 0 otherwise */ 167 int 168 decode() 169 { 170 register int bitsleft, c, i; 171 int j, lev, cont = 1; 172 char *p; 173 174 outp = &outbuff[0]; 175 lev = 1; 176 i = 0; 177 while (cont) { 178 if (inleft <= 0) { 179 inleft = read(infile, inp = &inbuff[0], BUFSIZ); 180 if (inleft < 0) { 181 (void) fprintf(stderr, gettext( 182 "%s: %s: read error: "), 183 argv0, filename); 184 perror(""); 185 return (0); 186 } 187 } 188 if (--inleft < 0) { 189 uggh: (void) fprintf(stderr, gettext( 190 "%s: %s: unpacking error\n"), 191 argv0, filename); 192 return (0); 193 } 194 c = *inp++; 195 bitsleft = 8; 196 while (--bitsleft >= 0) { 197 i *= 2; 198 if (c & 0200) 199 i++; 200 c <<= 1; 201 if ((j = i - intnodes[lev]) >= 0) { 202 p = &tree[lev][j]; 203 if (p == eof) { 204 c = outp - &outbuff[0]; 205 if (write(outfile, &outbuff[0], c) 206 != c) { 207 wrerr: (void) fprintf(stderr, 208 gettext( 209 "%s: %s: write error: "), 210 argv0, argvk); 211 perror(""); 212 return (0); 213 } 214 origsize -= c; 215 if (origsize != 0) 216 goto uggh; 217 return (1); 218 } 219 *outp++ = *p; 220 if (outp == &outbuff[BUFSIZ]) { 221 if (write(outfile, outp = &outbuff[0], 222 BUFSIZ) != BUFSIZ) 223 goto wrerr; 224 origsize -= BUFSIZ; 225 } 226 lev = 1; 227 i = 0; 228 } else 229 lev++; 230 } 231 } 232 return (1); /* we won't get here , but lint is pleased */ 233 } 234 235 int 236 main(int argc, char *argv[]) 237 { 238 extern int optind; 239 int i, k; 240 int error; 241 int sep, errflg = 0, pcat = 0; 242 register char *p1, *cp; 243 int fcount = 0; /* failure count */ 244 int max_name; 245 void onsig(int); 246 acl_t *aclp = NULL; 247 int c; 248 char *progname; 249 int sattr_exist = 0; 250 int xattr_exist = 0; 251 252 if (signal(SIGHUP, SIG_IGN) != SIG_IGN) 253 #ifdef __STDC__ 254 (void) signal((int)SIGHUP, onsig); 255 #else 256 (void) signal((int)SIGHUP, onsig); 257 #endif 258 if (signal(SIGINT, SIG_IGN) != SIG_IGN) 259 #ifdef __STDC__ 260 (void) signal((int)SIGINT, onsig); 261 #else 262 (void) signal((int)SIGINT, onsig); 263 #endif 264 if (signal(SIGTERM, SIG_IGN) != SIG_IGN) 265 #ifdef __STDC__ 266 (void) signal((int)SIGTERM, onsig); 267 #else 268 (void) signal(SIGTERM, onsig); 269 #endif 270 271 (void) setlocale(LC_ALL, ""); 272 #if !defined(TEXT_DOMAIN) 273 #define TEXT_DOMAIN "SYS_TEST" 274 #endif 275 (void) textdomain(TEXT_DOMAIN); 276 277 if (progname = strrchr(argv[0], '/')) 278 ++progname; 279 else 280 progname = argv[0]; 281 282 p1 = *argv; 283 while (*p1++) { }; /* Point p1 to end of argv[0] string */ 284 while (--p1 >= *argv) 285 if (*p1 == '/')break; 286 *argv = p1 + 1; 287 argv0 = argv[0]; 288 if (**argv == 'p')pcat++; /* User entered pcat (or /xx/xx/pcat) */ 289 290 while ((c = getopt(argc, argv, "/")) != EOF) { 291 if (c == '/') { 292 if (pcat) 293 ++errflg; 294 else 295 saflg++; 296 } else 297 ++errflg; 298 } 299 /* 300 * Check for invalid option. Also check for missing 301 * file operand, ie: "unpack" or "pcat". 302 */ 303 argc -= optind; 304 argv = &argv[optind]; 305 if (errflg || argc < 1) { 306 if (!pcat) 307 (void) fprintf(stderr, 308 gettext("usage: %s [-/] file...\n"), argv0); 309 else 310 (void) fprintf(stderr, gettext("usage: %s file...\n"), 311 argv0); 312 313 if (argc < 1) { 314 /* 315 * return 1 for usage error when no file was specified 316 */ 317 return (1); 318 } 319 } 320 /* loop through the file names */ 321 for (k = 0; k < argc; k++) { 322 fcount++; /* expect the worst */ 323 if (errflg) { 324 /* 325 * invalid option; just count the number of files not 326 * unpacked 327 */ 328 continue; 329 } 330 /* remove any .z suffix the user may have added */ 331 for (cp = argv[k]; *cp != '\0'; ++cp) 332 ; 333 if (cp[-1] == SUF1 && cp[-2] == SUF0) { 334 *cp-- = '\0'; *cp-- = '\0'; *cp = '\0'; 335 } 336 sep = -1; 337 cp = filename; 338 argvk = argv[k]; 339 /* copy argv[k] to filename and count chars in base name */ 340 for (i = 0; i < (MAXPATHLEN-3) && (*cp = argvk[i]); i++) 341 if (*cp++ == '/') 342 sep = i; 343 /* add .z suffix to filename */ 344 *cp++ = SUF0; 345 *cp++ = SUF1; 346 *cp = '\0'; 347 if ((infile = open(filename, O_RDONLY)) == -1) { 348 (void) fprintf(stderr, gettext( 349 "%s: %s: cannot open: "), 350 argv0, filename); 351 perror(""); 352 goto done; 353 } 354 if (pcat) 355 outfile = 1; /* standard output */ 356 else { 357 358 error = facl_get(infile, ACL_NO_TRIVIAL, &aclp); 359 if (error != 0) { 360 (void) printf(gettext( 361 "%s: %s: cannot retrieve ACL : %s\n"), 362 argv0, filename, acl_strerror(error)); 363 } 364 365 max_name = pathconf(filename, _PC_NAME_MAX); 366 if (max_name == -1) { 367 /* no limit on length of filename */ 368 max_name = _POSIX_NAME_MAX; 369 } 370 if (i >= (MAXPATHLEN-1) || (i - sep - 1) > max_name) { 371 (void) fprintf(stderr, gettext( 372 "%s: %s: file name too long\n"), 373 argv0, argvk); 374 goto done; 375 } 376 if (stat(argvk, &status) != -1) { 377 (void) fprintf(stderr, gettext( 378 "%s: %s: already exists\n"), 379 argv0, argvk); 380 goto done; 381 } 382 (void) fstat(infile, &status); 383 if (status.st_nlink != 1) { 384 (void) printf(gettext( 385 "%s: %s: Warning: file has links\n"), 386 argv0, filename); 387 } 388 if ((outfile = creat(argvk, status.st_mode)) == -1) { 389 (void) fprintf(stderr, gettext( 390 "%s: %s: cannot create: "), 391 argv0, argvk); 392 perror(""); 393 goto done; 394 } 395 rmflg = 1; 396 } 397 398 if (getdict()) { /* unpack */ 399 if (pathconf(filename, _PC_XATTR_EXISTS) == 1) 400 xattr_exist = 1; 401 if (saflg && sysattr_support(filename, 402 _PC_SATTR_EXISTS) == 1) 403 sattr_exist = 1; 404 if (pcat || xattr_exist || sattr_exist) { 405 if (mv_xattrs(progname, filename, argv[k], 406 sattr_exist, 0) 407 != 0) { 408 /* Move attributes back ... */ 409 xattr_exist = 0; 410 sattr_exist = 0; 411 if (pathconf(argvk, _PC_XATTR_EXISTS) 412 == 1) 413 xattr_exist = 1; 414 if (saflg && sysattr_support(argvk, 415 _PC_SATTR_EXISTS) == 1) 416 sattr_exist = 1; 417 if (!pcat && (xattr_exist || 418 sattr_exist)) { 419 (void) mv_xattrs(progname, 420 argv[k], filename, 421 sattr_exist, 1); 422 (void) unlink(argvk); 423 goto done; 424 } 425 } else { 426 if (!pcat) 427 (void) unlink(filename); 428 } 429 } else if (!pcat) 430 (void) unlink(filename); 431 432 if (!pcat) { 433 (void) printf(gettext("%s: %s: unpacked\n"), 434 argv0, argvk); 435 /* 436 * preserve acc & mod dates 437 */ 438 u_times.actime = status.st_atime; 439 u_times.modtime = status.st_mtime; 440 if (utime(argvk, &u_times) != 0) { 441 errflg++; 442 (void) fprintf(stderr, gettext( 443 "%s: cannot change times on %s: "), 444 argv0, argvk); 445 perror(""); 446 } 447 if (chmod(argvk, status.st_mode) != 0) { 448 errflg++; 449 (void) fprintf(stderr, gettext( 450 "%s: cannot change mode to %o on %s: "), 451 argv0, (uint_t)status.st_mode, 452 argvk); 453 perror(""); 454 } 455 (void) chown(argvk, 456 status.st_uid, status.st_gid); 457 if (aclp && (facl_set(outfile, aclp) < 0)) { 458 (void) printf(gettext("%s: cannot " 459 "set ACL on %s: "), argv0, argvk); 460 perror(""); 461 } 462 463 rmflg = 0; 464 } 465 if (!errflg) 466 fcount--; /* success after all */ 467 } 468 done: (void) close(infile); 469 if (!pcat) 470 (void) close(outfile); 471 472 if (aclp) { 473 acl_free(aclp); 474 aclp = NULL; 475 } 476 } 477 return (fcount); 478 } 479 480 /* 481 * This code is for unpacking files that 482 * were packed using the previous algorithm. 483 */ 484 485 static int Tree[1024]; 486 487 /* return 1 if successful, 0 otherwise */ 488 489 int 490 expand() 491 { 492 int tp, bit; 493 short word; 494 int keysize, i, *t; 495 496 outp = outbuff; 497 inp = &inbuff[2]; 498 inleft -= 2; 499 500 origsize = ((long)(unsigned)getwdsize())*256*256; 501 origsize += (unsigned)getwdsize(); 502 if (origsize == 0 || is_eof) { 503 (void) fprintf(stderr, gettext( 504 "%s: %s: not in packed format\n"), 505 argv0, filename); 506 return (0); 507 } 508 t = Tree; 509 for (keysize = getwdsize(); keysize--; ) { 510 if ((i = getch()) == 0377) 511 *t++ = getwdsize(); 512 else { 513 /* 514 * reached EOF unexpectedly 515 */ 516 if (is_eof) { 517 (void) fprintf(stderr, gettext( 518 "%s: %s: not in packed format\n"), 519 argv0, filename); 520 return (0); 521 } 522 *t++ = i & 0377; 523 } 524 } 525 /* 526 * reached EOF unexpectedly 527 */ 528 if (is_eof) { 529 (void) fprintf(stderr, gettext( 530 "%s: %s: not in packed format\n"), 531 argv0, filename); 532 return (0); 533 } 534 535 536 bit = tp = 0; 537 for (;;) { 538 if (bit <= 0) { 539 word = getwdsize(); 540 /* 541 * reached EOF unexpectedly 542 */ 543 if (word == 0 && is_eof && origsize > 0) { 544 (void) fprintf(stderr, gettext( 545 "%s: %s: not in packed format\n"), 546 argv0, filename); 547 return (0); 548 } 549 bit = 16; 550 } 551 tp += Tree[tp + (word < 0)]; 552 word <<= 1; 553 bit--; 554 if (Tree[tp] == 0) { 555 putch(Tree[tp+1]); 556 tp = 0; 557 if ((origsize -= 1) == 0) { 558 (void) write(outfile, outbuff, outp - outbuff); 559 return (1); 560 } 561 } 562 } 563 } 564 565 int 566 getch() 567 { 568 if (inleft <= 0) { 569 inleft = read(infile, inp = inbuff, BUFSIZ); 570 if (inleft < 0) { 571 (void) fprintf(stderr, gettext( 572 "%s: %s: read error: "), 573 argv0, filename); 574 perror(""); 575 longjmp(env, 1); 576 } else { /* reached EOF, report it */ 577 if (inleft == 0) { 578 is_eof = 1; 579 return (EOF); 580 } 581 } 582 } 583 inleft--; 584 return (*inp++ & 0377); 585 } 586 587 int 588 getwdsize() 589 { 590 char c; 591 int d; 592 593 c = getch(); 594 d = getch(); 595 if (is_eof) 596 return (0); 597 d <<= 8; 598 d |= c & 0377; 599 return (d); 600 } 601 602 void 603 onsig(int sig) 604 { 605 /* could be running as unpack or pcat */ 606 /* but rmflg is set only when running */ 607 /* as unpack and only when file is */ 608 /* created by unpack and not yet done */ 609 if (rmflg == 1) 610 (void) unlink(argvk); 611 /* To quiet lint noise */ 612 if (sig == SIGTERM || sig == SIGHUP || sig == SIGINT) 613 exit(1); 614 } 615 616 void 617 putch(char c) 618 { 619 int n; 620 621 *outp++ = c; 622 if (outp == &outbuff[BUFSIZ]) { 623 n = write(outfile, outp = outbuff, BUFSIZ); 624 if (n < BUFSIZ) { 625 (void) fprintf(stderr, gettext( 626 "%s: %s: write error: "), 627 argv0, argvk); 628 perror(""); 629 longjmp(env, 2); 630 } 631 } 632 } 633