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.
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.
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]
21 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
22 /* All Rights Reserved */
26 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
27 * Use is subject to license terms.
30 #pragma ident "%Z%%M% %I% %E% SMI"
33 * Huffman decompressor
34 * Usage: pcat filename...
35 * or unpack filename...
42 #include <sys/param.h>
45 #include <libcmdutils.h>
47 static struct utimbuf u_times
;
49 static struct stat status
;
50 static char *argv0
, *argvk
;
52 /* rmflg, when set it's ok to rm arvk file on caught signals */
60 /* variables associated with i/o */
61 static char filename
[MAXPATHLEN
];
66 static short is_eof
= 0;
69 static char inbuff
[BUFSIZ
];
70 static char outbuff
[BUFSIZ
];
75 static short intnodes
[25];
76 static char *tree
[25];
77 static char characters
[256];
80 static void putch(char c
);
83 static int getwdsize();
87 /* Extended system attribute support */
92 /* read in the dictionary portion and build decoding structures */
93 /* return 1 if successful, 0 otherwise */
97 register int c
, i
, nchildren
;
100 * check two-byte header
101 * get size of original file,
102 * get number of levels in maxlev,
103 * get number of leaves on level i in intnodes[i],
104 * set tree[i] to point to leaves for level i
106 eof
= &characters
[0];
109 inleft
= read(infile
, &inbuff
[0], BUFSIZ
);
111 (void) fprintf(stderr
, gettext(
112 "%s: %s: read error: "), argv0
, filename
);
119 if (inbuff
[1] == US
) { /* oldstyle packing */
129 for (i
= 0; i
< 4; i
++)
130 origsize
= origsize
*256 + ((*inp
++) & 0377);
131 maxlev
= *inp
++ & 0377;
133 goof
: (void) fprintf(stderr
, gettext(
134 "%s: %s: not in packed format\n"), argv0
, filename
);
137 for (i
= 1; i
<= maxlev
; i
++)
138 intnodes
[i
] = *inp
++ & 0377;
139 for (i
= 1; i
<= maxlev
; i
++) {
141 for (c
= intnodes
[i
]; c
> 0; c
--) {
142 if (eof
>= &characters
[255])
148 intnodes
[maxlev
] += 2;
149 inleft
-= inp
- &inbuff
[0];
154 * convert intnodes[i] to be number of
155 * internal nodes possessed by level i
159 for (i
= maxlev
; i
>= 1; i
--) {
161 intnodes
[i
] = nchildren
/= 2;
167 /* unpack the file */
168 /* return 1 if successful, 0 otherwise */
172 register int bitsleft
, c
, i
;
173 int j
, lev
, cont
= 1;
181 inleft
= read(infile
, inp
= &inbuff
[0], BUFSIZ
);
183 (void) fprintf(stderr
, gettext(
184 "%s: %s: read error: "),
191 uggh
: (void) fprintf(stderr
, gettext(
192 "%s: %s: unpacking error\n"),
198 while (--bitsleft
>= 0) {
203 if ((j
= i
- intnodes
[lev
]) >= 0) {
206 c
= outp
- &outbuff
[0];
207 if (write(outfile
, &outbuff
[0], c
)
209 wrerr
: (void) fprintf(stderr
,
211 "%s: %s: write error: "),
222 if (outp
== &outbuff
[BUFSIZ
]) {
223 if (write(outfile
, outp
= &outbuff
[0],
234 return (1); /* we won't get here , but lint is pleased */
238 main(int argc
, char *argv
[])
243 int sep
, errflg
= 0, pcat
= 0;
244 register char *p1
, *cp
;
245 int fcount
= 0; /* failure count */
254 if (signal(SIGHUP
, SIG_IGN
) != SIG_IGN
)
256 (void) signal((int)SIGHUP
, onsig
);
258 (void) signal((int)SIGHUP
, onsig
);
260 if (signal(SIGINT
, SIG_IGN
) != SIG_IGN
)
262 (void) signal((int)SIGINT
, onsig
);
264 (void) signal((int)SIGINT
, onsig
);
266 if (signal(SIGTERM
, SIG_IGN
) != SIG_IGN
)
268 (void) signal((int)SIGTERM
, onsig
);
270 (void) signal(SIGTERM
, onsig
);
273 (void) setlocale(LC_ALL
, "");
274 #if !defined(TEXT_DOMAIN)
275 #define TEXT_DOMAIN "SYS_TEST"
277 (void) textdomain(TEXT_DOMAIN
);
279 if (progname
= strrchr(argv
[0], '/'))
285 while (*p1
++) { }; /* Point p1 to end of argv[0] string */
286 while (--p1
>= *argv
)
287 if (*p1
== '/')break;
290 if (**argv
== 'p')pcat
++; /* User entered pcat (or /xx/xx/pcat) */
292 while ((c
= getopt(argc
, argv
, "/")) != EOF
) {
302 * Check for invalid option. Also check for missing
303 * file operand, ie: "unpack" or "pcat".
306 argv
= &argv
[optind
];
307 if (errflg
|| argc
< 1) {
309 (void) fprintf(stderr
,
310 gettext("usage: %s [-/] file...\n"), argv0
);
312 (void) fprintf(stderr
, gettext("usage: %s file...\n"),
317 * return 1 for usage error when no file was specified
322 /* loop through the file names */
323 for (k
= 0; k
< argc
; k
++) {
324 fcount
++; /* expect the worst */
327 * invalid option; just count the number of files not
332 /* remove any .z suffix the user may have added */
333 for (cp
= argv
[k
]; *cp
!= '\0'; ++cp
)
335 if (cp
[-1] == SUF1
&& cp
[-2] == SUF0
) {
336 *cp
-- = '\0'; *cp
-- = '\0'; *cp
= '\0';
341 /* copy argv[k] to filename and count chars in base name */
342 for (i
= 0; i
< (MAXPATHLEN
-3) && (*cp
= argvk
[i
]); i
++)
345 /* add .z suffix to filename */
349 if ((infile
= open(filename
, O_RDONLY
)) == -1) {
350 (void) fprintf(stderr
, gettext(
351 "%s: %s: cannot open: "),
357 outfile
= 1; /* standard output */
360 error
= facl_get(infile
, ACL_NO_TRIVIAL
, &aclp
);
362 (void) printf(gettext(
363 "%s: %s: cannot retrieve ACL : %s\n"),
364 argv0
, filename
, acl_strerror(error
));
367 max_name
= pathconf(filename
, _PC_NAME_MAX
);
368 if (max_name
== -1) {
369 /* no limit on length of filename */
370 max_name
= _POSIX_NAME_MAX
;
372 if (i
>= (MAXPATHLEN
-1) || (i
- sep
- 1) > max_name
) {
373 (void) fprintf(stderr
, gettext(
374 "%s: %s: file name too long\n"),
378 if (stat(argvk
, &status
) != -1) {
379 (void) fprintf(stderr
, gettext(
380 "%s: %s: already exists\n"),
384 (void) fstat(infile
, &status
);
385 if (status
.st_nlink
!= 1) {
386 (void) printf(gettext(
387 "%s: %s: Warning: file has links\n"),
390 if ((outfile
= creat(argvk
, status
.st_mode
)) == -1) {
391 (void) fprintf(stderr
, gettext(
392 "%s: %s: cannot create: "),
400 if (getdict()) { /* unpack */
401 if (pathconf(filename
, _PC_XATTR_EXISTS
) == 1)
403 if (saflg
&& sysattr_support(filename
,
404 _PC_SATTR_EXISTS
) == 1)
406 if (pcat
|| xattr_exist
|| sattr_exist
) {
407 if (mv_xattrs(progname
, filename
, argv
[k
],
410 /* Move attributes back ... */
413 if (pathconf(argvk
, _PC_XATTR_EXISTS
)
416 if (saflg
&& sysattr_support(argvk
,
417 _PC_SATTR_EXISTS
) == 1)
419 if (!pcat
&& (xattr_exist
||
421 (void) mv_xattrs(progname
,
424 (void) unlink(argvk
);
429 (void) unlink(filename
);
432 (void) unlink(filename
);
435 (void) printf(gettext("%s: %s: unpacked\n"),
438 * preserve acc & mod dates
440 u_times
.actime
= status
.st_atime
;
441 u_times
.modtime
= status
.st_mtime
;
442 if (utime(argvk
, &u_times
) != 0) {
444 (void) fprintf(stderr
, gettext(
445 "%s: cannot change times on %s: "),
449 if (chmod(argvk
, status
.st_mode
) != 0) {
451 (void) fprintf(stderr
, gettext(
452 "%s: cannot change mode to %o on %s: "),
453 argv0
, (uint_t
)status
.st_mode
,
458 status
.st_uid
, status
.st_gid
);
459 if (aclp
&& (facl_set(outfile
, aclp
) < 0)) {
460 (void) printf(gettext("%s: cannot "
461 "set ACL on %s: "), argv0
, argvk
);
468 fcount
--; /* success after all */
470 done
: (void) close(infile
);
472 (void) close(outfile
);
483 * This code is for unpacking files that
484 * were packed using the previous algorithm.
487 static int Tree
[1024];
489 /* return 1 if successful, 0 otherwise */
502 origsize
= ((long)(unsigned)getwdsize())*256*256;
503 origsize
+= (unsigned)getwdsize();
504 if (origsize
== 0 || is_eof
) {
505 (void) fprintf(stderr
, gettext(
506 "%s: %s: not in packed format\n"),
511 for (keysize
= getwdsize(); keysize
--; ) {
512 if ((i
= getch()) == 0377)
516 * reached EOF unexpectedly
519 (void) fprintf(stderr
, gettext(
520 "%s: %s: not in packed format\n"),
528 * reached EOF unexpectedly
531 (void) fprintf(stderr
, gettext(
532 "%s: %s: not in packed format\n"),
543 * reached EOF unexpectedly
545 if (word
== 0 && is_eof
&& origsize
> 0) {
546 (void) fprintf(stderr
, gettext(
547 "%s: %s: not in packed format\n"),
553 tp
+= Tree
[tp
+ (word
< 0)];
559 if ((origsize
-= 1) == 0) {
560 (void) write(outfile
, outbuff
, outp
- outbuff
);
571 inleft
= read(infile
, inp
= inbuff
, BUFSIZ
);
573 (void) fprintf(stderr
, gettext(
574 "%s: %s: read error: "),
578 } else { /* reached EOF, report it */
586 return (*inp
++ & 0377);
607 /* could be running as unpack or pcat */
608 /* but rmflg is set only when running */
609 /* as unpack and only when file is */
610 /* created by unpack and not yet done */
612 (void) unlink(argvk
);
613 /* To quiet lint noise */
614 if (sig
== SIGTERM
|| sig
== SIGHUP
|| sig
== SIGINT
)
624 if (outp
== &outbuff
[BUFSIZ
]) {
625 n
= write(outfile
, outp
= outbuff
, BUFSIZ
);
627 (void) fprintf(stderr
, gettext(
628 "%s: %s: write error: "),