From:	ADVAX::"mcnc!CUNYVM.CUNY.EDU!MAILSERV%FRSIM51.BITNET" 22-FEB-1991 11:56:13.53
To:	ARISIA::EVERHART
CC:	
Subj:	MAEVA:[MAILSERV.PUB.VMSTAR]VMSTAR.SHARE_2;5

Received: by ADVAX.DECnet (utk-mail11 v1.5) ; Fri, 22 Feb 91 11:55:27 EST
Received:  from mcnc by ge-dab.GE.COM (5.61/GE-DAB 1.15) with UUCP
	id AA26084 for ; Fri, 22 Feb 91 11:48:04 -0500
Received: from CUNYVM.CUNY.EDU by mcnc.mcnc.org (5.59/MCNC/6-11-90)
	id AA17471; Fri, 22 Feb 91 10:14:36 -0500
	for ARISIA.DNET.ge.com!EVERHART
Message-Id: <9102221514.AA17471@mcnc.mcnc.org>
Received: from FRSIM51.BITNET by CUNYVM.CUNY.EDU (IBM VM SMTP R1.2.2MX) with BSMTP id 5156; Fri, 22 Feb 91 10:15:00 EST
Date: 22 FEB 91 16:09:55.40-WET
From: mcnc!CUNYVM.CUNY.EDU!MAILSERV%FRSIM51.BITNET
Subject: MAEVA:[MAILSERV.PUB.VMSTAR]VMSTAR.SHARE_2;5
To: ARISIA::EVERHART
 
