Ultrix-3.1/src/cmd/ltf/putfile.c
/**********************************************************************
* Copyright (c) Digital Equipment Corporation 1984, 1985, 1986. *
* All Rights Reserved. *
* Reference "/usr/src/COPYRIGHT" for applicable restrictions. *
**********************************************************************/
#ifndef lint
static char *sccsid = "@(#)putfile.c 3.0 (ULTRIX) 4/21/86";
#endif lint
/**/
/*
*
* File name:
*
* putfile.c
*
* Source file description:
*
* This file contains the logic to put
* individual files on an output volume for
* the Labeled Tape Facility (LTF).
*
*
* Functions:
*
* bflush() Flushes Fortran Unformatted File
* record buffer data to output
* volume.
*
* addrtyp() ?_? Used during Fortran Formatted
* File output record processing.
*
* append() Appends (writes) the current
* file to the output volume.
*
* process() The function that actually
* writes the ANSI file header
* and ANSI file trailer
* records on the output volume.
*
* putfile() Determines the "type" of file
* being put on the output volume
* and calls function "process" to
* cause the file to be output.
*
* Usage:
*
* n/a
*
* Compile:
*
* cc -O -c putfile.c <- For Ultrix-32/32m
*
* cc CFLAGS=-DU11-O putfile.c <- For Ultrix-11
*
*
* Modification history:
* ~~~~~~~~~~~~~~~~~~~~
*
* revision comments
* -------- -----------------------------------------------
* 01.0 2-May-85 Ray Glaser
* Create original version.
*
* 01.1 10-Sep-85 Suzanne Logcher
* Add logic to detect current century
*
* 01.2 24-Sep-85 Suzanne Logcher
* Add logic to treat directory and subdirectory
* entries using ../ or ./ as relative pathnames
*
* 01.3 31-Oct-85 Suzanne Logcher
* Add logic to create segmented files
*/
/*
* +--> Local Includes
*/
#include "ltfdefs.h"
char *rindex();
/**/
/*
*
* Function:
*
* bflush
*
* Function Description:
*
* Flushes (writes to output volume) the Fortran
* Unformatted File record buffer.
*
* Arguments:
*
* char *name filename used when error in write
* char *Inbuf file writing buffer
*
* Return values:
*
* none
*
* Side Effects:
*
* Data is written to the output volume from the
* and the blocks written count is updated.
*/
bflush(name, Inbuf)
char *name; /* filename */
char *Inbuf; /* File writing buffer */
{
if (Rb - Bb > 0) {
while (Rb < Bb + Blocksize)
*Rb++ = PAD;
if (write(fileno(Magtfp), Inbuf, Blocksize) != Blocksize) {
PERROR "\n%s: %s %s\n", Progname, ERRWRF, name);
perror(Magtdev);
ceot();
}
Blocks++;
}
}/*E bflush() */
/**/
/*
*
* Function:
*
* addrtyp
*
* Function Description:
*
* Used during output to a volume for Fortran
* Unformatted File proccessing ?_?
*
* Arguments:
*
* char *inch ?_?
* char *typ ?_?
*
*
* Return values:
*
* none
*
* Side Effects:
*
* not known at this time
*/
addrtyp(inch, typ)
char *inch;
char *typ;
{
inch[4] = typ[0];
inch[5] = typ[1];
}/*E addrtyp() */
/**/
/*
*
* Function:
*
* append
*
* Function Description:
*
* Appends (writes) the given file to the output volume.
*
* Arguments:
*
* char *name filename
* FILE *fp Pointer to file to output
* int max Maximum line length
* int type Type of ANSI tape file being output
* int tftype True file type of file being output
* char *Inbuf File writing buffer
*
* Return values:
*
* Returns a LONG count of number of blocks output.
*
* Returns -1 and -2 as error indicators.
*
* Side Effects:
*
*
*/
long append(name, fp, type, tftype, max, Inbuf)
char *name; /* filename */
FILE *fp;
int type, tftype, max;
char *Inbuf; /* File writing buffer */
{
/*
* +--> Local Variables
*/
int done; /* Boolean used for segmented records */
int fillbuf; /* Integer of amount of data to read to fill
* line buffer to Blocksize */
char *index(); /* subroutine to find first char in string */
int length; /* Length of line */
char line[MAXBLKWRT+1]; /* Line read in from file to output */
int midway; /* Boolean used for segmented records */
int notfini; /* Boolean used for TEXT loop */
char *p; /* Pointer to the line input buffer */
char *q; /* Pointer to the line input buffer */
int used = 0; /* Number of characters used in Buffer for
* segmented records */
/*------*\
Code
\*------*/
Blocks = 0L;
p = Inbuf;
/*------*\
TEXT FILE
\*------*/
if (type == TEXT) {
notfini = TRUE;
midway = FALSE;
q = line;
fillbuf = Blocksize;
while (notfini != EOF) {
if (tftype != SYMLNK || Nosym) {
if ((i = read(fileno(fp), q, fillbuf)) <= 0)
if (i < 0) {
PERROR "\n%s: %s %s\n", Progname, CANTRD, name);
perror(Progname);
exit(FAIL);
}
else
break;
q[i] = '\0';
}
else
strcpy(line, Inbuf);
q = line;
done = FALSE;
while (done == FALSE) {
if (cp = index(q, '\n'))
*cp = '\0';
else
if (Format == VARIABLE)
break;
length = strlen(q);
if (length > max)
return((long)(-1));
if (Format == VARIABLE) {
if (&p[length+4] > &Inbuf[Blocksize]) {
while (p < &Inbuf[Blocksize])
*p++ = PAD;
if (write(fileno(Magtfp), Inbuf, Blocksize) != Blocksize) {
PERROR "\n%s: %s %s\n", Progname, ERRWRF, name);
perror(Magtdev);
ceot();
}
p = Inbuf;
Blocks++;
}
sprintf(p, "%04d%s", length+4, q);
p = &p[length+4];
q = ++cp;
}/*T if (Format == VARIABLE) */
else {
if (&p[length+5] <= &Inbuf[Blocksize]) {
if (cp) {
if (midway == FALSE)
sprintf(p, "%01d%04d%s", 0, length+5, q);
else {
sprintf(p, "%01d%04d%s", 3, length+5, q);
midway = FALSE;
}/*F if (midway == FALSE) */
used += length + 5;
p = &p[length+5];
q = ++cp;
}/*T if (cp) */
else {
strcpy(line, q);
q = &line[length];
fillbuf = Blocksize - length;
done = TRUE;
}/*F if (cp) */
}/* T if (&p[length+5] <= ... */
else {
if (used + 5 < Blocksize) {
if (midway == FALSE) {
sprintf(p, "%01d%04d%s", 1, Blocksize-used, q);
midway = TRUE;
}/*T if (midway == FALSE) */
else
sprintf(p, "%01d%04d%s", 2, Blocksize-used, q);
q = &q[Blocksize-used-5];
length -= Blocksize-used-5;
}/* T if (used + 5 < Blocksize) */
else
while (p < &Inbuf[Blocksize])
*p++ = PAD;
used = 0;
if (write(fileno(Magtfp), Inbuf, Blocksize) != Blocksize) {
PERROR "\n%s: %s %s\n", Progname, ERRWRF, name);
perror(Magtdev);
ceot();
}
p = Inbuf;
Blocks++;
if (cp)
q[length] = '\n';
if (strlen(q) == 0) {
q = line;
fillbuf = Blocksize;
done = TRUE;
}
}/*F if (&p[length+5] <= ... */
}/*F if (Format == VARIABLE) */
}/*E while (done == FALSE) */
if (tftype == SYMLNK && !Nosym)
notfini = EOF;
if (Format == VARIABLE) {
length = strlen(q);
strcpy(line, q);
q = &line[length];
fillbuf = Blocksize - length;
}
}/*E while (notfini != EOF */
if (p != Inbuf) {
while (p < &Inbuf[Blocksize])
*p++ = PAD;
if (write(fileno(Magtfp), Inbuf, Blocksize) != Blocksize) {
PERROR "\n%s: %s %s\n", Progname, ERRWRF, name);
perror(Magtdev);
ceot();
}
Blocks++;
}
}/*T if type == TEXT */
/*------*\
BINARY FILE
\*------*/
if (type == BINARY) {
while ((length = read(fileno(fp), p=Inbuf, Blocksize)) > 0) {
if (length < Blocksize) {
p = &p[length];
while (p < &Inbuf[Blocksize])
*p++ = PAD;
}
if (write(fileno(Magtfp), Inbuf, Blocksize) != Blocksize) {
PERROR "\n%s: %s %s\n", Progname, ERRWRF, name);
perror(Magtdev);
ceot();
}
p = Inbuf;
Blocks++;
}/*E while length = read ..*/
if (length < 0) {
PERROR "\n%s: %s %s\n", Progname, CANTRD, name);
perror(Progname);
exit(FAIL);
}
}/*T if (type == BINARY) */
/*------*\
COUNTED RECORD FILE
\*------*/
if (type == COUNTED) {
while ( fread( &length, sizeof (short), 1, fp)) {
if ( length == -1 || p+length+4 > &Inbuf[Blocksize]) {
while ( p < &Inbuf[Blocksize])
*p++ = PAD;
if (write(fileno(Magtfp), Inbuf, Blocksize) != Blocksize) {
PERROR "\n%s: %s %s\n", Progname, ERRWRF, name);
perror(Magtdev);
ceot();
}
p = Inbuf;
Blocks++;
}/*E if length == -1 ..*/
sprintf( p, "%04d", length+4);
fread( p+4, 2, (length+1)/2, fp);
/*
* Fudge for COUNTED records always beginning
* on a word boundary in file
*/
p += length+4;
}/*E while fread ..*/
if (p != Inbuf) {
while (p < &Inbuf[Blocksize])
*p++ = PAD;
if (write(fileno(Magtfp), Inbuf, Blocksize) != Blocksize) {
PERROR "\n%s: %s %s\n", Progname, ERRWRF, name);
perror(Magtdev);
ceot();
}
Blocks++;
}/*E if p != Inbuf */
}/*T if type == counted */
/*------*\
FORTRAN UNFORMATTED FILE
\*------*/
if (type == FUF) {
/*
* +--> Local Variables
*/
long bytcnt;
int irec;
int lastbit;
int nrec;
long nbytes, nbytesl;
char rectype;
int res, resl;
char *rp;
/*
* Initialize buffer pointers
*/
Bb = Inbuf;
Rb = Bb;
rp = Rb + RECOFF;
/*
* Loop over all records in the file. The unformatted
* format for f77 is as follows: each record is
* followed and preceded by a long int which contains
* the byte count of the record excluding the 2 long
* integers.
*/
while ((res = read(fileno(fp), &nbytes, sizeof(long))) > 0) {
if (nbytes > 0L) {
bytcnt = nbytes;
nrec = ((int)nbytes-1) / MAXREC6;
irec = nrec;
/*
* if record is greater than MAXREC6,
* then output it in chunks of MAXREC6
* first.
*/
while (irec--) {
if (Rb - Bb + MAXRECFUF > Blocksize) {
bflush(name, Inbuf);
Rb = Bb;
rp = Rb + RECOFF;
}
/*
* Read record in chunks of MAXREC6
*/
res = read(fileno(fp), rp, MAXREC6);
if (res < 0) {
PERROR "\n%s: %s%c\n\n",
Progname, EOFINM, BELL);
return((long)(-1));
}
if (res != MAXREC6) {
PERROR "%\n%s: %s%c\n\n",
Progname, WRLINM, BELL);
return((long)(-1));
}
/*
* Set up the record type. Note:
* to get here the record must
* be > MAXREC6 and it must be
* split. Thus there must be a
* FIRST record and all other
* records must be MIDDLE records.
* There could be a LAST record
* if the record was an exact
* multiple of MAXREC6.
*/
if (irec == nrec - 1)
rectype = FIRST;
else if (bytcnt > MAXREC6)
rectype = MIDDLE;
else
rectype = LAST;
/*
* Now output chunk of record
* on volume as VARIABLE format
*/
resl = res + RECOFF;
sprintf(Rb, "%04d", resl);
addrtyp(Rb, &rectype);
bytcnt -= res;
Rb += resl;
rp = Rb + RECOFF;
}/*E While irec-- */
/*
* Output final part (unless exact
* multiple of MAXREC6) of record or
* all of it if record is < MAXREC6.
*/
if (bytcnt > 0) {
lastbit = bytcnt;
if (Rb - Bb + lastbit + RECOFF > Blocksize) {
bflush(name, Inbuf);
Rb = Bb;
rp = Rb + RECOFF;
}
res = read(fileno(fp), rp, lastbit);
if (res < 0) {
PERROR "\n%s: %s%c\n\n",
Progname, EOFINM, BELL);
return((long)(-1));
}
if (res != lastbit) {
PERROR "%\n%s: %s%c\n\n",
Progname, WRLINM, BELL);
return((long)(-1));
}
if (lastbit == nbytes)
rectype = ALL;
else
rectype = LAST;
resl = res + RECOFF;
sprintf(Rb, "%04d", resl);
addrtyp(Rb, &rectype);
Rb += resl;
rp = Rb + RECOFF;
}/*E if bycnt > 0 */
}/*T if nbytes > 0L */
else {
if (Rb - Bb + RECOFF > Blocksize) {
bflush(name, Inbuf);
Rb = Bb;
rp = Rb + RECOFF;
}
sprintf(Rb, "%04d", RECOFF);
rectype = ALL;
addrtyp(Rb, &rectype);
Rb += RECOFF;
rp = Rb + RECOFF;
}/*F if nbytes > 0L */
res = read(fileno(fp), &nbytesl, sizeof(long));
if (res < 0) {
PERROR "\n%s: %s%c\n\n",
Progname, EOFINM, BELL);
return((long)(-1));
}
if (nbytesl != nbytes) {
PERROR "\n%s: %s%c\n\n",
Progname, BFRCNE, BELL);
return((long)(-1));
}
}/*E while res= read ..*/
if (res < 0) {
PERROR "\n%s: %s %s\n", Progname, CANTRD, name);
perror(Progname);
exit(FAIL);
}
bflush(name, Inbuf);
}/*E if type == FUF */
/*
* Return to the caller the number of blocks
* that were output to the volume.
*/
return(Blocks);
}/*E append()*/
/**/
/*
*
* Function:
*
* process
*
* Function Description:
*
* This functions writes the ANSI file header labels,
* file data, and ANSI file trailer labels to the
* output volume.
*
* Arguments:
*
* char *reallong; Contains the full pathname & file name
* char *longname; Contains the pathname & file name
* char *shortname; File name only
* int type; Ultrix disk file type
*
* Return values:
*
* none
*
* Side Effects:
*
* If the function encounters an error condition during
* the output of the file, a message is output to
* "stderr" and the function exits to system control.
*/
process(reallong, longname, shortname, type)
char *reallong; /* Full path name_+_filename */
char *longname; /* Relative path name_+_filename */
char *shortname; /* Contains the file name only */
int type; /* Type of Ultrix disk file */
{
/*
* +--> Local Variables
*/
char ansift; /* Save ANSI file type character from HDR2
* for later verbose messge output.
*/
int ch; /* Character returned from getc to check line
* size for TEXT files */
char crecent; /* Creation date century */
char *ctime(); /* Declare ctime routine */
char dummy[MAXPATHLEN+1]; /* dummy variable */
int found = 0; /* a head link is not on tape yet */
FILE *fp;
int hlink = 0; /* Flag set for field in HDR2 if hard link */
char Inbuf[MAXBLKWRT+1]; /* Buffer for writing files */
char interchange[18]; /* Interchange name */
int length; /* size of complete filename */
int linkflag = NO; /* Used to trigger output linked files
* message. Set to YES if the current file
* is linked to a file that has already
* been appended to the output volume.
*/
int lnkseq = 0; /* Field in HDR2 for file sequence number that
* a hard link points to */
struct tm *localtime();
struct ALINKBUF *lp; /* Node for hard link files */
struct tm *ltime;
int max; /* maximum line length */
int nlinks; /* number of links to file */
int otype = 0; /* If outputting sym link file, save SYMLNK
* file type to check in append routine */
char pathname[MAXPATHLEN+1]; /* path name */
int version = 1; /* version number (1 is default) */
/*------*\
Code
\*------*/
if (strlen(longname) >= MAXPATHLEN) {
PERROR "\n%s: %s %s%c\n\n",
Progname, FNTL, longname, BELL);
/*
* A string that long is probably fatal...
*/
exit(FAIL);
}
strcpy(dummy, longname);
pathname[0] = '\0';
if (cp = rindex(dummy, '/')) {
*++cp = '\0';
/*
* ?_? NOTE: When we get to putting loong file names on
* the output volume.. This logic will need to
* be updated...
*/
if (strlen(dummy) >= MAXPATHLEN) {
PERROR "\n%s: %s %s%c\n\n",
Progname, FNTL, longname, BELL);
/*
* A string that long is probably fatal...
*/
exit(FAIL);
}
strcpy(pathname, dummy);
}
/*
* Make the ANSI interchange file name
*/
strcpy(dummy,shortname);
j = 0;
if (!(filter_to_a(dummy,REPORT_ERRORS)))
if (Warning) {
PERROR "\n%s: %s %s", Progname, NONAFN, shortname);
PERROR "\n%s: %s %s", Progname, INVVID2, dummy);
j++;
}
if (strlen(dummy) > 17) {
/*
* If user has requested warnings, tell user file name
* is too long for HDR1 and that it will be truncated.
*/
dummy[17] = '\0';
if (Warning) {
PROMPT "\n%s: %s %s%c", Progname, FNTL, shortname, BELL);
j++;
}
}
if ((j > 0) && Warning)
PERROR "\n%s: %s\n\n", Progname, FILENNG);
strcpy(interchange, dummy);
interchange[17] = '\0';
if ((fp = fopen(reallong, "r")) == NULL) {
PERROR "\n%s: %s %s%c\n\n", Progname, CANTOPEN, reallong, BELL);
perror(Progname);
exit(FAIL);
}
nlinks = Inode.st_nlink;
/*
* Get file owner's name string for HDR3.
*/
if (getpw(Inode.st_uid,Name)) {
PERROR "\n%s: %s %d%c\n", Progname, CANTFPW, Inode.st_uid, BELL);
strcpy(Name, " ");
}
/*
* Owner id field in HDR3 label is maximum of 10 characters
*/
for (j=0; j < 11 && Name[j] && Name[j] != ':'; j++)
Owner[j] = Name[j];
Owner[j] = NULL;
cp = ctime(&Inode.st_mtime);
if (cp[20] == '2' && cp [21] == '0')
crecent = '0';
else
crecent = ' ';
ltime = localtime(&Inode.st_mtime);
Blocks = 0L;
max = 0;
if (type == TEXT || type == SYMLNK && Nosym) {
/*
* If we find a really long line in the text,
* we should output it as a spanned/segmented
* record rather variable length record.
*
* Find length of longest line.
*/
Format = 0;
ch = TRUE;
while (ch != EOF) {
length = 0;
while ((ch = getc(fp)) != EOF && ch != '\n')
length++;
if (length > max)
max = length;
}/*E while (ch) */
fclose(fp);
if ((fp = fopen(reallong, "r")) == NULL) {
PERROR "\n%s: %s %s%c\n\n", Progname, CANTOPEN, reallong, BELL);
exit(FAIL);
}
if (max + 5 > Reclength && Reclength != MAXRECSIZE) {
PERROR "\n%s: %s %s%c\n\n", Progname, RECLTS, longname, BELL);
return;
}/*T if (max + 5 > Reclength ... */
else
if (max + 5 > Reclength || max + 5 > Blocksize) {
Format = SEGMENT;
Maxrec = max;
}/*T if (max + 5 ... */
else {
Format = VARIABLE;
Maxrec = max + 4;
}/*F if (max + 5 ... */
}/*E if (type == TEXT || type == SYMLNK && Nosym) */
fseek(fp, 0L, 0);
/****\
* Write HDR1 on volume..
****/
sprintf(Dummy,
"HDR1%-17.17s%-6.6s%04d%04d%04d%02d%c%02d%03d %02d%03d %06d%-13.13s%7.7s",
interchange, Volid, Fsecno, Fseqno,
(version-1) / 100 + 1, (version-1) % 100,
crecent, ltime->tm_year, ltime->tm_yday+1, 99, 366, 0,
type == FUF ? "DECFILE11A" : IMPID, Spaces);
if (Ansiv != '4')
filter_to_a(Dummy,IGNORE_ERRORS);
if (write(fileno(Magtfp), Dummy, BUFSIZE) != BUFSIZE) {
PERROR "\n%s: %s %s\n", Progname, ERRWRF, longname);
perror(Magtdev);
ceot();
}
if (type == FUF)
max = MAXREC4;
/****\
* Write HDR2 on volume..
****/
/*
* Directories always have a link count > 1 ...
* So, we don't bother to enter them in the linked files list.
* Also, can't hard link directories ...
*/
if (type != DIRECT && nlinks > 1 && !Nosym) {
hlink = 1;
/* If this file is linked to another,
* find the ANSI file sequence number that it
* is linked to.
*/
for (lp = A_head; lp; lp = lp->a_next)
if (lp->a_inum == Inode.st_ino && lp->a_dev == Inode.st_dev) {
found++;
break;
}
/* If we found the file that this file is linked to in our list,
* get it's file sequence number and set linkflag.
*/
if (found) {
lnkseq = lp->a_fseqno;
linkflag = YES;
}
else {
/* Else, enter info into a node for a possible reference
*/
lp = (struct ALINKBUF *) malloc(sizeof(*lp));
if (lp == NULL) {
PERROR "\n%s: %s%c%c\n\n", Progname, NOMEM, BELL, BELL);
exit(FAIL);
}/*T if lp == NULL */
else {
lp->a_next = A_head;
A_head = lp;
lp->a_inum = Inode.st_ino;
lp->a_dev = Inode.st_dev;
lp->a_fsecno = Fsecno;
lp->a_fseqno = Fseqno;
lp->a_pathname = (char *) malloc(strlen(longname) + 1);
if (lp == NULL) {
PERROR "\n%s: %s%c%c\n\n", Progname, NOMEM, BELL, BELL);
exit(FAIL);
}/*T if lp == NULL */
else {
strcpy(lp->a_pathname, longname);
}
lnkseq = 0;
}/*F if lp == NULL */
}/*F if (found) */
}/*E if (type != DIRECT && nlinks > 1) */
/*
* Perform any special functions required for symbolic links
*/
if (type == SYMLNK) {
otype = type;
type = TEXT;
if (!Nosym) {
/*
* Read the link to find out what
* it points to.
*/
dummy[0] = 0;
if ((ch = readlink(reallong, dummy, MAXNAMLEN)) < 0) {
PERROR "\n%s: %s %s\n",Progname, CANTRSL, reallong);
perror(Progname);
}
else
dummy[ch] = '\0';
linkflag = YES;
/*
* For Symbolic links, the file data is the full
* path name of the file pointed to by the
* symbolic link.
*/
strcpy(Inbuf,dummy);
max = strlen(Inbuf);
Inbuf[max] = '\n';
Inbuf[max+1] = '\0';
if (max + 5 > Reclength || max + 5 > Blocksize || max + 5 > MAXRECSIZE) {
Format = SEGMENT;
Maxrec = max;
}
else {
Format = VARIABLE;
Maxrec = max + 4;
}
}/*T if (!Nosym) */
}/*T if (type == SYMLNK) */
/******
*
* Calculate the number of HDR / EOF labels that will be needed
* to contain the full path/file name.
*
*/
length = (strlen(longname)) -1;
Lhdrl = 3;
Leofl = 0;
length -= 36;
/*
* Determine the number of HDR labels needed.
*/
while ((length > 0) && (Lhdrl !=9)) {
length -= 76;
Lhdrl++;
}
/*
* Determine the number of EOF labels needed.
*/
if (length > 0) {
Leofl = 2;
while ((length >0) && (Leofl != 9)) {
length -= 76;
Leofl++;
}
}
/* Set the format of the record if it is not a TEXT file. If it is,
* it has already been set.
*/
if (type == FUF || type == COUNTED)
Format = VARIABLE;
else
if (type != TEXT)
Format = FIXED;
if (type == FUF)
Maxrec = max + 4;
else
if (type != TEXT)
Maxrec = Reclength;
sprintf(Dummy,
"HDR2%c%05d%05d%06o%04d%04d%04d%3.3s%c%010ld%1.1d%1.1d%1.1d00%-28.28s",
Format, Blocksize, Maxrec,
Inode.st_mode & 0177777,
Inode.st_uid, Inode.st_gid,
lnkseq, Tftypes,
(type == BINARY) ? 'M' : Carriage,
(type == SYMLNK && !Nosym) ? max : Inode.st_size,
Lhdrl, Leofl, hlink, Spaces);
/*
* Save ANSI file type for verbose messgae use.
*/
ansift = Dummy[4];
if (write(fileno(Magtfp), Dummy, BUFSIZE) != BUFSIZE) {
PERROR "\n%s: %s %s\n", Progname, ERRWRF, longname);
perror(Magtdev);
ceot();
}
if (!Noheader3) {
/****\
* Write HDR3 on volume..
****/
sprintf(Dummy, "HDR3%010ld%-10.10s%-20.20s%-36.36s",
Inode.st_mtime,
Owner,
Hostname,
longname);
if (Ansiv != '4')
filter_to_a(Dummy,IGNORE_ERRORS);
if (write(fileno(Magtfp), Dummy, BUFSIZE) != BUFSIZE) {
PERROR "\n%s: %s %s\n", Progname, ERRWRF, longname);
perror(Magtdev);
ceot();
}
/****\
* Write additional file header labels (HDR4 - HDRn)
* to contain the remaining portions of very long
* path/file names.
****/
if (Lhdrl > 3) {
int i;
for (i=4,j=36; i<=Lhdrl; i++,j += 76) {
sprintf(Dummy, "HDR%1.1d%-76.76s", i,&longname[j]);
if (Ansiv != '4')
filter_to_a(Dummy,IGNORE_ERRORS);
if (write(fileno(Magtfp), Dummy, BUFSIZE) != BUFSIZE) {
PERROR "\n%s: %s %s\n", Progname, ERRWRF, longname);
perror(Magtdev);
ceot();
}
}
}
}/* T !Noheader3 */
/****\
* Write an end-of-file mark on tape that separates
* the file header labels from the data ....
****/
weof();
/****\
* Write the actual file data on the output volume.
****/
if ((Blocks = append(longname, fp, type, otype, max, Inbuf)) < 0L)
if (Blocks == (long)(-1)) {
PERROR "\n%s: %s %s%c\n\n", Progname, ERRWRF, longname, BELL);
ceot();
}
if (fclose(fp) < 0) {
PERROR "\n%s: %s %s\n", Progname, CANTCLS, longname);
perror(longname);
exit(FAIL);
}
/* If outputting symlnk, change type from TEST back to SYMLNK
*/
if (otype)
type = otype;
/****\
* Write an end-of-file mark on tape
* Separates the data from the file trailer labels...
****/
weof();
/****\
* Write EOF1 to output volume..
****/
sprintf(Dummy,
"EOF1%-17.17s%-6.6s%04d%04d%04d%02d%c%02d%03d %02d%03d %06ld%-13.13s%7.7s",
interchange, Volid, Fsecno, Fseqno,
(version-1) / 100 + 1, (version-1) % 100,
crecent, ltime->tm_year, ltime->tm_yday+1, 99, 366, Blocks,
type == FUF ? "DECFILE11A" : IMPID, Spaces);
if (Ansiv != '4')
filter_to_a(Dummy,IGNORE_ERRORS);
if (write(fileno(Magtfp), Dummy, BUFSIZE) != BUFSIZE) {
PERROR "\n%s: %s %s\n", Progname, ERRWRF, longname);
perror(Magtdev);
ceot();
}
/****\
* Write EOF2 to output volume..
****/
sprintf(Dummy,
"EOF2%c%05d%05d%06o%04d%04d%04d%3.3s%c%010ld%1.1d%1.1d%1.1d00%-28.28s",
Format, Blocksize, Maxrec,
Inode.st_mode & 0177777,
Inode.st_uid, Inode.st_gid,
lnkseq, Tftypes,
(type == BINARY) ? 'M' : Carriage,
(type == SYMLNK && !Nosym) ? max : Inode.st_size,
Lhdrl, Leofl, hlink, Spaces);
if (write(fileno(Magtfp), Dummy, BUFSIZE) != BUFSIZE) {
PERROR "\n%s: %s %s\n", Progname, ERRWRF, longname);
perror(Magtdev);
ceot();
}
if (!Noheader3) {
/*
* Write EOF3 - EOFn to output volume.
*
* EOF3 thru EOF'n' contain the remaining characters of a
* very long path/file name. If no characters need be stored
* in the EOF labels for a path/file name, at a minimum we
* output the same number of trailer lables as header labels
* in order to keep things tidy.
*/
if (Leofl) {
int i;
for (i=3,j=492; i<= Leofl; i++,j += 76) {
sprintf(Dummy, "EOF%1.1d%-76.76s", i,&longname[j]);
if (Ansiv != '4')
filter_to_a(Dummy,IGNORE_ERRORS);
if (write(fileno(Magtfp), Dummy, BUFSIZE) != BUFSIZE) {
PERROR "\n%s: %s %s\n", Progname, ERRWRF, longname);
perror(Magtdev);
ceot();
}
}
}/* if (Leofl) */
/*
* If Leofl = 0, no EOF lables are required to hold path/file
* name characters. Therefore, we output as many space filled EOFx
* lables as we need to in order to have the same number of EOF
* trailer labesl as HDR header labels to keep ANSI happy. If some
* number of EOF labels were required for path/file characters,
* they will have been output by the code above. If this does not
* result in the same number of EOF labels as HDR labels, write out
* the required number of EOF labels.
*/
if (Leofl < Lhdrl) {
/* \----> By accident, all HDR and all EOF labels may
* have been needed, and have been output, to
* contain path/file name characters. Therefor,
* the following code has no function. The case
* referred to as an accident is one where the
* path/file name is in the order of 949 to
* 1024 characters in length.
*/
if (!Leofl) /* If no EOF labels were required for path/file
* characters, begin with EOF3, and continue
* with blank EOF lables until we output as many
* EOF labesl as HDR labels.
*/
j = 3;
else
j = Leofl + 1; /* If padding out EOF labels to the
* same number of HDR labels and
* some EOF labels have been used for
* path/file name characters, start with
* the next sequential label number.
*/
while (j <= Lhdrl) {
sprintf(Dummy, "EOF%1.1d%-76.76s", j++,Spaces);
if (write(fileno(Magtfp), Dummy, BUFSIZE) != BUFSIZE) {
PERROR "\n%s: %s %s\n", Progname, ERRWRF, longname);
perror(Magtdev);
ceot();
}
}
}/* if (Leofl < Lhdrl)*/
}/* T !Noheader3 */
/*****\
* Write tape mark to separate us from next label group
* if we are going to output more files.
*****/
weof();
term_string(shortname,DELNL,TRUNCATE);
if (Verbose) {
printf("c<%s>%c %s%s",Tftypes, ansift, pathname, shortname);
#if 0
/* If we decide we care about tape blocks, put
* this logic back in. -else- Just announce the
* byte count.
*/
if (Blocks == 1L)
printf(",\t001%s ", TAPEB);
else
printf(",\t%03ld%s ", Blocks, TAPEBS);
#endif
if (Inode.st_size == 1L || (type == SYMLNK && !Nosym && max == 1))
printf(",\t0001%s ", BYTE);
else
if (type == SYMLNK && !Nosym)
printf(",\t%04d%s ", max, BYTES);
else
printf(",\t%04ld%s ", Inode.st_size, BYTES);
if (linkflag || type == SYMLNK) {
if (strlen(longname) > 19 || strlen(dummy) > 19)
printf("\n ");
if (type == SYMLNK)
printf("%s %s", SLINKTO, dummy);
else
printf("%s %s", HLINKTO, lp->a_pathname);
}
printf("\n");
}/*T if Verbose */
else
printf("c %s%s\n", pathname, shortname);
/* Increment the ANSI file sequence number for the next
* file to go out (if any).
*/
Fseqno++;
}/*E process() */
/**/
/*
*
* Function:
*
* putfile
*
* Function Description:
*
* This function determines the Ultrix disk file type
* (if required) and calls function "process" to output
* a file to the volume.
*
* Arguments:
*
* char *longname Full pathname_+_filename
* char *shortname File name only
*--
* Accesses Global variable:
*--
* int Dfiletype Default/designated Ultrix
* disk file type.
*
* Return values:
*
* none
*
* Side Effects:
*
* If the user has specified a filename that is in fact
* a directory -AND- for that argument the user has
* specified a default/designated Ultrix disk file
* type, then ALL files under that heirarchy will take
* on the attributes appropriate for the given default
* file type. The Dfiletype variable should only be
* applied to singular file names, applying it to
* a directory may or may not be what the user intends.
*
* If errors occur during the file type determination
* process, the function outputs a message to "stderr"
* and exits to system control.
*/
DIR *dirfile;
struct stat inodes;
char dirent[14+1];
int tfiletype; /* Result from Filetype */
struct direct *dirp;
char sbuf[MAXPATHLEN+1];
char fullpath[MAXPATHLEN+1]; /* Full pathname */
char dummy4[MAXPATHLEN+1]; /* The current working file/directory */
/* #define DEBUG /* turn on debug output */
putfile(longname, shortname, iflag, workdir)
char *longname; /* Pathname_+_filename */
char *shortname; /* File name only */
int iflag; /* If iflag = 1, then stdin */
char *workdir; /* Working directory */
{
/*
* +--> Local Variables
*/
long p; /* WAS AN int, MUST BE long FOR PDP */
int savindex; /* index into sbuf; the place to terminate on return */
/*------*\
Code
\*------*/
/*
* We build dummy4[] for the fstat call, instead of adding the file
* name to the end of fullpath. This leaves the last component of
* fullpath always being a directory, which later turns into sbuf.
* Then, new directories are added to the end of fullpath, just after
* we have descended the new directory. NOTE: in this manner, fullpath
* always points to the current directory! fullpath components are
* popped off just before we chdir up to the new level. Search for
* keyword "HERE".
*/
#ifdef DEBUG
printf("\n\nIn putfile:\n");
printf(" longname: %s\n", longname);
printf(" shortname: %s\n", shortname);
printf(" workdir: %s\n\n", workdir);
#endif
if (longname[0] == '/' || !(strcmp(shortname, "/"))) {
if (strlen(longname) == 0)
strcpy(dummy4, shortname);
else
strcpy(dummy4, longname);
}
else {
strcpy(dummy4, workdir);
strcat(dummy4, "/");
strcat(dummy4, longname);
}
#ifdef DEBUG
printf("fullpath is Currently: %s\n",
strlen(fullpath) > 0 ? fullpath : "Unknown");
printf("about to stat(%s)\n",dummy4);
#endif
/* Do the correct "stat" call
*/
i = stat(dummy4, &inodes);
j = lstat(dummy4, &Inode);
if (i < 0 || j < 0)
if (skip && iflag == 1)
return(EOF);
else {
if ((Inode.st_mode & S_IFMT) == S_IFLNK && i < 0)
PERROR "\n%s: %s %s%c\n", Progname, CANTSTS, dummy4, BELL);
else
PERROR "\n%s: %s %s%c\n", Progname, CANTSTW, dummy4, BELL);
perror(Progname);
return(EOF);
}
if (Nosym)
Inode = inodes;
/*
* Go put any required directory entries on the output volume.
*/
if (Ansiv != '3' && !Noheader3)
if ((i = putdir(longname, shortname, workdir)) == EOF)
return;
/* Check if current file (dummy4) is a directory - start recursive volume creation
*/
tfiletype = Filetype(dummy4, Progname);
if ((Inode.st_mode & S_IFMT) == S_IFDIR) {
if (chdir(dummy4) < 0) {
/* Check if error is permission denied
*/
if (errno != EACCES) {
PERROR "\n%s: %s %s%c\n", Progname, CANTCHD, dummy4, BELL);
perror(Progname);
exit(FAIL);
}
else {
PERROR "\n%s: %s %s%c\n", Progname, CANTCHW, dummy4, BELL);
perror(Progname);
return;
}
}
#ifdef DEBUG
printf("just chdir'd down to %s\n",dummy4);
#endif
/*
* HERE, we update fullpath to reflect where we are currently,
* so we can later get back by popping the last component,
* search for keyword "HERE".
*/
strcpy(fullpath, dummy4);
#ifdef DEBUG
printf("new fullpath is: %s\n", fullpath);
#endif
/* Read through current directory
*/
if (!( dirfile = opendir( "."))) {
PERROR "\n%s: %s %s%c\n\n", Progname, CANTOD, longname, BELL);
perror(Progname);
exit(FAIL);
}
while (dirp = readdir(dirfile)) {
/* Make sure we don't read empty slots in the
* directory ...
*/
if (!dirp->d_ino)
continue;
/* Likewise, don't try to process the current
* and previous directory entries which are
* present in all directories.
*/
if (!strcmp(".", dirp->d_name) ||
!strcmp("..", dirp->d_name))
continue;
/* Get new contents of sbuf
*/
strcpy(sbuf, longname);
savindex = strlen(sbuf);
strcat(sbuf, "/");
strcat(sbuf, dirp->d_name);
/*
* RECURSIVE UPON THINESELF !
*
* But, first save a pointer to where we are in the
* current directory and close it, lest we have too
* many open files dangling about the premises.
*/
p = telldir(dirfile);
/* Save the directory name because as soon as we
* issue the closedir we will lose the "dirp"
* pointer !
*/
strcpy(dirent, dirp->d_name);
closedir(dirfile);
/* RECURSE !*@#$!
*/
/**************
printf("push sbuf = %s, dirent = %s, p = %ld\n", sbuf, dirent, p);
printf("push fullpath = %s\n", fullpath);
***************/
putfile(sbuf, dirent, iflag, workdir);
sbuf[savindex] = '\0';
/* When we return, re-open and position the
* current directory.
*/
dirfile = opendir(".");
seekdir(dirfile, p);
#ifdef DEBUG
printf("Continuing with opendir...");
#endif
}/*E while dirp ..*/
#ifdef DEBUG
printf("DONE with opendir...\n\n");
#endif
closedir(dirfile);
/*
* HERE: pop 1 off end of fullpath to get back up 1 level,
* check if going up to /
*/
if ((strlen(fullpath) > 1) && (cp = rindex(fullpath, '/'))) {
if (cp == fullpath)
cp++;
*cp = '\0';
}
#ifdef DEBUG
printf("\nNew working directory will be: %s\n\n", fullpath);
#endif
if (chdir(fullpath) < 0) {
PERROR "\n%s: %s %s%c\n", Progname, CANTCHD, fullpath, BELL);
exit(FAIL);
}
#ifdef DEBUG
printf("just chdir'd back up to %s\n", fullpath);
#endif
return;
}/*E if ((Inode.st_mode & S_IFMT) == S_IFDIR) */
if ((Inode.st_mode & S_IFMT) == S_IFCHR) {
special:
PERROR "\n%s: %s %s%c", Progname, SPCLDF, longname, BELL);
return;
}
if ((Inode.st_mode & S_IFMT) == S_IFBLK)
goto special;
if ((Inode.st_mode & S_IFMT) != S_IFDIR) {
/* Has the user given us a default Ultrix disk file
* type for this file ? If yes, use it and bypass our
* file determination logic.
*/
if (Dfiletype) {
/*
* Go put a file on the output volume,
* making sure user is aware s/he is overriding our
* disk file type determination logic.
*/
PROMPT "\n%s: %s %s%c\n", Progname, USEDF, shortname, BELL);
process(dummy4, longname, shortname, Dfiletype);
}/*T if Dfiletype */
else {
/* Go put a file on the output volume.
*/
if (tfiletype != EOF) {
process(dummy4, longname, shortname, tfiletype);
}
}/*F if Dfiletype */
return;
}/* if ((Inode.st_mode & S_IFMT) != S_IFDIR) */
else
return;
}/*E putfile() */
/**\\**\\**\\**\\**\\** EOM putfile.c **\\**\\**\\**\\**\\*/
/**\\**\\**\\**\\**\\** EOM putfile.c **\\**\\**\\**\\**\\*/