From:	CSBVAX::MRGATE!IUS%DACTH51.BITNET@CUNYVM.CUNY.EDU@SMTP 14-JAN-1988 04:47
To:	ARISIA::EVERHART
Subj:	tar.3_of_3


Received: from CUNYVM.CUNY.EDU by KL.SRI.COM with TCP; Wed 13 Jan 88 19:00:06-PST
Received: from DACTH51.BITNET by CUNYVM.CUNY.EDU ; Wed, 13 Jan 88 21:59:33 EST
Date:     Wed, 13 Jan 88 13:36 N
From:     <IUS%DACTH51.BITNET@CUNYVM.CUNY.EDU> (Eberhard W. Lisse)
Subject:  tar.3_of_3
To:       info-vax@kl.sri.com
X-Original-To:  info-vax@kl.sri.com

$Part3:
$ File_is="VMS2TAR.C"
$ Check_Sum_is=1763549126
$ Copy SYS$Input VMS_SHAR_DUMMY.DUMMY
X/* Write a TAR format tape or file , from files in VMS directories */
X/* Copyright 1986,Sid Penstone,
X*  Department of Electrical Engineering,
X*  Queen's University,
X*  Kingston, Ontario, Canada K7L3N6
X* (613)-545-2925
X* BITNET:   PENSTONE@QUCDNEE1
X* Version 1.7, Nov.3,1986
X*
X* Modifications:
X*       - used the C call stat() to get file information
X*       - now propagates directory specs to subsequent file-specs
X* 1.4   - starts pathnames at current default directory
X* 1.5   - corrected error in scan_name for  directories outside tree
X*       - did immediate close of file-descriptor version in out_file
X*         to get around overflow of file operations ???
X* 1.6   - added cleanup_dire() to correctly handle rooted directory specs
X* 1.6b  - corrected typing error in scan_name "-" should be "="
X*       - looked past nodename in getting rid of device in scan_name()
X*       - reject access to other nodes by trapping "::" in initsearch()
X* 1.7   - set resultant string size to 0 in search(), because of problems
X*         with rooted directories
X*/
X
X
X/* The input data is in VMS format,. The output will be
X*  blocks of 10240 bytes, with 512 byte internal blocks of header
X* and data. Unfilled 512 blocks will be packed with garbage.
X* The output will be padded out to a full block of size BLKSIZE at
X* the end of the Tar file.
X */
X
X
X#include stdio
X#include time
X#include ssdef
X#include descrip
X#include ctype
X#include rms
X#include stsdef
X#include file
X#include stat
X#include types
X
X
X#define ISDIRE 1
X#define ISFILE 0
X#define FIXED           FAB$C_FIX
X#define NAMSIZE 100
X#define BLKSIZE 10240           /* Block size on tape*/
X#define DSIZE 512               /* data block */
X
Xstatic struct tarhdr                    /* A Tar header */
X    {
X    char title[NAMSIZE];
X    char protection[8];
X    char uid[8];
X    char gid[8];
X    char count[12];
X    char time[12];
X    char chksum[8];
X    char linkmode;      /* hope this is right */
X    char linkname[NAMSIZE];     /* Space for the name of the link */
X    char dummy[255];    /* and the rest */
X    } header;
X
Xstruct tarhdr *empty;                   /* buffer of nulls  */
Xchar *dbuffer;                          /* for buffering output data  */
X
Vstatic int bufferpointer;               /* Position of next byte in the block *
X/
Xstatic struct FAB fblock,fblock2;       /* File attribute block */
Xstatic struct NAM nblock,nblock2;       /* Name attribute block for rms */
Xstruct stat *sblock;                    /*  for stat() call  */
X
X/* Function flags, options:*/
Xint create,                     /* c operation (default) */
X    list,                       /* t operation */
X    verbose,            /* v option, report actions */
X    wait;
X
X/* Miscellaneous globals, etc. */
X
Xchar *strindex();       /* String search function */
X
Xchar *tarfile = "tape" ,        /* Output file */
X    operation = ' ',    /* Current operation c,t  */
X    pathname[NAMSIZE],  /* File name as written on tape (UNIX) */
X    directory[NAMSIZE], /* The current root directory */
X    new_directory[NAMSIZE],     /* Directory of current file */
X    newfile[NAMSIZE],   /* VMS format of file name */
X    outfile[NAMSIZE],   /* stripped format of file name */
X    filetime[32],               /* Modification date as from vms */
X    searchname[NAMSIZE];        /* for the NAM block  */
X
X/* Global file characteristics */
XFILE *vmsfile;
Xint vmsfd, outfd, temfd;
Xunsigned vmsmrs, vmstime;               /* maximum record size */
Xint vmsrat,vmsorg,vmsrfm; /* Other format (as integers) */
X
X
Xint bytecount,  mode, uid , gid , links;/* Data in the header */
Xdefault_name = "*.*";   /* Only get the most recent version */
Xint i;
X
X
X/* ******************** start here *************************** */
Xmain(argc,argv)
Xint argc;
Xchar *argv[];
X{
Xint status,file_type,j,c,len;
Xchar  *cp, *indx, names[NAMSIZE]= "", string[NAMSIZE]= "";
XFILE *temfile;
X
X    initialize();
X
X/* Decode the options and parameters: */
X    if(argc ==1)
X        {
X        create = 1;             /* Default for now */
X        operation = 'c';
X        list = 0;
X        verbose = 1;
X        wait = 0;               /* Don't wait for prompt */
X        }
X    if(--argc > 0)
X        {
X        cp = argv[1];
X        while(c = *cp++)
X            {
X            switch(c)
X                {
X                case 'c':               /*  c and t exclusive  */
X                    create = 1;
X                    operation = 'c';
X                    list = 0;
X                    break;
X                case 't':
X                    create = 0;
X                    list = 1;
X                    operation = 't';
X                    verbose = 1;        /* t means report  */
X                    break;
X                case 'v':
X                    verbose=1;
X                    break;
X                case 'w':
X                    wait=1;
X                    break;
X                default:
X                    printf("Option '%c' not recognized.\n",c);
X                }
X            }
X        }
X
X
X
X/* Use the parse operation to fill in missing specifications, and
X* set up for repeated searching. The multiple file search described
X* in the RMS manual does not seem to work, so we will have to sort out
X* the items separated by commas.
X */
X    if(--argc > 0)
X        strcpy(names,argv[2]);          /* Assume file name is next */
X    else
X        {
X        strcpy(names,"[...]*.*");
X/******** COMMENTED OUT.. otherwise asks the user for file names
X    printf(" File name(s)?");
X    gets(names);
X************ */
X        }
X    if(create)  /* Open the output and scratch files  */
X        {
X        outfd = creat(tarfile,0600,"rfm=fix","mrs=512");
X        temfile = tmpfile();
X        temfd = fileno(temfile);
X        if(outfd < 0 || temfd < 0 )
X            {
X            printf(
X            "Couldn't open output tar or scratch file. Bye,bye.\n");
X            exit(2);
X            }
X        }
X    /* Now we will extract search strings from the names string. Assume
X    * they are separated by commas.
X    */
X    while(strlen(names)!=0)     /* Get the file name argument */
X        {
X        if(indx=strchr(names,','))
X                *indx = 0;      /* Replace , by terminator  */
X        if(strchr(names,']'))   /* Always include a directory spec */
X            strcpy(string,names);       /* Get the new part  */
X        else                            /* If no directory, keep the old one */
X            if((cp = strchr(string,']')))
X                strcpy(cp+1,names);
X            else
X                strcpy(string,names);
X        if(initsearch(string) <= 0)
X            printf("***** No files found while searching for:%s\n",string);
X        else
X        while(search(newfile,100)!=0)
X            {
X            chgcase(newfile);   /* all lower case, please */
X            cleanup_dire(newfile);
X            file_type = scan_name(newfile,new_directory,outfile);
X            strcpy(pathname,new_directory);
X            strcat(pathname,outfile);
X            get_attributes(newfile);
X            if(create)
X                {
X                if(file_type == ISDIRE)
X                    {
X                    bytecount =  0;
X                    mode = 0755;
X                    fill_header(pathname);
X                    write_header(outfd);
X                    }
X                if(file_type == ISFILE)
X                    {
X                    mode = 0644;
X                    if(addfile(newfile, pathname) < 0)
X                        printf("ERROR: %s NOT COPIED\n",newfile);
X                    }
X                }
X            if(verbose || list)
X                {
X                if(bytecount || file_type == ISDIRE)
X                    printf("%c: %-40s %6d  %26s",
X                       operation,pathname,bytecount,ctime(&vmstime));
X                else
X                   printf("IGNORED:  %s\n",pathname);
X                }
X            }
X        if(indx)                        /* any more in the string ? */
X            strcpy(names,indx+1);       /* Yes, work on it  */
X        else
X            break;
X        }
X    if(create)
X        {
X        write_trailer(outfd);
X        close(outfd);
X        }
X    exit(SS$_NORMAL);
X}
X
X/* Copy the vms file to the output file.
X*
X*/
X
Xint addfile(vmsname,unixname)
Xchar vmsname[],unixname[];
X{
Xint ind;
X    if(bytecount == 0)          /* We don't output null files  */
X        return(0);
X    if((ind=out_file(vmsname,bytecount,outfd)) < 0)
X        return(ind);
X    bufferpointer = bufferpointer%BLKSIZE;
X    return(1);
X}
X
X
X/* Write out the file.
X* move nbytes of data from "fdin" to "fdout";
X* Always pad the output to a full DSIZE
X* If it a vms text file, it may be various formats, so we will
X* write into a temporary file first, then copy to the output
X* so that we get the correct byte count.
X* We set the bytecount=0 if this is funny file.
X*/
Xint out_file(filename,nbytes,fdout)
Xchar filename[];
Xint fdout, nbytes;
X{
Xint i, n, pos, fdin;
XFILE *filein;
X    if(vmsrfm == FIXED)
X        {
X        if((fdin=open(filename,0)) <=0)
X                {
X                printf("Error opening input file %s\n",filename);
X                return(-1);
X                }
X        fill_header(pathname);          /* We have all of the information */
X        write_header(outfd);            /* So write to the output */
X        while(nbytes > 0)
X            {
X            n = read(fdin,dbuffer,nbytes>DSIZE? DSIZE:nbytes);
X            if(n<0)
X                {
X                close(fdin);
X                printf("Read error on input file\n");
X                return(-1);
X                }
X            nbytes -= n;
X            write(fdout,dbuffer,DSIZE);
X            bufferpointer += DSIZE;             /* Count the position */
X            }
X        close(fdin);
X        return(0);
X        }
X    else if(vmsrat != 0)                /* must be a text file  */
X        {                               /* Write out to standard stream */
X        if((filein = fopen(filename,"r")) == NULL)
X                {
X                printf("ERROR OPENING %s\n",filename);
X                return(-1);
X                }
X        nbytes = 0;
X        lseek(temfd,0,0);               /* Back to the beginning  */
X        while((i = fgets(dbuffer,DSIZE,filein)) !=  NULL)
X            {
X            n = strlen(dbuffer);
X            nbytes += n;
X            write(temfd,dbuffer,n);
X            }
X        fclose(filein);                 /* All done with the input */
X        lseek(temfd,0,0);               /* Back to the beginning  */
X        bytecount = nbytes;             /* Use the real count  */
X        fill_header(pathname);          /* Compute the header */
X        write_header(outfd);            /* Write it  */
X        while(nbytes > 0)               /* Now copy to the output */
X            {
X            n = read(temfd,dbuffer,nbytes>DSIZE? DSIZE:nbytes);
X            nbytes -= n;
X            write(fdout,dbuffer,DSIZE);
X            bufferpointer += DSIZE;             /* Count the position */
X            }
X        return(0);
X        }
X                        /* Other formats e.g. .OBJ are not done  */
X        bytecount = 0;
X        return(0);
X}
X
X/* Copy the header to the output file  */
Xint write_header(fd)
Xint fd;
X{
Xint n;
X    if((n=write(fd,&header,DSIZE))!=DSIZE)
X        {
X        printf("Error writing header in output file.\n");
X        exit(1);
X        }
X    bufferpointer += DSIZE;
X    return(n);
X}
X
X/*  get the file attributes via stat()  */
X
Xint get_attributes(fname)
Xchar fname[];
X{
X    if(stat(fname,sblock))
X    {
X        printf("Error getting file status:%s\n",fname);
X        vmstime = 0;                    /* Prevent garbage printoout */
X        bytecount = 0;                  /* of inaccessible files  */
X        return(-1);
X    }
X/* now get the file attributes, we don't use them all */
X    bytecount = sblock->st_size;
X    vmsrat = sblock->st_fab_rat;
X    vmsmrs = sblock->st_fab_mrs;
X    vmsrfm = sblock->st_fab_rfm;
X    vmstime = sblock->st_mtime;
X}
X
X
X/* Write the two blank blocks on the output file, and pad the output
X* to a full blocksize if needed. */
Xwrite_trailer(fdout)
Xint fdout;
X{
Xint rem;
X    header = *empty;
X    write_header(fdout);
X    write_header(fdout);
X    bufferpointer = bufferpointer%BLKSIZE;
X    while (bufferpointer < BLKSIZE)
X        write_header(fdout);
X    return(1);
X}
X
X/* Decode a file name into the directory, and the name, and convert
X* to a valid UNIX pathname. Return  a value to indicate if this is
X* 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_name(line,dire,fname)
Xchar line[],dire[],fname[];
X{
Xchar temp[NAMSIZE],*end1,*end2;
Xint len,len2,i;
X/* The format will be VMS at input, so we have to scan for the
X* VMS device separator ':', and also the VMS directory separators
X*  '[' and ']'.
X* If the name ends with '.dir;1' then it is actually a directory name.
V* The outputs dire and  fname will be a complete file spec, based on the defaul
Xt
X* directory.
X* It may be a rooted directory, in which case there will be a "][" string
X* remove it..
V* Strip out colons from the right, in case there is a node name (should not be!
X)
X*/
X
X
X    strcpy(temp,strrchr(line,':')+1);           /* Start with the whole name */
X/* Get rid of default directory part of the name  */
X    for(end1=temp,end2=strrchr(directory,':')+1;*end2 && (*end1 == *end2);
X         end1++,end2++);
X    if(*end2 == 0)
X        *end1 = 0;              /* Perfect match, no directory spec  */
X    else
X        {
X        switch(*end1)
X        {
X        case '.':
X        case '[':               /* Legal beginnings or ends  */
X            break;
X        case ']':               /* We are above the default, use full name */
X            end1 = strchr(temp,'[');    /* Fixed this from 1.5  */
X            break;
X        default:                /* Something strange, back up  */
X/*******            printf("File located above default directory..\n"); ***/
X            while(*end1 != '.' && *end1 != '[' && end1 >= temp)
X                end1--;
X            break;
X        }
X        end1++;                 /* Get past the starting . or [ */
X    }
X    strcpy(dire,end1);
X    if(strlen(dire))
X        strcpy(strchr(dire,']'),"/");   /* get rid of the directory marks  */
X    strcpy(temp,strchr(line,']')+1); /* Now get the file name */
X    if((end1=strindex(temp,".dir;1"))!=0)
X        {
X        strcpy(end1,"/");                       /* Terminate directory name */
X        strcat(dire,temp);
X        strcpy(fname,"");
X        }
X    else
X        {
X        strcpy(fname,temp);
X        strcpy(strchr(fname,';'),"");           /* no version numbers */
X        }
X    /* Now rewrite the directory name  */
X    for (i=1;dire[i];i++)       /* Change '.' to '/'  */
X        if(dire[i]=='.')
X            dire[i]='/';
X    if(strlen(fname)==0)
X        {
X        return(ISDIRE);
X        }
X    else
X        return(ISFILE);
X}
X
X/* To start looking for file names to satisfy the requested input,
X* use the sys$parse routine to create a wild-card name block. When
X* it returns, we can then use the resultant FAB and NAM blocks on
X* successive calls to sys$search() until there are no more files
X* that match
X*/
X
Xint initsearch(string)
Xchar string[];
X{
Xint status;
X
X    if(strindex(string,"::")!=NULL)
X        {
X        printf("***** Access across nodes is not supported.\n");
X        return(-1);
X        }
X    fblock = cc$rms_fab;
X    nblock = cc$rms_nam;
X    fblock.fab$l_dna = default_name;
X    fblock.fab$b_dns = strlen(default_name);
X    fblock.fab$l_fna = string;
X    fblock.fab$b_fns = strlen(string);
X    fblock.fab$l_nam = &nblock;
X    nblock.nam$l_esa = searchname;
X    nblock.nam$b_ess = sizeof(searchname);
X#ifdef debug
X    printf("searching on: %s\n",string);
X#endif
X    status = sys$parse(&fblock);
X    if(status != RMS$_NORMAL)
X        {
X        if(status == RMS$_DNF)
X            printf("Directory not found:%s\n",searchname);
X        else
X            printf("Error in sys$parse()\n");
X        return (-1);
X        }
X    searchname[nblock.nam$b_esl] = 0;   /* Terminate the string  */
X    /* Now reset for searching, pointing to the parsed name block */
X    fblock = cc$rms_fab;
X    fblock.fab$l_nam = &nblock;
X    return(nblock.nam$b_esl); /* return the length of the string  */
X}
X
X/* Get the next file name that matches the namblock that was set
X* up by the sys$search() function.
X*/
Xint search(buff,maxlen)
Xchar buff[];
Xint maxlen;
X{
Xint status;
X
X    nblock.nam$l_rsa = buff;
X    nblock.nam$b_rss = maxlen;
X    nblock.nam$b_rsl = 0;       /* For next time around  */
X    while( (status = sys$search(&fblock)) != RMS$_NMF)
X    {
X        buff[nblock.nam$b_rsl] = 0;
X        if(status == RMS$_NORMAL)
X            {
X            return(nblock.nam$b_rsl);
X            }
X        else
X            {
X            if( status == RMS$_PRV)
X                printf("%s : No privilege for access.\n",buff);
X            else if (status == RMS$_FNF)
X                printf("%s : File not found.\n",buff);
X            else
X                {
X                printf(" Error in f$search for :%s\n", buff);
X                return (0);
X                }
X            }
X    }
X    return (0);
X}
X/* Fill the fields of the header; enter with the file name
X* if the file name is empty, then this is a trailer, and we should
X* fill it with zeroes. */
X
Xint fill_header(name)
Xchar name[];
X{
Xint i,chksum;
Xchar *ptr,tem[15];
X    header = *empty;            /* Clear the header  */
X    if(strlen(name)!=0)         /* only fill if there is a file */
X        {
X        sprintf(header.title,"%s",name);        /* write file name */
X        sprintf(header.protection,"%6o ",mode); /* all written with */
X        sprintf(header.uid,"%6o ",uid);         /* a trailing space */
X        sprintf(header.gid,"%6o ",gid);
X        sprintf(tem,"%11o ",bytecount);         /* except the count */
X        strncpy(header.count,tem,12);           /* and the time, which */
X        sprintf(tem,"%11o ",vmstime);           /* except the count */
X        strncpy(header.time,tem,12);            /* have no null */
X        strncpy(header.chksum,"        ",8);    /* all blanks for sum*/
X/* I know that the next two are already zero, but do them */
X        header.linkmode = 0;                    /* always zero */
X        sprintf(header.linkname,"%s","");       /* always blank */
X        for(chksum=0, ptr = &header;ptr < &header.linkmode;ptr++)
X                 chksum += *ptr;                /* make the checksum */
X        sprintf(header.chksum,"%6o",chksum);    /* This is how it looks */
X        }                                       /* on UNIX tapes... */
X    return(0);
X}
X
X/* Initialize various fields, get some standard values */
X
Xinitialize()
X{
Xint i;
X    dbuffer = malloc(DSIZE+1);
X    sblock = malloc(sizeof(struct stat));
X    empty = malloc(DSIZE);
X    for (i=0;i < DSIZE;i++)
X        empty->title[i] = 0;    /* all zeroes, even if malloc() did it  */
X    header = *empty;
X    bufferpointer = 0;
X    gid = getgid();     /* for now, use the user's uic */
X    uid = getuid(); /* and group uic */
X    mode = 0644;                /* This get changed elsewhere, anyhow */
X    strcpy(directory,getenv("PATH"));   /* Default directory */
X    return;
X}
X
X
X/* Search for string2 in string1; return address pointer. */
Xchar *strindex(string1,string2)
Xchar *string1,*string2;
X{
Xchar *c1, *c2, *cp;
X    for(c1 = string1; *c1 !=0; c1++)
X        {
X        cp = c1;        /* save the start address */
X        for(c2=string2; *c2 !=0 && *c1 == *c2; c1++,c2++);
X           if(*c2 == 0)
X                return(cp);
X        }
X    return(NULL);
X}
X
X/* function to change a string to lower case */
Xint chgcase(string)
Xchar string[];
X{
Xint i;
X        for(i=0;string[i]=tolower(string[i]);i++);
X        return (--i);           /* return string length */
X}
X
X/* Routine to get rid of rooted directory problems,
X* and any others that turn up
X*/
X
Xint cleanup_dire(string)
Xchar string[];
X{
Xchar *ptr, temp[NAMSIZE];
X        if((ptr=strindex(string,"][")) == NULL)
X                return(0);
X                /* Just collapse around the string */
X        strcpy(ptr,ptr+2);
X        return(1);
X}
$ GoSub Convert_File
$ File_is="VMS2TAR.DOC"
$ Check_Sum_is=1412616241
$ Copy SYS$Input VMS_SHAR_DUMMY.DUMMY
XGreetings:                                      Nov.3,1986
X        Here is the current version of a program to write Tar format tapes on
Xa VMS system. Comments and reports on bugs will be much appreciated. It
Xhas been tried with a SUN system, and files were read successfully.
X        Before compiling, separate the program, at the "*** CUT HERE ***"
Xline below.
X        Incidentally, .EXE programs from vms can be moved around on a tar tape,
Xand when re-extracted with the Tar reader, they run on vms again. (Note that
Xthe file attributes are wrong).
X        The file-spec in the command string can use the usual VMS wild cards,
Xin fact anything that you would use in a DIRECTORY command. Successive
Xfile-specs must be separated by commas, without blank spaces, or the
Xcommand handler separates them as separate arguments, and only the data
Xahead of the blanks is used.
XExample:   vms2tar cv [john.new...]*.c   will copy all of the .c files in
Xthe subdirectories to the Tar file.
X        Directory specifications are propagated to successive file
Xspecifications, if there is no explicit directory specification. A
Xtest with the "t" (list) option will help to show how it works.
X        Note that UNIX does not permit two files of the same name in
Xthe same directory, so the program does not assume the wild card for
Xthe version number, and you should not use it in the input spec, or
Xonly the last version written on the tape (the oldest) will survive
Xwhen extracted on the UNIX system. The program as written copies the
Xhighest version number by default. The version number is NOT included
Xin the file name on the Tar tape.
X        If you wish to output different version numbers to Tar, then
Xthe code would be modified something like this in scan_name:
XIf there is a ";*" string in the searchname[] string, then convert
Xthe ';' in the fname[] into an appropriate UNIX symbol, e.g. '.',,
Xso it will come out as "fname.c.34" , for example.
X
X
XSid Penstone,
XVLSI Group,
XDept. of Electrical Engineering,
XQueen's University,
XKingston, Ontario, Canada K7L 3N6
X
X Usage:
X-------------------------------------------------------------------------
X
X    -Define the logical variable "TAPE" to be the desired tape
X     unit, or the output file.
X
X    -Mount the tape /FOREIGN/BLOCK=10240/RECORD=512
X     Existing data on the tape will be written over, unless the
X     tape is moved to an end-of-file with the SET MAGTAPE/ commands.
X
X    -Set the default directory to the top of the tree (if applicable).
X     This gives pathnames on the tape that start at the current
X     default. i.e. if your default is [MYDIRE.MAIN], the file
X     [MYDIRE.MAIN]START.C will be copied as "start.c" ; the file
X     [MYDIRE.MAIN.TESTS]RUNIT.C will be copied as "tests/runit.c" .
X     Files that are not in the current default tree will be copied
X     with a full pathname; e.g. "mydire/main/tests/runit.c"
X
X   -Then run VMS2TAR: (either by RUN or as a command)
X     if you use RUN, the operation is "(create, verbose) [...]*.*"
X     As a command:
Xvms2tar [options] [file-spec,file-spec,,,]
X     where the options are:
X            "t" (listing of the files that will be copied (no copy done))
X            "c" (create copies of the files on the output tape, starting
X                        at the current position on the tape.)
X            "v" (verbose: report activities on stdout)
X            "w" (wait)  not implemented
X    -To use the options:
X     the program must be executed using the foreign command
X     feature of VMS by defining a command:
Xcommand :== $path:vms2tar      !where path= full location of vms2tar.exe
X
X     - if no file-spec is given, the highest version number of all of
X     the files in the current default directory and its subdirectories
X     will be written out.
X
XERRORS:
X    - "couldn't open Tar file":  likely forgot to MOUNT the tape
X    - "error getting status" :  protection error
X
X--------------------------------------------------------------------------
XImportant assumptions for this version:
X
X    The defaults are (no options):
X    -Extract the highest numbered version of all of the files in the
X     current directory tree,reporting  as each file is created.
X     Pathnames on the tape start below the current default directory; for
X     example, if you are in [SID.MAIN], the files in [SID.MAIN.SUB]
X     will be written as sub/filename .
X
X    -Write to a tape, mounted foreign, with block size of 10240
X     bytes, or a file of fixed record length. If a different block
X     size is desired, change the  definition of BLKSIZE.
X
X    -Close with the special (blank header) block written by UNIX.
X     It will be followed by an end-of-file or end-of tape.
X
X    -All files with record attributes are assumed to be text files
X     and are converted into  UNIX stream files. This includes regular
X     VMS text files, printer files, stream files, or Fortran output.
X
X    -Files with fixed record length and no record attributes are
X     copied in fixed block format. This includes .EXE files, and
X     other specials, but not .OBJ files.
X
X    -Does not copy files with variable-length, no record attributes;
X     ex. .OBJ files. They are reported as not copied.
X
X    -Does not copy savesets correctly.
X
X
X This version converts the directory names to UNIX format before creating
X the files. Some special cases:
X (1) Directories are written with a trailing "/".
X (2) Directories are created in  the order that they are encountered
X        by the F$SEARCH() operation of VMS
X
X--------------------------------------------------------------------------
XKnown Bugs:
X    (1) Writes extra empty trailer blocks into a file as though it
X     were a tape.Could be fixed by finding out if the output is a file.
X    (2) The method used to remove the higher level directory spec.
X     from the pathname may be a little flaky. Watch to see if any files
X     end up in the wrong tree.
X    (3) Can't change the default directory within the same run.
X    (4) Cannot emulate the "r" or "u" functions of UNIX Tar. Separate
X     files must be used.
X    (5) There is a problem with indexed files (e.g .MAI files) that
X        will be looked at shortly.
X    (6) Files with no file extension will be written on the TAR file
X        with a trailing "." . This can cause some files to apparently
X        vanish on the UNIX system that reads it, since "makefile" is
X        now called "makefile." , etc. So they will have to be renamed
X        on the UNIX system back to the correct name.
X        There are similar problems with files that were copied from
X        UNIX that had extra "." or "," in the file name; these will
X        have been translated to "_", and written back out.
$ GoSub Convert_File
$ Exit
