Ultrix-3.1/src/cmd/ltf/xtractf.c

Compare this file to the similar file:
Show the results in this format:


/**********************************************************************
 *   Copyright (c) Digital Equipment Corporation 1984, 1985, 1986.    *
 *   All Rights Reserved. 					      *
 *   Reference "/usr/src/COPYRIGHT" for applicable restrictions.      *
 **********************************************************************/

#ifndef lint
static	char	*sccsid = "@(#)xtractf.c	3.0	(ULTRIX)	4/21/86";
#endif	lint

/**/
/*
 *
 *	File name:
 *
 *		xtractf.c
 *
 *	Source file description:
 *
 *		Contains the functions that read data from the
 *		input volume and places it in the resultant
 *		output disk file.
 *
 *	Functions:
 *
 *		checkdir()	Check to see if a directory exists
 *				& create missing directories
 *
 *		fufcnv()	Converts a Fortran Unformatted File
 *				(from input volume) to correct Ultrix
 *				disk file format
 *
 *		getlen()	Get the length of the next variable-
 *				length record from the input volume
 *
 *		xtractf()	Top  level logic to extract files
 *				from the input volume
 *
 *	Usage:
 *
 *		n/a
 *
 *	Compile:
 *
 *	    cc -O -c xtractf.c		<- For Ultrix-32/32m
 *
 *	    cc CFLAGS=-DU11-O xtractf.c	<- For Ultrix-11
 *
 *
 *	Modification history:
 *	~~~~~~~~~~~~~~~~~~~~
 *
 *	revision			comments
 *	--------	-----------------------------------------------
 *	 01.0		25-April-85	Ray Glaser
 * 			Create original version
 *
 *	 01.1		4-Sep-85	Suzanne Logcher
 *			Correct use of Noheader3 in xtractf()
 *
 *	 01.2		4-Oct-85	Suzanne Logcher
 *			Add logic to extract a segmented file
 */

/*
 * +--> Include File(s)
 */

#include "ltfdefs.h"

/**/
/*
 *
 * Function:
 *
 *	checkdir
 *
 * Function Description:
 *
 *	This function checks to see if a directory exists.
 *	It creates those directories that are not found to exist.	
 *
 * Arguments:
 *
 *	char	*path	Pointer to the string containing the
 *			directory path structure to be checked.
 *
 * Return values:
 *
 *	TRUE	if the directory existed
 *	FALSE	if the directory had to be created
 *
 * Side Effects:
 *
 *	This functions "forks" a child process to create a
 *	needed directory.
 *
 *	If the function fails to create the required directory,
 *	an error message is output to  stderr  and the function
 *	exits to system control.
 *	
 */
checkdir(path)
	char	*path;
{
/*
 * +--> Local variables
 */

char	dummy[MAXPATHLEN+1];
char	dummy2[MAXPATHLEN+1];
int	k;

/*------*\
   Code
\*------*/

/* Remove any trailing slash from directory name, else
 * the mkdir call will fail.  dummy is used to preserve the
 * orginal form of path given to us.
 */
strcpy(dummy2,path);
j = 0;
for (cp = dummy2; *cp; cp++)
    if (*cp == '/')
	j++;
i = strlen(dummy2);
if (dummy2[i-1] == '/')
    dummy2[i-1] = 0;
for (i = 1; i <= j; i++) {
    strcpy(dummy, dummy2);
    cp = dummy;
    for (k = 1; *cp && k <= i; cp++)
	if (*cp == '/')
	    k++; 
    if (*(--cp) == '/')
	*cp = 0;

    if (stat(dummy, &Inode) < 0) {
	register int pid, rp;

	if (!(pid = fork())) {
		execl("/bin/mkdir", "mkdir", dummy, 0);
		execl("/usr/bin/mkdir", "mkdir", dummy, 0);

		/* If the execl's ever return to here, ERROR */
		PERROR "\n%s: %s %s  %c\n", Progname, CANTMKD, dummy,BELL);
		perror(Progname);
		exit(FAIL);
	}/*E if pid = fork ..*/

	while ((rp = wait(&i)) >= 0 && rp != pid)
	    	;
	return(TRUE);

    }/*E if stat dummy &Inode ..*/
}/*E for */
return(FALSE);

}/*E checkdir() */
/**/
/*
 *
 * Function:
 *
 *	fufcnv
 *
 * Function Description:
 *
 *	Converts a Fortran Unformatted File (from input volume)
 *	to the correct form for an Ultrix disk file.
 *
 * Arguments:
 *
 *	int	count;
 *	FILE	*fp;
 *	char	*p;
 *
 *
 * Return values:
 *
 *
 * Side Effects:
 *
 *	
 */

