PageRenderTime 27ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/usr/src/cmd/unpack/unpack.c

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