home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
kermit.columbia.edu
/
kermit.columbia.edu.tar
/
kermit.columbia.edu
/
tu
/
tuvwta.c
< prev
next >
Wrap
C/C++ Source or Header
|
1988-08-16
|
14KB
|
606 lines
#include <stdio.h>
#define NOKNET
#define import_spp
#define import_finfo
#define import_knames
#include <iraf.h>
/*
* WTAR -- Write a UNIX tar format file (on disk, tape, or to stdout)
*
* Switches:
* f write to named file, otherwise write to stdout
* t print name of each file written
* v verbose; print full description of each file
* d print debug messages
* o omit binary files (e.g. when foreign host has
* incompatible binary file format)
*/
#define TBLOCK 512
#define NBLOCK 20
#define NAMSIZ 100
#define MAXERR 20
#define MAXTRYS 100
#define SZ_TAPEBUFFER (TBLOCK * NBLOCK)
#define RWXR_XR_X 0755
/* File header structure. One of these precedes each file on the tape.
* Each file occupies an integral number of TBLOCK size logical blocks
* on the tape. The number of logical blocks per physical block is variable,
* with at most NBLOCK logical blocks per physical tape block. Two zero
* blocks mark the end of the tar file.
*/
union hblock {
char dummy[TBLOCK];
struct header {
char name[NAMSIZ]; /* NULL delimited */
char mode[8]; /* octal, ascii */
char uid[8];
char gid[8];
char size[12];
char mtime[12];
char chksum[8];
char linkflag;
char linkname[NAMSIZ];
} dbuf;
};
/* Decoded file header.
*/
struct fheader {
char name[NAMSIZ];
int mode;
int uid;
int gid;
int isdir;
long size;
long mtime;
long chksum;
int linkflag;
char linkname[NAMSIZ];
};
/* Map TAR file mode bits into characters for printed output.
*/
struct _modebits {
int code;
char ch;
} modebits[] = {
040000, 'd',
0400, 'r',
0200, 'w',
0100, 'x',
040, 'r',
020, 'w',
010, 'x',
04, 'r',
02, 'w',
01, 'x',
0, 0
};
int debug=NO; /* Print debugging messages */
int omitbinary; /* omit binary files */
int printfnames; /* Print file names */
int verbose; /* Print everything */
struct fheader *curfil;
int nerrs;
char *first_file;
char tapeblock[SZ_TAPEBUFFER];
char *nextblock = NULL;
int nblocks;
int in;
int out = EOF;
extern char *vfn2osfn();
long os_utime();
/* MAIN -- "wtar [-tvdo] [-f tarfile] [files]". If no files are listed the
* current directory tree is used as input. If no output file is specified
* output is to the standard output.
*/
main (argc, argv)
int argc;
char *argv[];
{
static char *def_flist[2] = { ".", NULL };
char *argp, **flist;
int argno, ftype, i;
ZZSTRT();
flist = def_flist;
omitbinary = NO;
printfnames = debug;
verbose = debug;
if (debug) {
printf ("wtar called with %d arguments:", argc);
for (argno=1; (argp = argv[argno]) != NULL; argno++)
printf (" %s", argp);
printf ("\n");
}
/* Process the argument list.
*/
for (argno=1; (argp = argv[argno]) != NULL; argno++) {
if (*argp != '-') {
flist = &argv[argno];
break;
} else {
for (argp++; *argp; argp++) {
switch (*argp) {
case 'd':
debug++;
printfnames++;
verbose++;
break;
case 't':
printfnames++;
break;
case 'v':
verbose++;
break;
case 'o':
omitbinary++;
break;
case 'f':
if (argv[argno+1]) {
argno++;
if (debug)
printf ("open output file `%s'\n", argv[argno]);
out = tape_open (argv[argno], 1);
if (out == ERR) {
fprintf (stderr,
"cannot open `%s'\n", argv[argno]);
ZZSTOP();
exit (OSOK+1);
}
}
break;
default:
fprintf (stderr,
"Warning: unknown switch -%c\n", *argp);
fflush (stderr);
}
}
}
}
/* Write to the standard output if no output file specified.
* The filename "stdin" is reserved.
*/
if (out == ERR) {
if (debug)
printf ("output defaults to stdout\n");
out = tape_open ("stdout", 1);
}
nextblock = tapeblock;
nblocks = 0;
/* Put each directory and file listed on the command line to
* the tarfile.
*/
for (i=0; (argp = flist[i]) != NULL; i++)
if ((ftype = os_filetype (argp)) == DIRECTORY_FILE)
putfiles (argp, out, "");
else
tarfileout (argp, out, ftype, "");
/* Close the tarfile.
*/
endtar (out);
tape_close (out);
ZZSTOP();
exit (OSOK);
}
/* PUTFILES -- Put the named directory tree to the output tarfile. We chdir
* to each subdirectory to minimize path searches and speed up execution.
*/
putfiles (dir, out, path)
char *dir; /* directory name */
int out; /* output file */
char *path; /* pathname of curr. directory */
{
char newpath[SZ_PATHNAME+1];
char fname[SZ_PATHNAME+1];
int ftype, dp;
if (debug)
printf ("putfiles (%s, %d, %s)\n", dir, out, path);
/* Put the directory file itself to the output as a file.
*/
tarfileout (dir, out, DIRECTORY_FILE, path);
if ((dp = os_diropen (dir)) == ERR) {
fprintf (stderr, "cannot open subdirectory `%s%s'\n", path, dir);
fflush (stderr);
return;
}
sprintf (newpath, "%s%s/", path, dir);
if (debug)
printf ("change directory to %s\n", newpath);
if (os_chdir (dir) == ERR) {
os_dirclose (dp);
fprintf (stderr, "cannot change directory to `%s'\n", newpath);
fflush (stderr);
return;
}
/* Put each file in the directory to the output file. Recursively
* read any directories encountered.
*/
while (os_gfdir (dp, fname, SZ_PATHNAME) > 0)
if ((ftype = os_filetype (fname)) == DIRECTORY_FILE)
putfiles (fname, out, newpath);
else
tarfileout (fname, out, ftype, newpath);
if (debug)
printf ("return from subdirectory %s\n", newpath);
if (os_chdir ("..") == ERR) {
fprintf (stderr, "cannot return from subdirectory `%s'\n", newpath);
fflush (stderr);
}
os_dirclose (dp);
}
/* TARFILEOUT -- Write the named file to the output in tar format.
*/
tarfileout (fname, out, ftype, path)
char *fname; /* file to be output */
int out; /* output stream */
int ftype; /* file type */
char *path; /* current path */
{
struct _finfo fi;
struct fheader fh;
int status;
if (debug)
printf ("put file `%s', type %d\n", fname, ftype);
if (ftype == BINARY_FILE && omitbinary) {
if (printfnames) {
fprintf (stderr, "omit binary file `%s'\n", fname);
fflush (stderr);
}
return;
}
/* Get info on file to make file header.
*/
ZFINFO ((PKCHAR *)vfn2osfn(fname,0), &fi, &status);
if (status == XERR) {
fprintf (stderr, "Warning: can't get info on file `%s'\n", fname);
fflush (stderr);
return;
}
/* Format and output the file header.
*/
strcpy (fh.name, path);
strcat (fh.name, fname);
if (ftype == DIRECTORY_FILE) {
strcat (fh.name, "/");
fh.size = 0;
fh.isdir = 1;
} else {
fh.size = fi.fi_size;
fh.isdir = 0;
}
os_getowner (fname, &fh.uid, &fh.gid);
fh.linkflag = 0; /* no links allowed */
strcpy (fh.linkname, "");
fh.mode = u_fmode (fi.fi_perm, fi.fi_type);
fh.mtime = os_utime (fi.fi_mtime);
if (putheader (&fh, out) == EOF) {
fprintf (stderr,
"Warning: could not write file header for `%s'\n", fname);
fflush (stderr);
return;
}
/* Copy the file data.
*/
if (fh.size > 0 && !fh.isdir)
copyfile (fname, &fh, ftype, out);
if (printfnames) {
printheader (stdout, &fh, verbose);
fflush (stdout);
}
}
/* PUTHEADER -- Encode and write the file header to the output tarfile.
*/
putheader (fh, out)
register struct fheader *fh; /* (input) file header */
int out; /* output file descriptor */
{
register char *ip, *op;
register int n;
union hblock hb;
/* Clear the header block. */
for (n=0; n < TBLOCK; n++)
hb.dummy[n] = '\0';
/* Encode the file header.
*/
strcpy (hb.dbuf.name, fh->name);
sprintf (hb.dbuf.mode, "%6o ", fh->mode);
sprintf (hb.dbuf.uid, "%6o ", fh->uid);
sprintf (hb.dbuf.gid, "%6o ", fh->gid);
sprintf (hb.dbuf.size, "%11lo ", fh->size);
sprintf (hb.dbuf.mtime, "%11lo ", fh->mtime);
n = fh->linkflag;
if (n >= '0' && n <= '9')
hb.dbuf.linkflag = n - '0';
else
hb.dbuf.linkflag = 0;
strcpy (hb.dbuf.linkname, fh->linkname);
/* Encode the checksum value for the file header and then
* write the field. Calculate the checksum with the checksum
* field blanked out. Compute the actual checksum as the sum of
* all bytes in the header block. A sum of zero indicates the
* end of the tar file.
*/
for (n=0; n < 8; n++)
hb.dbuf.chksum[n] = ' ';
sprintf (hb.dbuf.chksum, "%6.8o", cchksum (hb.dummy, TBLOCK));
if (debug) {
printf ("File header:\n");
printf (" name = %s\n", hb.dbuf.name);
printf (" mode = %s\n", hb.dbuf.mode);
printf (" uid = %s\n", hb.dbuf.uid);
printf (" gid = %s\n", hb.dbuf.gid);
printf (" size = %-12.12s\n", hb.dbuf.size);
printf (" mtime = %-12.12s\n", hb.dbuf.mtime);
printf (" chksum = %s\n", hb.dbuf.chksum);
printf (" linkflag = %c\n", hb.dbuf.linkflag);
printf (" linkname = %s\n", hb.dbuf.linkname);
fflush (stdout);
}
/* Write the header to the tarfile.
*/
return (putblock (out, hb.dummy));
}
/* CCHKSUM -- Compute the checksum of a byte array.
*/
cchksum (p, nbytes)
register char *p;
register int nbytes;
{
register int sum;
for (sum=0; --nbytes >= 0; )
sum += *p++;
return (sum);
}
/* PRINTHEADER -- Print the file header in either short or long (verbose)
* format, e.g.:
* drwxr-xr-x 9 tody 1024 Nov 3 17:53 .
*/
printheader (fp, fh, verbose)
FILE *fp; /* output file */
register struct fheader *fh; /* file header struct */
int verbose; /* long format output */
{
register struct _modebits *mp;
char *tp, *ctime();
if (!verbose) {
fprintf (fp, "%s\n", fh->name);
return;
}
for (mp=modebits; mp->code; mp++)
fprintf (fp, "%c", mp->code & fh->mode ? mp->ch : '-');
tp = ctime (&fh->mtime);
fprintf (fp, "%3d %4d %2d %8d %-12.12s %-4.4s %s",
fh->linkflag,
fh->uid,
fh->gid,
fh->size,
tp + 4, tp + 20,
fh->name);
if (fh->linkflag)
fprintf (fp, " -> %s\n", fh->linkname);
else
fprintf (fp, "\n");
}
/* COPYFILE -- Copy bytes from the input file to the output file. Each file
* consists of a integral number of TBLOCK size blocks on the output file.
*/
copyfile (fname, fh, ftype, out)
char *fname; /* file being read from */
struct fheader *fh; /* file header structure */
int ftype; /* file type, text or binary */
int out; /* output file */
{
register char *bp;
register int i;
int nbytes, nleft, blocks, fd, count, total, ch;
char buf[TBLOCK*2];
bp = buf;
total = nbytes = 0;
blocks = (fh->size + TBLOCK - 1 ) / TBLOCK;
if ((fd = os_open (fname, 0, ftype)) == ERR) {
fprintf (stderr, "Warning: cannot open file `%s'\n", fname);
fflush (stderr);
goto pad_;
}
while (blocks > 0) {
if ((count = os_read (fd, bp, TBLOCK)) == ERR || count > TBLOCK) {
fprintf (stderr, "Warning: file read error on `%s'\n", fname);
fflush (stderr);
if (nerrs++ > MAXERR) {
fprintf (stderr, "Too many errors\n");
exit (OSOK+1);
}
} else {
/* Buffer input to TBLOCK blocks.
*/
if (count == 0) /* EOF */
break;
else if ((nbytes += count) < TBLOCK)
bp += count;
else {
putblock (out, buf);
blocks--;
/* Copy overflow back to beginning... */
if (nbytes > TBLOCK) {
nleft = nbytes - TBLOCK;
os_amovb (&buf[TBLOCK], buf, nbytes - TBLOCK);
} else
nleft = 0;
bp = (char *) ((int)buf + nleft);
total += nbytes;
nbytes = nleft;
}
}
}
os_close (fd);
/* Fill current block and subsequent full blocks until the number of
* bytes specified in the file header have been output. All files
* occupy an integral number of 512 byte blocks on tape. For text
* files, pad with spaces, otherwise pad with nulls. Also, for text
* files, add newlines to avoid excessively long lines.
*/
pad_:
ch = (ftype == TEXT_FILE) ? ' ' : '\0';
while (blocks > 0) {
for (i=nbytes; i < TBLOCK; i++)
if (ftype == TEXT_FILE && i % 64 == 0)
buf[i] = '\n';
else
buf[i] = ch;
if (ftype == TEXT_FILE)
buf[TBLOCK-1] = '\n';
putblock (out, buf);
blocks--;
nbytes = 0;
}
}
/* PUTBLOCK -- Write a block to tape (buffered).
*/
putblock (out, buf)
int out;
char *buf;
{
int nbytes = 0;
if (buf) {
os_amovb (buf, nextblock, TBLOCK);
nextblock += TBLOCK;
if (++nblocks == NBLOCK)
nbytes = SZ_TAPEBUFFER;
} else
nbytes = nblocks * TBLOCK;
if (nbytes > 0) {
if (tape_write (out, tapeblock, nbytes) < nbytes) {
fprintf (stderr, "Warning: write error on tarfile\n");
fflush (stderr);
}
nextblock = tapeblock;
nblocks = 0;
}
return (TBLOCK);
}
/* ENDTAR -- Write the end of the tar file, i.e., two zero blocks.
*/
endtar (out)
int out;
{
register int i;
union hblock hb;
if (debug)
printf ("write end of tar file\n");
for (i=0; i < TBLOCK; i++)
hb.dummy[i] = '\0';
putblock (out, hb.dummy); /* write 2 null blocks */
putblock (out, hb.dummy);
putblock (out, 0); /* flush tape buffer */
}
/* U_FMODE -- Convert the IRAF file mode bits to the corresponding UNIX bits
* for the tar file header.
*/
u_fmode (iraf_fmode, ftype)
int iraf_fmode;
int ftype;
{
register int in = iraf_fmode;
register int m = 0;
int exec;
exec = (ftype == FI_DIRECTORY || ftype == FI_EXECUTABLE);
if (in & 001) m |= 0400; /* Owner READ */
if (in & 002) m |= 0200; /* WRITE */
if (exec) m |= 0100; /* EXECUTE */
if (in & 004) m |= 040; /* Group READ */
if (in & 010) m |= 020; /* WRITE */
if (exec) m |= 010; /* EXECUTE */
if (in & 020) m |= 004; /* World READ */
if (in & 040) m |= 002; /* WRITE */
if (exec) m |= 001; /* EXECUTE */
return (m);
}