-+-+-+-+-+-+-+-+ START OF PART 2 -+-+-+-+-+-+-+-+
X *`09- file list on create should now be space separated (removed difficult
X *`09  support of comma-separated list with context "a la BACKUP")
X *`09- global code simplification attempt, may have broken some
X *`09  odd case handling
X *`09- added some error handling in tarfile write operations
X *`09- probably millions of bugs introduced... sorry.
X */
X
X
X#include stdio
X#include time
X#include ssdef
X#include iodef
X#include descrip
X#include ctype
X#include strdef
X#include rms
X#include stsdef
X#include file
X#include stat
X#include types
X#include iodef
X#include string
X#include errno
X
X#define ERROR1 -1
X#define BUFFSIZE 512
X#define ISDIRE 1
X#define ISFILE 0
X#define NAMSIZE 100
X#define BLKSIZE 10240           /* Block size */
X#define DSIZE 512               /* Data block size */
X#define FIXED FAB$C_FIX
X
Xstruct tarhdr                   /* A tar header */
X`7B
X    char title`5BNAMSIZE`5D;
X    char protection`5B8`5D;
X    char uid`5B8`5D;                /* this is the user id */
X    char gid`5B8`5D;                /* this is the group id */
X    char count`5B12`5D;             /* was 11 in error */
X    char time`5B12`5D;              /* UNIX format date  */
X    char chksum`5B8`5D;             /* header checksum */
X    char linkcount;             /* hope this is right */
X    char linkname`5BNAMSIZE`5D;     /* Space for the name of the link */
X    char dummy`5B255`5D;            /* and the rest */
X`7D header;
X
Xchar buffer`5BDSIZE`5D;             /* buffer for a tarfile record */
X
X/* Function flags, options */
X
Xint extract,            /* x option, extract */
X    list,               /* t option, list tape contents */
X    verbose,            /* v option, report actions */
X    wait,               /* w option, prompt */
X    dot,                /* d option, suppress dots */
X    create,             /* c option, create */
X    binmode,            /* z option, binary mode */
X    foption;`09`09/* f option, specify tarfile */
X
X/* Miscellaneous globals, etc. */
X
Xchar tarfile`5BNAMSIZE`5D,  /* Tarfile name  */
X    pathname`5BNAMSIZE`5D,  /* File name as found on tape (UNIX) */
X    curdir`5BNAMSIZE`5D,    /* Current directory */
X    topdir`5BNAMSIZE`5D,    /* Top level directory of current default */
X    curdev`5BNAMSIZE`5D,    /* Current device */
X    new_directory`5BNAMSIZE`5D,     /* Directory of current file */
X    newfile`5BNAMSIZE`5D,   /* VMS format of file name */
X    outfile`5BNAMSIZE`5D,   /* Complete output file specification */
X    temp`5BNAMSIZE`5D,      /* Scratch */
X    creation`5BNAMSIZE`5D,  /* Date as extracted from the TAR file */
X    *ctime(),           /* System function */
X    linkname`5BNAMSIZE`5D,  /* Linked file name  */
X    searchname`5BNAMSIZE`5D, /* used in the NAM block for SYS$SEARCH */
X    dbuffer`5BDSIZE`5D,     /* input file buffer for create operation */
X    badchars`5B`5D = `7B",+`7E`60@#%`5E*?`7C\&`5B`5D`7B`7D"`7D;
X                        /* Chars found in Un*x file names, illegal in VMS */
X
Xstruct stat sblock;     /* structure returned from stat() */
Xstruct FAB fblock;      /* File attribute block */
Xstruct NAM nblock;      /* Name attribute block for rms */
X
Xint bytecount,  mode, uic1, uic2, linktype; /* Data from header */
Xint uid, gid, bufferpointer;    /* current values used by create */
XFILE *tarfp;                      /* The input file pointer */
X
X/* Global file characteristics */
X
XFILE *vmsfile;
Xint vmsfd, outfd;
Xunsigned int vmsmrs, vmstime;       /* maximum record size */
Xint vmsrat,vmsorg,vmsrfm;           /* other format (as integers) */
Xchar default_name`5B`5D = `7B"*.*;"`7D;     /* only get the most recent vers
Vion */
X
X/* main -- parses options, dispacthes to tar2vms and vms2tar */
X
Xmain(argc,argv)
Xint argc;
Xchar *argv`5B`5D;
X`7B
Xchar *cp, c;
X
X/* Decode the options and parameters: */
X
X    if(argc ==1)
X        usage();
X    extract = 0;            /* Defaults for now */
X    verbose = 0;
X    wait = 0;               /* Don't wait for prompt */
X    binmode = 0;
X    create = 0;
X    dot = 0;
X    foption = 0;
X    strcpy(tarfile,"$TAPE");
X
X        cp = argv`5B1`5D;
X        while(c = *cp++)
X            `7B
X            switch(c)
X            `7B
X            case 't':
X                list=1;
X                break;
X            case 'x':
X                extract=1;
X                break;
X            case 'c':
X                create=1;
X                break;
X            case 'v':
X                verbose=1;
X                break;
X            case 'w':
X                wait=1;
X                break;
X            case 'd':
X                dot=1;
X                break;
X            case 'b':
X                binmode=1;
X                break;
X            case 'f':
X                if (*cp != '\0' `7C`7C argc < 3)
X                    usage();
X                else
X                    foption = 1;
X                    strcpy(tarfile,argv`5B2`5D);
X                break;
X            case '-':
X                    break;
X            default:
X                printf("tar: option '%c' not recognized.\n",c);
X                usage();
X            `7D
X       `7D
X
X
X/* Check options are coherent */
X
X    if (extract + list + create == 0)
X    `7B
X        printf("tar: no action specified.\n");
X        exit(1);
X    `7D
X    if (extract + create == 2)
X    `7B
X        printf("tar: incompatible options specified.\n");
X        exit(1);
X    `7D
X
X/* Set up directory names - current and top level */
X
X    strcpy(curdev, getenv("PATH"));
X    for (cp = curdev; *cp != '\0'; ++cp)
X        *cp = toupper(*cp);`09`09/* map to uppercase */
X
X    cp = strchr(curdev, ':');    /* split into device and directory */
X    *cp++ = '\0';
X    strcpy(curdir, cp);
X
X    strcpy(topdir, curdir);
X    cp = strchr(topdir,'.');`09`09/* isolate top level directory */
X    if (cp != NULL)
X    `7B
X        *cp = '`5D';
X        *++cp = '\0';
X    `7D
X
X    if (create == 0)
X        tar2vms(argc,argv);
X    else
X        vms2tar(argc,argv);
X`7D
X
X/* tar2vms -- handles extract and list options */
X
Xtar2vms(argc,argv)
Xint argc;
Xchar **argv;
X
X`7B
Xint status,file_type,j, flag, argi, process;
Xchar *make_directory(), *argp, *ptr;
Xstruct dsc$descriptor pattern, candidate;
XFILE *opentar();
X
X/* open the file for reading */
X
X    if((tarfp = opentar()) == NULL)
X        `7B
X        printf("tar: error opening tarfile.\n");
X        exit(1);
X        `7D
X
X/* Now keep reading headers from this file, and decode the names, etc. */
X
X    while((status=hdr_read(&header))==DSIZE)    /* 0 on end of file */
X    `7B
X        process = 0;
X        if(strlen(header.title)!=0)     /* Valid header */
X        `7B
X            decode_header();
X            process = 1;
X
X/* Now if file names were specified on the command line, check if they
X   match the current one */
X
X            if ((foption == 0 && argc > 2) `7C`7C argc > 3)
X            `7B
X                process = 0;
X                argi = foption ? 3 : 2;
X                while (argi < argc)
X                `7B
X                    pattern.dsc$w_length = strlen(argv`5Bargi`5D);
X                    pattern.dsc$a_pointer = argv`5Bargi`5D;
X                    pattern.dsc$b_dtype = DSC$K_DTYPE_T;
X                    pattern.dsc$b_class = DSC$K_CLASS_S;
X                    candidate.dsc$w_length = strlen(pathname);
X                    candidate.dsc$a_pointer = pathname;
X                    candidate.dsc$b_dtype = DSC$K_DTYPE_T;
X                    candidate.dsc$b_class = DSC$K_CLASS_S;
X
X                    ++argi;
X
X                    if (STR$MATCH_WILD(&candidate, &pattern) == STR$_MATCH)
X                    `7B
X                        process = 1;
X                        break;
X                    `7D
X                `7D
X            `7D
X        `7D
X        else
X        `7B
X             status = 1;
X             break;
X        `7D `20
X        if (process && wait)
X        `7B
X            *temp = '\0';
X            while (*temp != 'y' && *temp != 'n')
X            `7B
X                printf("%s   (y/n) ? ", pathname);
X                scanf("%s", temp);
X                *temp = tolower(*temp);
X            `7D
X            process = (*temp == 'y');
X        `7D
X        if (process && extract)
X        `7B              `20
X                file_type=scan_title(pathname,new_directory,newfile);
X                cleanup_dire(new_directory);
X                if( make_new(new_directory)!=0)
X                    printf("tar: error creating %s\n",new_directory);
X                if(file_type == ISDIRE)
X                    `7B`7D
X                if(file_type == ISFILE)
X
X/*  Now move the data into the output file */
X
X                    if(bytecount>0)
X                        `7B
X                        strcpy(outfile,new_directory);
X                        strcat(outfile,newfile);
X                        if((j=copyfile(outfile,bytecount))<0)
X                            printf("tar: error writing file %s\n",outfile);
X                        `7D
X        `7D
X        else
X        `7B
X            if (process && list)               /* listing only */
X            `7B
X                printf("%6o %8d %s %s\n",
X                    mode,bytecount,creation+4,pathname);
X                if (linktype == 1 `7C`7C linktype == 2)
X                 printf("                                --->  %s\n",linknam
Ve);
X            `7D
X            if(linktype == 0)
X                tarskip(bytecount);
X        `7D
X    `7D       /* end while  */
X    if(status == 1)                     /* Empty header */
X    `7B
X
X/*        printf("Do you wish to move past the EOF mark (y/n) ? ");
X**        fflush(stdout);
X**        gets(temp);
X**        if(tolower(*temp) == 'y')
X**            while((status=hdr_read(&header)) >0);
X**        else
X*/
X            exit(SS$_NORMAL);
X    `7D
X    if(status==0)                       /* End of tar file  */
X    `7B
X        printf("tar: EOF hit on tarfile.\n");
X        exit(SS$_NORMAL);
X    `7D
X    if(status<0)                        /* An error  */
X    `7B
X        printf("tar: error reading tarfile.\n");
X        exit(SS$_NORMAL);
X    `7D
X`7D
X
X
X/* This function simply copies the file to the output, no conversion */
X
Xint copyfile(outfile,nbytes)
Xchar outfile`5B`5D; /* name of output version */
Xint nbytes;
X
X`7B
Xint inbytes, fil;
X
X/*  Open the output file */
X
X    if (binmode)
X        fil = creat(outfile,0,"rfm=fix","mrs=512","alq=5");
X    else
X        fil = creat(outfile,0,"rfm=stmlf","rat=cr");
X
X    if(fil == ERROR1)
X        `7B
X        printf("tar: error creating %s \n",outfile);
X        tarskip(bytecount);
X        return(-2);
X        `7D
X    if(linktype !=0)
X        `7B
X        sprintf(buffer,"*** This file is only a link to %s\n",linkname);
X        write(fil,buffer,strlen(temp));
X        `7D
X    else
X        `7B
X        while(nbytes>0)
X            `7B
X            if((inbytes=fread(buffer,1,DSIZE,tarfp)) > 0)
X                `7B
X                write(fil,buffer,(nbytes > DSIZE)? DSIZE:nbytes);
X                nbytes -= inbytes;
X                `7D
X            else
X                `7B
X                printf("tar: EOF hit on input file.\n");
X                close(fil);
X                return(-1);
X                `7D
X            `7D
X        `7D
X/* Close the file */
X    close(fil);
X    if(verbose)
X        `7B
X        printf("%s %8d %s\n",creation+4,bytecount,outfile);
X        if(linktype!=0)
X            printf("                         --> %s\n",linkname);
X        `7D
X    return(0);
X`7D
X
X/* scan_title -- decode a Un*x file name into the directory and name */
X
X/* Return a value to indicate if this is a directory name, or another file
X* We return the extracted directory string in "dire", and the
X* filename (if it exists) in "fname". The full title is in "line"
X* at input.
X*/
X
Xint scan_title(line,dire,fname)
Xchar line`5B`5D,dire`5B`5D,fname`5B`5D;
X`7B
Xchar *end1;
Xint len,len2,i,ind;
X/* The format will be UNIX at input, so we have to scan for the
X* UNIX directory separator '/'
X* If the name ends with '/' then it is actually a directory name.
X* If the directory consists only of '.', then don't add a subdirectory
X* The output directory will be a complete file spec, based on the default
X* directory.
X*/
X
X    strcpy(dire,curdir);                /* Start with the current dir */
X    if(strncmp(line,"./",2)==0)
X        strcpy(line,line+2);            /* ignore "./" */
X    strcpy(temp,line);                  /* Start in local buffer */
X    ind=vms_cleanup(temp);              /* Remove illegal vms characters */
X    if((end1=strrchr(temp,'/'))==0)     /* No directory at all  ? */
X        strcpy(fname,temp);             /* Only a file name */
X    else
X    `7B                                   /* End of directory name is '/' */
X        *end1 = 0;                      /* Terminate directory name */
X        strcpy(fname,end1+1);           /* File name without directory */
X        for (i=1;temp`5Bi`5D;i++)           /* Change '/' to '.' in director
Vy */
X            if(temp`5Bi`5D=='/')`09`09/* and '.' to '_' */
X                temp`5Bi`5D='.';
X`09    else if (temp`5Bi`5D == '.')
X`09        temp`5Bi`5D = '_';
X        if (*temp == '/')               /* absolute path ? */
X        `7B
X            *temp = '`5B';`09`09/* yes, build absolute VMS path */
X            strcpy(dire,temp);
X        `7D
X        else
X        `7B
X            dire`5Bstrlen(dire)-1`5D = (*temp=='.')?0:'.' ;
X                 /* "." to indicate a subdirectory (unless already there )*/
X            strcat(dire,temp);      /* Add on the new directory  */
X        `7D
X        strcat(dire,"`5D") ;              /* And close with '`5D' */
X    `7D
X    if(strlen(fname)==0)        /* Could this cause problems ? */
X    `7B
X        return(ISDIRE);
X    `7D
X    else
X        for(i=0,end1=fname;*end1;end1++) /* Replace multiple . */
X            if(*end1 == '.')
X                if(i++)*end1 = '_'; /* After the first */
X    return(ISFILE);
X`7D
X
X/* make_new -- create a new directory */
X
Xint make_new(want)
Xchar want`5B`5D;
X`7B
Xint status, created;
+-+-+-+-+-+-+-+-  END  OF PART 2 +-+-+-+-+-+-+-+-