fufcnv(name, p, count, fp)
	char	*name;		/* filename used for error */
	char	*p;
	int	count;
	FILE	*fp;
{
/*
 * +--> Local Variables
 */
int	bincnt = 0;

/*------*\
   Code
\*------*/

i = *p++;
j = *p++;

if (j != 0)
	PERROR "\n%s: %s %d%c\n", Progname, SCNDCB, j, BELL);

count -= 2;

switch(i) {
	case ALL:
		bincnt = count;
		if (write(fileno(fp), &bincnt, sizeof(bincnt)) != sizeof(bincnt)) {
		    PERROR "\n:%s %s %s\n", Progname, ERRWRF, name);
		    exit(FAIL);
		}
		if (write(fileno(fp), p, bincnt) != bincnt) {
		    PERROR "\n:%s %s %s\n", Progname, ERRWRF, name);
		    exit(FAIL);
		}
		if (write(fileno(fp), &bincnt, sizeof(bincnt)) != sizeof(bincnt)) {
		    PERROR "\n:%s %s %s\n", Progname, ERRWRF, name);
		    exit(FAIL);
		}
		break;

	case FIRST:
		bincnt = 0;
		if (write(fileno(fp), Spaces, sizeof(bincnt)) != sizeof(bincnt)) {
		    PERROR "\n:%s %s %s\n", Progname, ERRWRF, name);
		    exit(FAIL);
		}
		if (write(fileno(fp), p, count) != count) {
		    PERROR "\n:%s %s %s\n", Progname, ERRWRF, name);
		    exit(FAIL);
		}
		bincnt += count;
		break;

	case MIDDLE:
		if (write(fileno(fp), p, count) != count) {
		    PERROR "\n:%s %s %s\n", Progname, ERRWRF, name);
		    exit(FAIL);
		}
		bincnt += count;
		break;

	case LAST:
		if (write(fileno(fp), p, count) != count) {
		    PERROR "\n:%s %s %s\n", Progname, ERRWRF, name);
		    exit(FAIL);
		}
		bincnt += count;
		fseek(fp, (long)(-1 * (bincnt+sizeof(bincnt))), 1);
		if (write(fileno(fp), &bincnt, sizeof(bincnt)) != sizeof(bincnt)) {
		    PERROR "\n:%s %s %s\n", Progname, ERRWRF, name);
		    exit(FAIL);
		}
		fseek(fp, (long)bincnt, 1);
		if (write(fileno(fp), &bincnt, sizeof(bincnt)) != sizeof(bincnt)) {
		    PERROR "\n:%s %s %s\n", Progname, ERRWRF, name);
		    exit(FAIL);
		}
		break;

	default:
		PERROR "\n%s: %s %d%c\n", Progname, FSTCB, i, BELL);
		break;
	}
return(1);

}/*E fufcnv() */
/**/
/*
 *
 * Function:
 *
 *	getlen
 *
 * Function Description:
 *
 *	Get and return the length of the next variable-length
 *	record from the input volume.
 *
 * Arguments:
 *
 *	char	*s	Pointer to the string containing ?_?
 *
 * Return values:
 *
 *	The integer length of the record is returned.
 *
 *	A zero length is a valid return value. It indicates
 *	an empty record.
 *
 *	If *s points to the padding character (^),
 *	-1 is returned to signify the end of available data
 *	in the current block.
 *
 *
 * Side Effects:
 *
 *	none	
 */

getlen(s)
	char	*s;
{

/*------*\
   Code
\*------*/

if (*s == PAD)
	return(-1);	/* Record padding character seen, signal
			 * end of data to the caller.
			 */
/* Increment pointer if record is segmented
*/
if (L_recformat == SEGMENT)
    s++;

/* Default is an empty record
 */
j = 0;

for (i=0; i < 4; i++)
	j = 10 * j + (*s++ - '0');
/* If VARIABLE, -4.  If SEGMENT, -5
*/
if (L_recformat == VARIABLE)
    return(j-4);
return(j-5);

}/*E getlen() */
/**/
/*
 *
 * Function:
 *
 *	xtractf
 *
 * Function Description:
 *
 *	Extract a given file from the input Volume.
 *
 * Arguments:
 *
 *	char	*path;		 Pathname_+_filename from input vol
 *	char	*s;		 User entered path/file name
 *	long	charcnt;	 Character count (if applicable) 
 *	char	*name;		 Alternate name given to disk file if
 *				 different from that on the input
 *				 volume (user driven). Used when -W
 *				 switch is given and the input volume
 *				 file is found to exist on disk. 
 *
 * Return values:
 *
 *	1. The character count of the extracted file.
 *	2. -or-   -1  if an error was encountered that can
 *		  be recovered from without undue hardship.
 *
 *		 (xtractf must return -1 upon error because a
 *		  zero-length file can have a valid returned
 *		  length of 0 bytes)
 *
 * Side Effects:
 *
 *	If the function cannot write the file on the output
 *	disk for whatever ... An error message is output to
 *	stderr and the function exits to system control.
 *
 *	If the user has requested that warnings be issued when
 *	a file being extracted is already on disk (-W qualifier)
 *	the logic will pause and give the user the option(s) of:
 *
 *		1. Cancel the extraction of the file from 
 *		   the input volume.
 *
 *		2. Extract the file and overwrite the existing
 *		   copy on the output medium.
 *
 *		3. Extract the file, but give it a new name as
 *		   supplied by the user.
 */
 
