V10/cmd/asd/package.c
#include "asd.h"
#include "ftw.h"
FILE *tf;
static Sig_typ sigsav;
static int rc;
static char tfname[TMPNAML];
/*
* Prepare to build a package. The package will appear on stdout.
* The argument is nonzero if remarks are to be read.
*/
void
pkgstart()
{
struct stat pks;
rc = 0;
nchk (fstat (fileno (stdout), &outsb));
/* establish a temporary file to hold the instruction information */
tmpname (tfname);
tf = fopen (tfname, "w");
sigsav = signal (SIGINT, SIG_IGN);
if (sigsav != SIG_IGN)
signal (SIGINT, delete);
nchk (chmod (tfname, 0644));
schk ((char *) tf);
/* create the initial element in the component chain */
pkhead = pktail = new (struct pack);
pkhead->iname = copy (instr);
pkhead->ename = copy (tfname);
pkhead->time = 0;
pkhead->link = NULL;
pkhead->uid = getuid();
nchk (fstat (fileno(tf), &pks));
pkhead->gid = pks.st_gid;
pkhead->mode = 0100644;
}
/*
* put a file (or directory) into a package
*/
void
pkgfile (file)
register char *file;
{
register int x;
struct stat sb;
/* if the file is truly not present, generate a remove request */
#ifdef S_IFLNK
if (lstat (file, &sb) < 0 && errno == ENOENT) {
#else
if (stat (file, &sb) < 0 && errno == ENOENT) {
#endif
fprintf (tf, "r ");
putpath (tf, transname (file));
putc ('\n', tf);
} else {
x = ftw (file, consider, 8);
if (x != 0) {
rc++;
if (x == -1)
perror (file);
}
}
}
/*
* we are done building a package. This writes the actual file
* contents, so make sure the files are still around
*/
int
pkgend()
{
register struct pack *pack;
struct stat s;
/* write 'x' or 'X' execution item if requested */
if (xstr) {
fprintf (tf, "x ");
putpath (tf, xstr);
fprintf (tf, "\n");
}
if (Xstr) {
fprintf (tf, "X ");
putpath (tf, Xstr);
fprintf (tf, "\n");
}
/* we now know how long the first component is */
pkhead->size = ftell (tf);
/* we no longer need to write the temporary file */
fclose (tf);
/* describe the temp file correctly so it will pass later checks */
if (pkhead->time == 0)
(void) time (&pkhead->time);
nchk (stat (tfname, &s));
pkhead->dev = s.st_dev;
pkhead->ino = s.st_ino;
/*
* write the files out into an archive
*/
/* first the archive header */
printf (ARMAG);
/*
* run through the list, creating the archive components
* and deleting the list entries. One iteration per component.
* We know there is at least one component, because the
* "Instructions" component must be represented.
*/
do {
struct ar_hdr ah;
char buf[30];
register int c;
/* "pack" is the package component under consideration */
pack = pkhead;
if (pack->iname) { /* non-regular file entry, no data */
/* log it if requested */
if (vflag)
fprintf (stderr, "package %s\n",
strcmp (pack->iname, instr)? pack->ename: instr);
/* write the archive element header */
# define ent(a,x) sprintf(buf, "%-*s", sizeof(ah.a), x); \
strncpy (ah.a, buf, sizeof (ah.a))
ent (ar_name, pack->iname);
ent (ar_fmag, ARFMAG);
# undef ent
# define ent(a,x) sprintf(buf, "%*ld", sizeof(ah.a), (long) x); \
strncpy (ah.a, buf, sizeof (ah.a))
ent (ar_date, pack->time);
ent (ar_uid, pack->uid);
ent (ar_gid, pack->gid);
ent (ar_size, pack->size);
# undef ent
# define ent(a,x) sprintf(buf, "%*o", sizeof(ah.a), x); \
strncpy (ah.a, buf, sizeof (ah.a))
ent (ar_mode, pack->mode);
# undef ent
fwrite ((char *) &ah, sizeof (ah), 1, stdout);
/* write the archive element itself */
tf = fopen (pack->ename, "r");
if (tf == NULL) {
perror (pack->iname);
exit (1);
}
while ((c = getc (tf)) != EOF)
putchar (c);
/* if things now don't match, complain */
if (fstat (fileno (tf), &s) < 0 || s.st_size != pack->size ||
(s.st_mtime != pack->time && strcmp (pack->iname, instr)) ||
s.st_dev != pack->dev || s.st_ino != pack->ino ||
s.st_uid != pack->uid || s.st_gid != pack->gid ||
(s.st_mode & 07777) != (pack->mode & 07777)) {
fprintf (stderr, "phase error on %s\n",
pack->ename);
rc++;
}
fclose (tf);
if (pack->size & 1)
putchar ('\n');
}
/* delete the element, move on to the next */
if (pack->iname) free (pack->iname);
free (pack->ename);
pkhead = pack->link;
free ((char *) pack);
} while (pkhead);
/* zap the tail pointer for general cleanliness */
pktail = NULL;
nchk (unlink (tfname));
signal (SIGINT, sigsav);
return rc;
}
/* internal function for package creation */
static int
consider (name, buf, type)
register char *name;
register struct stat *buf;
register int type;
{
register struct pack *pack;
register int mode;
char *biname;
#ifdef S_IFLNK
char *slname;
#endif
switch (type) {
case FTW_D:
fprintf (tf, "d %-*.4o ", MAXCOMP, buf->st_mode & 07777);
hdrsub (name, buf);
fprintf (tf, "\n");
break;
case FTW_F:
case FTW_SL:
mode = buf->st_mode & S_IFMT;
/* Has this file already appeared? If so, it's a link */
for (pack = pkhead->link; pack; pack = pack->link) {
if (buf->st_dev == pack->dev &&
buf->st_ino == pack->ino) {
fprintf (tf, "l %s ", transname (pack->ename));
fprintf (tf, "%s\n", transname (name));
return 0;
}
}
switch (mode) {
#ifdef S_IFLNK
case S_IFLNK:
slname = alloc((unsigned)buf->st_size+1);
slname[buf->st_size] = '\0';
if (readlink(name, slname, buf->st_size) !=
buf->st_size) {
perror(name);
return (0);
}
fprintf (tf, "s %s ", transname (slname));
fprintf (tf, "%s\n", transname (name));
biname = NULL;
break;
#endif
case S_IFBLK:
case S_IFCHR: /* is it a special file? */
fprintf (tf, "%c %#o %d %d ",
mode == S_IFBLK? 'b': 'c',
buf->st_mode & 07777,
major (buf->st_rdev),
minor (buf->st_rdev));
hdrsub (name, buf);
fprintf (tf, "\n");
biname = NULL;
break;
case S_IFREG:
/* refuse to package the standard output */
if (buf->st_dev == outsb.st_dev &&
buf->st_ino == outsb.st_ino) {
fprintf (stderr, "skipping output file %s\n",
fullname (name));
return 0;
}
biname = iname (name);
fprintf (tf, "f ");
putpath (tf, biname);
fprintf (tf, " ");
hdrsub (name, buf);
fprintf (tf, "\n");
break;
default:
fprintf (stderr, "%s: unrecognized file type\n",
fullname (name));
return 0;
}
/* package the file */
pack = new (struct pack);
pack->ename = copy (name);
pack->dev = buf->st_dev;
pack->ino = buf->st_ino;
pack->uid = buf->st_uid;
pack->gid = buf->st_gid;
pack->time = buf->st_mtime;
if (pack->time > pkhead->time)
pkhead->time = pack->time;
pack->size = buf->st_size;
pack->mode = buf->st_mode;
pack->link = NULL;
pack->iname = biname;
pktail->link = pack;
pktail = pack;
break;
case FTW_DNR:
fprintf (stderr, "cannot read directory %s\n", name);
return 1;
case FTW_NS:
fprintf (stderr, "cannot stat %s\n", name);
return 1;
case FTW_DP:
break;
default:
fprintf (stderr, "impossible code %d from ftw\n", type);
exit (1);
}
return 0;
}
static
hdrsub (name, buf)
register char *name;
register struct stat *buf;
{
putpath (tf, struid (buf->st_uid));
putc ('\t', tf);
putpath (tf, strgid (buf->st_gid));
putc ('\t', tf);
putpath (tf, transname (name));
}
/*
* generate a unique internal name for a file
*/
static char *
iname (s)
char *s;
{
register char *p;
register char *lastcomp;
register struct pack *pack;
char trial[MAXCOMP+1];
/* point lastcomp at the last pathname component */
lastcomp = s;
for (p = s; *p; p++) {
if (*p == '/')
lastcomp = p + 1;
}
/* if the name is acceptably short, modify it slightly */
if (strlen (lastcomp) <= MAXCOMP) {
char prefix[MAXCOMP+1], suffix[MAXCOMP+1], num[30];
register int n;
/* split the name, remove unprintables */
strcpy (prefix, lastcomp);
for (p = prefix; *p; p++)
if (*p == ' ' || !isprint (*p))
*p = '$';
suffix[0] = '\0';
p = strrchr (prefix, '.');
if (p != NULL) {
strcpy (suffix, p);
*p = '\0';
}
/* generate trial names until we run out of space */
for (n = 0, num[0] = '\0';
strlen(prefix) + strlen(suffix) + strlen(num) <= MAXCOMP;
n++, sprintf (num, "%.0d", n)) {
/* generate the trial name */
strcpy (trial, prefix);
strcat (trial, num);
strcat (trial, suffix);
/* if the name is unique, we're done */
pack = pkhead;
while (pack != NULL && strcmp (pack->iname, trial) != 0)
pack = pack->link;
if (pack == NULL)
return copy(trial);
}
}
/* punt -- generate a completely new name */
do {
static int tempno;
tempno++;
sprintf (trial, "Temp%d", tempno);
pack = pkhead;
while (pack != NULL && strcmp (trial, pack->iname) != 0)
pack = pack->link;
} while (pack != NULL);
return copy(trial);
}
static void
delete()
{
unlink (tfname);
exit (3);
}