#include <setjmp.h>
#include <signal.h>
#include <locale.h>
#include <utime.h>
#include <sys/param.h>
#include <sys/acl.h>
#include <aclutils.h>
#include <libcmdutils.h>
static struct utimbuf u_times;
static jmp_buf env;
static struct stat status;
static char *argv0, *argvk;
static int rmflg = 0;
#define SUF0 '.'
#define SUF1 'z'
#define US 037
#define RS 036
static char filename[MAXPATHLEN];
static short infile;
static short outfile;
static short inleft;
static short is_eof = 0;
static char *inp;
static char *outp;
static char inbuff[BUFSIZ];
static char outbuff[BUFSIZ];
static long origsize;
static short maxlev;
static short intnodes[25];
static char *tree[25];
static char characters[256];
static char *eof;
static void putch(char c);
static int expand();
static int decode();
static int getwdsize();
static int getch();
static int getdict();
static int saflg = 0;
int
getdict()
{
register int c, i, nchildren;
eof = &characters[0];
inbuff[6] = 25;
inleft = read(infile, &inbuff[0], BUFSIZ);
if (inleft < 0) {
(void) fprintf(stderr, gettext(
"%s: %s: read error: "), argv0, filename);
perror("");
return (0);
}
if (inbuff[0] != US)
goto goof;
if (inbuff[1] == US) {
if (setjmp(env))
return (0);
return (expand());
}
if (inbuff[1] != RS)
goto goof;
inp = &inbuff[2];
origsize = 0;
for (i = 0; i < 4; i++)
origsize = origsize*256 + ((*inp++) & 0377);
maxlev = *inp++ & 0377;
if (maxlev > 24) {
goof: (void) fprintf(stderr, gettext(
"%s: %s: not in packed format\n"), argv0, filename);
return (0);
}
for (i = 1; i <= maxlev; i++)
intnodes[i] = *inp++ & 0377;
for (i = 1; i <= maxlev; i++) {
tree[i] = eof;
for (c = intnodes[i]; c > 0; c--) {
if (eof >= &characters[255])
goto goof;
*eof++ = *inp++;
}
}
*eof++ = *inp++;
intnodes[maxlev] += 2;
inleft -= inp - &inbuff[0];
if (inleft < 0)
goto goof;
nchildren = 0;
for (i = maxlev; i >= 1; i--) {
c = intnodes[i];
intnodes[i] = nchildren /= 2;
nchildren += c;
}
return (decode());
}
int
decode()
{
register int bitsleft, c, i;
int j, lev, cont = 1;
char *p;
outp = &outbuff[0];
lev = 1;
i = 0;
while (cont) {
if (inleft <= 0) {
inleft = read(infile, inp = &inbuff[0], BUFSIZ);
if (inleft < 0) {
(void) fprintf(stderr, gettext(
"%s: %s: read error: "),
argv0, filename);
perror("");
return (0);
}
}
if (--inleft < 0) {
uggh: (void) fprintf(stderr, gettext(
"%s: %s: unpacking error\n"),
argv0, filename);
return (0);
}
c = *inp++;
bitsleft = 8;
while (--bitsleft >= 0) {
i *= 2;
if (c & 0200)
i++;
c <<= 1;
if ((j = i - intnodes[lev]) >= 0) {
p = &tree[lev][j];
if (p == eof) {
c = outp - &outbuff[0];
if (write(outfile, &outbuff[0], c)
!= c) {
wrerr: (void) fprintf(stderr,
gettext(
"%s: %s: write error: "),
argv0, argvk);
perror("");
return (0);
}
origsize -= c;
if (origsize != 0)
goto uggh;
return (1);
}
*outp++ = *p;
if (outp == &outbuff[BUFSIZ]) {
if (write(outfile, outp = &outbuff[0],
BUFSIZ) != BUFSIZ)
goto wrerr;
origsize -= BUFSIZ;
}
lev = 1;
i = 0;
} else
lev++;
}
}
return (1);
}
int
main(int argc, char *argv[])
{
extern int optind;
int i, k;
int error;
int sep, errflg = 0, pcat = 0;
register char *p1, *cp;
int fcount = 0;
int max_name;
void onsig(int);
acl_t *aclp = NULL;
int c;
char *progname;
int sattr_exist = 0;
int xattr_exist = 0;
if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
#ifdef __STDC__
(void) signal((int)SIGHUP, onsig);
#else
(void) signal((int)SIGHUP, onsig);
#endif
if (signal(SIGINT, SIG_IGN) != SIG_IGN)
#ifdef __STDC__
(void) signal((int)SIGINT, onsig);
#else
(void) signal((int)SIGINT, onsig);
#endif
if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
#ifdef __STDC__
(void) signal((int)SIGTERM, onsig);
#else
(void) signal(SIGTERM, onsig);
#endif
(void) setlocale(LC_ALL, "");
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
(void) textdomain(TEXT_DOMAIN);
if (progname = strrchr(argv[0], '/'))
++progname;
else
progname = argv[0];
p1 = *argv;
while (*p1++) { };
while (--p1 >= *argv)
if (*p1 == '/')break;
*argv = p1 + 1;
argv0 = argv[0];
if (**argv == 'p')pcat++;
while ((c = getopt(argc, argv, "/")) != EOF) {
if (c == '/') {
if (pcat)
++errflg;
else
saflg++;
} else
++errflg;
}
argc -= optind;
argv = &argv[optind];
if (errflg || argc < 1) {
if (!pcat)
(void) fprintf(stderr,
gettext("usage: %s [-/] file...\n"), argv0);
else
(void) fprintf(stderr, gettext("usage: %s file...\n"),
argv0);
if (argc < 1) {
return (1);
}
}
for (k = 0; k < argc; k++) {
fcount++;
if (errflg) {
continue;
}
for (cp = argv[k]; *cp != '\0'; ++cp)
;
if (cp[-1] == SUF1 && cp[-2] == SUF0) {
*cp-- = '\0'; *cp-- = '\0'; *cp = '\0';
}
sep = -1;
cp = filename;
argvk = argv[k];
for (i = 0; i < (MAXPATHLEN-3) && (*cp = argvk[i]); i++)
if (*cp++ == '/')
sep = i;
*cp++ = SUF0;
*cp++ = SUF1;
*cp = '\0';
if ((infile = open(filename, O_RDONLY)) == -1) {
(void) fprintf(stderr, gettext(
"%s: %s: cannot open: "),
argv0, filename);
perror("");
goto done;
}
if (pcat)
outfile = 1;
else {
error = facl_get(infile, ACL_NO_TRIVIAL, &aclp);
if (error != 0) {
(void) printf(gettext(
"%s: %s: cannot retrieve ACL : %s\n"),
argv0, filename, acl_strerror(error));
}
max_name = pathconf(filename, _PC_NAME_MAX);
if (max_name == -1) {
max_name = _POSIX_NAME_MAX;
}
if (i >= (MAXPATHLEN-1) || (i - sep - 1) > max_name) {
(void) fprintf(stderr, gettext(
"%s: %s: file name too long\n"),
argv0, argvk);
goto done;
}
if (stat(argvk, &status) != -1) {
(void) fprintf(stderr, gettext(
"%s: %s: already exists\n"),
argv0, argvk);
goto done;
}
(void) fstat(infile, &status);
if (status.st_nlink != 1) {
(void) printf(gettext(
"%s: %s: Warning: file has links\n"),
argv0, filename);
}
if ((outfile = creat(argvk, status.st_mode)) == -1) {
(void) fprintf(stderr, gettext(
"%s: %s: cannot create: "),
argv0, argvk);
perror("");
goto done;
}
rmflg = 1;
}
if (getdict()) {
if (pathconf(filename, _PC_XATTR_EXISTS) == 1)
xattr_exist = 1;
if (saflg && sysattr_support(filename,
_PC_SATTR_EXISTS) == 1)
sattr_exist = 1;
if (pcat || xattr_exist || sattr_exist) {
if (mv_xattrs(progname, filename, argv[k],
sattr_exist, 0)
!= 0) {
xattr_exist = 0;
sattr_exist = 0;
if (pathconf(argvk, _PC_XATTR_EXISTS)
== 1)
xattr_exist = 1;
if (saflg && sysattr_support(argvk,
_PC_SATTR_EXISTS) == 1)
sattr_exist = 1;
if (!pcat && (xattr_exist ||
sattr_exist)) {
(void) mv_xattrs(progname,
argv[k], filename,
sattr_exist, 1);
(void) unlink(argvk);
goto done;
}
} else {
if (!pcat)
(void) unlink(filename);
}
} else if (!pcat)
(void) unlink(filename);
if (!pcat) {
(void) printf(gettext("%s: %s: unpacked\n"),
argv0, argvk);
u_times.actime = status.st_atime;
u_times.modtime = status.st_mtime;
if (utime(argvk, &u_times) != 0) {
errflg++;
(void) fprintf(stderr, gettext(
"%s: cannot change times on %s: "),
argv0, argvk);
perror("");
}
if (chmod(argvk, status.st_mode) != 0) {
errflg++;
(void) fprintf(stderr, gettext(
"%s: cannot change mode to %o on %s: "),
argv0, (uint_t)status.st_mode,
argvk);
perror("");
}
(void) chown(argvk,
status.st_uid, status.st_gid);
if (aclp && (facl_set(outfile, aclp) < 0)) {
(void) printf(gettext("%s: cannot "
"set ACL on %s: "), argv0, argvk);
perror("");
}
rmflg = 0;
}
if (!errflg)
fcount--;
}
done: (void) close(infile);
if (!pcat)
(void) close(outfile);
if (aclp) {
acl_free(aclp);
aclp = NULL;
}
}
return (fcount);
}
static int Tree[1024];
int
expand()
{
int tp, bit;
short word;
int keysize, i, *t;
outp = outbuff;
inp = &inbuff[2];
inleft -= 2;
origsize = ((long)(unsigned)getwdsize())*256*256;
origsize += (unsigned)getwdsize();
if (origsize == 0 || is_eof) {
(void) fprintf(stderr, gettext(
"%s: %s: not in packed format\n"),
argv0, filename);
return (0);
}
t = Tree;
for (keysize = getwdsize(); keysize--; ) {
if ((i = getch()) == 0377)
*t++ = getwdsize();
else {
if (is_eof) {
(void) fprintf(stderr, gettext(
"%s: %s: not in packed format\n"),
argv0, filename);
return (0);
}
*t++ = i & 0377;
}
}
if (is_eof) {
(void) fprintf(stderr, gettext(
"%s: %s: not in packed format\n"),
argv0, filename);
return (0);
}
bit = tp = 0;
for (;;) {
if (bit <= 0) {
word = getwdsize();
if (word == 0 && is_eof && origsize > 0) {
(void) fprintf(stderr, gettext(
"%s: %s: not in packed format\n"),
argv0, filename);
return (0);
}
bit = 16;
}
tp += Tree[tp + (word < 0)];
word <<= 1;
bit--;
if (Tree[tp] == 0) {
putch(Tree[tp+1]);
tp = 0;
if ((origsize -= 1) == 0) {
(void) write(outfile, outbuff, outp - outbuff);
return (1);
}
}
}
}
int
getch()
{
if (inleft <= 0) {
inleft = read(infile, inp = inbuff, BUFSIZ);
if (inleft < 0) {
(void) fprintf(stderr, gettext(
"%s: %s: read error: "),
argv0, filename);
perror("");
longjmp(env, 1);
} else {
if (inleft == 0) {
is_eof = 1;
return (EOF);
}
}
}
inleft--;
return (*inp++ & 0377);
}
int
getwdsize()
{
char c;
int d;
c = getch();
d = getch();
if (is_eof)
return (0);
d <<= 8;
d |= c & 0377;
return (d);
}
void
onsig(int sig)
{
if (rmflg == 1)
(void) unlink(argvk);
if (sig == SIGTERM || sig == SIGHUP || sig == SIGINT)
exit(1);
}
void
putch(char c)
{
int n;
*outp++ = c;
if (outp == &outbuff[BUFSIZ]) {
n = write(outfile, outp = outbuff, BUFSIZ);
if (n < BUFSIZ) {
(void) fprintf(stderr, gettext(
"%s: %s: write error: "),
argv0, argvk);
perror("");
longjmp(env, 2);
}
}
}