long xtractf(path, s, charcnt, name)
	char	*path;		/* pathname_+_filename from input vol */
	char	*s;		/* user entered path/file name */
	long	charcnt;	/* character count (if applicable) */
	char	*name;		/* alternate extracted filename
				 * (if different from user entered
				 *  name) */
{
/*
 * +--> Local Variables
 */

int	count;
int	done = FALSE;		/* Boolean to make sure new file names
				 * get "stat" -ed too */
char	dummy2[MAXPATHLEN+1];	/* Temporary variable */
char	Inbuf[MAXBLKSIZE+1];	/* File writing buffer */
int	nbytes;
long	num = 0L;
char	*p;
char	*q;
FILE	*xfp;

/*------*\
   Code
\*------*/

/* If user didn't specify path/file names, use the
 * name from the input volume as default.
 */
if (!*s) {
	strcpy(dummy2,path);
#if 0
	sprintf(dummy2, "%s%s", path, L_filename);
	term_string(dummy2,DELNL,TRUNCATE);
#endif
}
else
	strcpy(dummy2, s);

if (Wildc) {
	/*
	 * User entered a wild card name string that matched
	 * the current file on the input volume.
	 * Use the actual name found on the
	 * input volume.
	 */
#if 0
	term_string(path,DELNL,TRUNCATE);
#endif
	strcpy(name,path);
	strcpy(dummy2,path);
}
if (!strcmp(Tftypes,"dir")) {
    Dircre = checkdir(dummy2);
    fsf(1);
    return((long)(0));
}/*T if (!strcmp(Tftypes,"dir")) */ 

while (stat(dummy2, &Inode) >= 0 && !done) {
    if (Warning) {
	PROMPT "\n%s: %s %s\n", Progname, EXISTS, dummy2);
	PROMPT "%s: %s %c", Progname, OVRWRT, BELL);

	gets(Labelbuf);
	PROMPT "\n");

	Labelbuf[0] = Labelbuf[0] == 'Y' ? 'y' : Labelbuf[0];

	if (Labelbuf[0] != 'y') {
		/*
		 * User does not want to overwrite existing file.
		 */
		char	dummy[MAXPATHLEN+1];

		PROMPT "%s: %s ", Progname, ALTERN);
		gets(dummy);
		PERROR "\n");
		if (!dummy[0]) {
			/*
			 * User wants to skip extract of this file.
			 */
			fsf(2);
			return((long)(-1));
		}/*T if !dummy[0] */
		else {
			if (strlen(dummy) > MAXPATHLEN) {
				PERROR "\n%s: %s %s%c", Progname,
				    FNTL, dummy, BELL);
				fsf(2);
				return((long)(-1));

			}/*T if strlen dummy > MAXPATHLEN */
			else {
#if 0
				term_string(dummy,DELNL,TRUNCATE);
#endif
				strcpy(dummy2, dummy);
				strcpy(name, dummy2);
				Wildc = FALSE;

			}/*F if strlen dummy > MAXPATHLEN */
		}/*F if !dummy[0] */
	}/*T if Labelbuf[0] != 'y') */
	else
	    done = TRUE;
    }/*E if Warning */
    else
	done = TRUE;
}/*while stat dummy2 ..*/


/* File being extracted ...
 */
if (!(xfp = fopen(dummy2, "w")))
    if ((Dircre = checkdir(dummy2)) == FALSE) {
	PERROR "\n%s: %s %s %c\n", Progname,
	  CANTCRE, dummy2, BELL);
	perror(Progname);
	fsf(2);
	return((long)(-1));
    }
    else {
	if (!(xfp = fopen(dummy2, "w"))) {
	    PERROR "\n%s: %s %s %c\n", Progname, CANTCRE, dummy2, BELL);
	    perror(Progname);
	    fsf(2);
	    return((long)(-1));
	}/*if !xfp */
    }
while ((nbytes = read(fileno(Magtfp), p=Inbuf, L_blklen)) > 0 ) {
	if (!Tape) {
		if (tape_mark(Inbuf))
			goto eofdata;
	}/*E if !Tape */
	
	if (L_recformat == FIXED || L_recformat == UFORMAT || (L_recformat != VARIABLE && L_recformat != SEGMENT)) {
		/*
		 * Test if charcnt == 0L
		 * foreign tapes won't have a character count !
		 */
		if (charcnt == 0L) {

			cp = p;
			cp += nbytes;

			while (*--cp == PAD)
			    ;
			cp++;
			num += (long)(cp - p);

			if (write(fileno(xfp), p, cp - p) != (cp - p)) {
			    PERROR "\n%s: %s %s\n", Progname, ERRWRF, dummy2);
			    exit(FAIL);
			}/*E if write < 0 */

		}/*T if charcnt == 0L */

		else if (charcnt >= (long)nbytes) {
			if (write(fileno(xfp), Inbuf, nbytes) != nbytes) {
			    PERROR "\n%s: %s %s\n", Progname, ERRWRF, dummy2);
			    exit(FAIL);

			}/* if write < 0 */

			charcnt -= (long)nbytes;
			num += (long)nbytes;

		}/*T if charcnt >= nbytes */

		else if (charcnt > 0L) {
		        if (write(fileno(xfp), Inbuf,(int)charcnt) != (int)charcnt){
			    PERROR "\n%s: %s %s\n", Progname, ERRWRF, dummy2);
			    exit(FAIL);

			}/* if write < 0 */

			num += charcnt;

			/* Set charcnt equal to -1 */

			charcnt = (long)(-1);
	
		}/* if charcnt > 0L */
	
	}/*T if (L_recformat == FIXED) */
/**/
/*
 *	Volume file was not FIXED LENGTH  record  format.
 */
	else {
	    j = 0;
	    while (p < &Inbuf[nbytes] && (count = getlen(p)) >= 0) {

		if (L_recformat == VARIABLE) {
			p += 4;

			if (!count) {
				putc('\n', xfp);
				fflush(xfp);
				num++;
				continue;

			}/*E if !count */
		}/*T if L_recformat == VARIABLE */

		else if (L_recformat == FUF) {
			p += 4;

			if (! fufcnv(dummy2, p, count, xfp)) {
			    PERROR "\n%s: %s\n", Progname, FUFTL);
			    PERROR "%s: %s -> %s%c\n", Progname,
				NOTEX, dummy2, BELL);
			    fsf(2);
			    return((long)(-1));

			}/*E if ! fufcnv ..*/

			p += count;
			continue;

		}/*T if L_recformat == FUF */
		else
		    if (L_recformat == SEGMENT) {
			q = p;
			p += 5;
			if (write(fileno(xfp), p, count) != count) {
			    PERROR "\n%s: %s %s\n", Progname, ERRWRF, dummy2);
			    exit(FAIL);
			}/*E if write < 0 */
			if (*q == '0' || *q == '3') {
			    putc('\n', xfp);
			    fflush(xfp);
			    num++;
			}/*T if (*q == '0' || *q == '3') */ 
			p += count;
			num += (long)count;
			continue;
		    }/*T if L_recformat == SEGMENT */
		else /* L_recformat == DD */
			count += 4;

		if (write(fileno(xfp), p, count) != count) {
		    PERROR "\n%s: %s %s\n", Progname, ERRWRF, dummy2);
		    exit(FAIL);
		}/*E if write < 0 */

		p += count;
		num += (long)count;

/* ?_?
 * ?_?	Checking for VARIABLE type   AGAIN ???    ?_?
 */
		if (L_recformat == VARIABLE) {
			putc('\n', xfp);
			fflush(xfp);
			num++;

		}/*E if L_recformat == VARIABLE */
	    }/*E while p < &Inbuf[nbytes]  .. */
	}/*F if (L_recformat == FIXED) */
}/*E while ((nbytes = read(fileno(Magtfp), p=Inbuf, L_blklen))) */
if (nbytes < 0) {
    PERROR "\n%s: %s %s\n", Progname, CANTRD, Magtdev);
    ceot();
}
/*
*/
eofdata:

fclose(xfp);

return(num);

}/*E xtractf() */

/**\\**\\**\\**\\**\\**  EOM  xtractf.c  **\\**\\**\\**\\**\\*/
/**\\**\\**\\**\\**\\**  EOM  xtractf.c  **\\**\\**\\**\\**\\*/