[comp.os.vms] tar.1_of_2

IUS@DACTH51.BITNET (Eberhard W. Lisse) (01/11/88)

Hi,

here is the promised public domaine tar. I have made two parts with Michael
Bednarek's vms_shar.

the other one follows.

regards, el

...................... Cut between dotted lines and save ......................
$!..............................................................................
$! VAX/VMS archive file created by VMS_SHAR V-5.01 01-Oct-1987
$! which was written by Michael Bednarek (U3369429@ucsvc.dn.mu.oz.au)
$! To unpack, simply save and execute (@) this file.
$!
$! This archive was created by AMSD::LISSE
$! on Monday 11-JAN-1988 13:33:44.53
$!
$! ATTENTION: To keep each article below 65024 bytes, this program
$! has been transmitted in 2 parts.
$! You should concatenate ALL parts to ONE file and execute (@) that file.
$!
$! It contains the following 6 files:
$! BLKLOOK.C TAR2VMS.C TAR2VMS.DOC TGTAR.C VMS2TAR.C VMS2TAR.DOC
$!==============================================================================
$ Set Symbol/Scope=(NoLocal,NoGlobal)
$ Version=F$GetSYI("VERSION") ! See what VMS version we have here:
$ If Version.ges."V4.4" then goto Version_OK
$ Write SYS$Output "Sorry, you are running VMS ",Version, -
                ", but this procedure requires V4.4 or higher."
$ Exit 44
$Version_OK: CR[0,8]=13
$ Pass_or_Failed="failed!,passed."
$ Goto Start
$Convert_File:
$ Read/Time_Out=0/Error=No_Error1/Prompt="creating ''File_is'" SYS$Command ddd
$No_Error1: Define/User_Mode SYS$Output NL:
$ Edit/TPU/NoSection/NoDisplay/Command=SYS$Input/Output='File_is' -
        VMS_SHAR_DUMMY.DUMMY
f:=Get_Info(Command_Line,"File_Name");b:=Create_Buffer("",f);
o:=Get_Info(Command_Line,"Output_File");Set(Output_File,b,o);
Position(Beginning_of(b));Loop x:=Erase_Character(1);Loop ExitIf x<>"V";
Move_Vertical(1);x:=Erase_Character(1);Append_Line;
Move_Horizontal(-Current_Offset);EndLoop;Move_Vertical(1);
ExitIf Mark(None)=End_of(b) EndLoop;Position(Beginning_of(b));Loop
x:=Search("`",Forward,Exact);ExitIf x=0;Position(x);Erase_Character(1);
If Current_Character='`' then Move_Horizontal(1);else
Copy_Text(ASCII(INT(Erase_Character(3))));EndIf;EndLoop;Exit;
$ Delete VMS_SHAR_DUMMY.DUMMY;*
$ Checksum 'File_is
$ Success=F$Element(Check_Sum_is.eq.CHECKSUM$CHECKSUM,",",Pass_or_Failed)+CR
$ Read/Time_Out=0/Error=No_Error2/Prompt=" CHECKSUM ''Success'" SYS$Command ddd
$No_Error2: Return
$Start:
$ File_is="BLKLOOK.C"
$ Check_Sum_is=1345803428
$ Copy SYS$Input VMS_SHAR_DUMMY.DUMMY
X /*
X   This program attempts to find out the blocksize of a tape
X */
X
X#include descrip
X#include stdio
X#include iodef
X#include file
X
Xmain()
X{
X#define MNT$M_FOREIGN  1
X#define MNT$_DEVNAM    1
X#define MNT$_BLOCKSIZE 8
X#define MNT$_RECORDSIZ 16
X#define MNT$_FLAGS     4
X
X#define DMT$M_NOUNLOAD 1
X
Xtypedef struct
X          {
X          short cond_value;
X          short count;
X          int info;
X          }  status_block;
X
Xtypedef struct
X          {
X          short buffer_len;
X          short item_code;
X          int buffer_addr;
X          int ret_len_addr;
X          }  item_desc;
X
Xstruct
X   {
X   item_desc dev_name;
X   item_desc block_size;
X   item_desc flags_item;
X   int terminator;
X   }  mnt_list;
X
Xchar tape[] = "MRA0:", line[65534];
Xint flags = MNT$M_FOREIGN,
X    blocks = 65532,
X    status;
X
Xshort channel;
Xstatus_block iosb;
X$DESCRIPTOR(tape_desc, tape);
X
X/* set up mnt_list */
Xmnt_list.dev_name.buffer_len = strlen(tape);
Xmnt_list.dev_name.item_code = MNT$_DEVNAM;
Xmnt_list.dev_name.buffer_addr = tape;
Xmnt_list.dev_name.ret_len_addr = 0;
X
Xmnt_list.block_size.buffer_len = 4;
Xmnt_list.block_size.item_code = MNT$_BLOCKSIZE;
Xmnt_list.block_size.buffer_addr = &blocks;
Xmnt_list.block_size.ret_len_addr = 0;
X
Xmnt_list.flags_item.buffer_len = 4;
Xmnt_list.flags_item.item_code = MNT$_FLAGS;
Xmnt_list.flags_item.buffer_addr = &flags;
Xmnt_list.flags_item.ret_len_addr = 0;
X
Xmnt_list.terminator = 0;
X
X/* mount the tape */
Xif (((status = SYS$MOUNT(&mnt_list)) &1) != 1)
X   LIB$STOP(status);
X
Xif (((status = SYS$ASSIGN(&tape_desc,&channel,0,0)) &1) !=1)
X   LIB$STOP(status);
X
X/* read a block */
Xif (((status = SYS$QIOW(0, channel, IO$_READLBLK, &iosb, 0, 0,
X                  line, blocks, 0,0,0,0)) &1) != 1)
X   LIB$STOP(status);
Xif ((iosb.cond_value &1) != 1)
X   LIB$STOP(iosb.cond_value);
X
Xprintf("  Block Size = %d bytes\n",iosb.count);
X
X
Xif (((status = SYS$DISMOU(&tape_desc, DMT$M_NOUNLOAD)) &1) != 1)
X   LIB$STOP(status);
X}
$ GoSub Convert_File
$ File_is="TAR2VMS.C"
$ Check_Sum_is=1685857467
$ Copy SYS$Input VMS_SHAR_DUMMY.DUMMY
X/* Read a TAR format tape or file , move files into VMS directories */
X/* Copyright 1986, Sid Penstone,
X*  Department of Electrical Engineering,
X*  Queen's University,
X*  Kingston, Ontario, Canada K7L3N6
X* (613)-545-5925
X* BITNET:          PENSTONE@QUCDNEE1  (Preferred)
X*       or  PENSTONE@QUCDN
X*
X* Version 2.2, Oct.21,1986
X* mods: - corrected header size (thanks to Eric Gisin, U .of Waterloo)
X*       - No more of the dreaded QIO's ( "  "  " )
X*       - tried to sort out link flag format
X*       - uses a tape or a file as input
X*       - NOTE: default is NO conversion to vms standard text format (cr)
X* 2.1   - trapped commas in file names, converted to '_'
X* 2.2   - reported translations of names
X*       - continued after error in opening output file
X*       - exit correctly on cannot open input file
X*/
X
X
X/* The input data is in record format, length 512, blocks of 10240 bytes;
X */
X
X
X#include stdio
X#include time
X#include ssdef
X#include iodef
X#include descrip
X#include ctype
X
X#define ERROR1 -1
X#define BUFFSIZE 512
X#define ISDIRE 1
X#define ISFILE 0
X#define NAMSIZE 100
X#define SIZE 10240              /* Block size */
X#define DSIZE 512               /* Data block size */
X
Xstruct                  /* A Tar header */
X    {
X    char title[NAMSIZE];
X    char protection[8];
X    char field1[8];             /* this is the user id */
X    char field2[8];             /*  this is the group id */
X    char count[12];             /*  was 11 in error */
X    char time[12];              /* UNIX format date  */
X    char chksum[8];             /* Header Checksum (ignored) */
X    char linkcount;             /* 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
Xstatic char buffer[DSIZE];      /* BUFFER for a record */
X
X/* Function flags, options:*/
Xint extract,            /* x option (default) */
X    list,                       /* t option : list tape contents */
X    verbose,            /* v option, report actions */
X    wait;
X
X/* Miscellaneous globals, etc. */
X
Xchar *tarfile = "tape", /* Input file name  */
X    pathname[NAMSIZE],  /* File name as found on tape (UNIX) */
X    directory[NAMSIZE], /* Current directory */
X    new_directory[NAMSIZE],     /* Directory of current file */
X    top[NAMSIZE],               /* Top level or root */
X    newfile[NAMSIZE],   /* VMS format of file name */
X    outfile[NAMSIZE],   /* Complete output file specification */
X    temp[256],          /* Scratch */
X    creation[NAMSIZE],  /* Date as extracted from the TAR file */
X    *ctime(),           /* System function */
X    linkname[NAMSIZE];  /* Linked file name  */
X
Xint bytecount,  mode, uic1, uic2, linktype;/* Data from header */
Xint tarfd;                      /* The input file descriptor */
X
Xmain(argc,argv)
Xint argc;
Xchar *argv[];
X{
Xint isterm,status,file_type,j,c, flag;
Xchar *make_directory(), *cp;
X
X/* Decode the options and parameters: */
X
X    if(argc ==1)
X        {
X        extract = 1;            /* Default for now */
X        verbose = 1;
X        wait = 0;               /* Don't wait for prompt */
X        }
X    while(--argc > 0)
X        {
X        cp = argv[1];
X        while(c = *cp++)
X            {
X            switch(c)
X            {
X            case 't':
X                list=1;
X                break;
X            case 'x':
X                extract=1;
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/* Find if this is a terminal */
X    isterm = isatty(0);
X
X/* Set up directory names */
X    strcpy(top,getenv("PATH"));
X
X/* Start with the default as the top */
X    strcpy(directory,top);
X
X/* open the file for reading */
X    if((tarfd = opentar()) <= 0)
X        {
X        printf("Error opening the Tar tape\n");
X        exit(2);
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        {
X        if(strlen(header.title)!=0)     /* Valid header */
X            {
X            decode_header();
X            if(extract)
X                {
X                file_type=scan_title(pathname,new_directory,newfile);
X                if( make_new(new_directory)!=0)
X                    printf("Error creating %s\n",new_directory);
X                if(file_type == ISDIRE)
X                    {}
X                if(file_type == ISFILE)
X/*  Now move the data into the output file */
X                    if(bytecount>0)
X                        {
X                        strcpy(outfile,new_directory);
X                        strcat(outfile,newfile);
X                        if((j=copyfile(outfile,bytecount))<0)
X                            printf("Error writing file %s\n",outfile);
X                        }
X                }
X            else                        /* listing only */
X                {
X                printf("%o %6d %s %s\n",
X                    mode,bytecount,creation+4,pathname);
X                if(linktype == 0)
X                    tarskip(bytecount);
X                else
X                    printf("     *****( Linked to file: %s)\n",linkname);
X                }
X            }
X        else                    /* Empty header means the end!!! */
X            {
X            status = 1;
X            printf("End of Tar file found.\n");
X            break;
X            }
X
X        }       /* end while  */
X    if(status == 1)                     /* Empty header */
X        {
X        printf("Do you wish to move past the EOF mark ? y/n\n");
X        gets(temp);
X        if(tolower(temp[0]) == 'y')
X            while((status=hdr_read(&header)) >0);
X        else
X            exit(SS$_NORMAL);
X        }
X    if(status==0)                       /* End of tar file  */
X        {
X        printf("End of file encountered\n");
X        exit(SS$_NORMAL);
X        }
X    if(status<0)                        /* An error  */
X        {
X        printf("Error reading input.\n");
X        exit(2);
X        }
X}
X
X
X/* This function simply copies the file to the output, no conversion */
X
Xint copyfile(outfile,nbytes)
Xchar outfile[]; /* name of output version */
Xint nbytes;
X
X{
Xint inbytes, fil;
X/*  Open the output file */
X    if((fil=creat(outfile,0)) == ERROR1)
X        {
X        printf(" Creation error in opening %s \n",outfile);
X        tarskip(bytecount);
X        return(-2);
X        }
X    if(linktype !=0)
X        {
X        sprintf(buffer,"This file is linked to %s\n",linkname);
X        write(fil,buffer,strlen(temp));
X        }
X    else
X        {
X        while(nbytes>0)
X            {
X            if((inbytes=read(tarfd,buffer,DSIZE)) > 0)
X                {
X                write(fil,buffer,(nbytes > DSIZE)? DSIZE:nbytes);
X                nbytes -= inbytes;
X                }
X            else
X                {
X                printf("End of input file detected\n");
X                close(fil);
X                return(-1);
X                }
X            }
X        }
X/* Close the file */
X    close(fil);
X    if(verbose)
X        {
X        printf("CREATED: %s\n",outfile);
X        if(linktype!=0)
X            printf(" *** REAL DATA IS IN: %s\n",linkname);
X        }
X    return(0);
X}
X
X/* Decode a file name into the directory, and the name, return
X* 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[],dire[],fname[];
X{
Xchar temp[NAMSIZE],*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    strcpy(dire,top);                   /* Start with the top level */
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        {                               /* End of directory name is '/' */
X        *end1 = 0;                      /* Terminate directory name */
X        strcpy(fname,end1+1);           /* File name without directory */
X        for (i=0;temp[i];i++)           /* Change '/' to '.' in directory */
X            if(temp[i]=='/')
X                temp[i]='.';
X        dire[strlen(dire)-1] = (temp[0]=='.')?0:'.' ;
X                 /* "." to indicate a subdirectory (unless already there )*/
X        strcat(dire,temp);      /* Add on the new directory  */
X        strcat(dire,"]") ;              /* And close with ']' */
X        }
X    if(strlen(fname)==0)        /* Could this cause problems ? */
X        {
X        return(ISDIRE);
X        }
X    else
X        for(i=0,end1=fname;*end1;end1++) /* Replace multiple . */
X            if(*end1 == '.')
X                if(i++)*end1 = '_'; /* After the first */
X        if((i>1||ind)&& verbose )       /* Any translations ? */
X            printf("****RENAMED: %s \n         TO: %s\n",line,fname);
X    return(ISFILE);
X}
X
X/* Create a new directory, finding out any higher levels that are missing */
X
X/* We will parse the directory name into the next higher directory, and the
X* desired directory as "desired.dir".
X* Thus: "DEV:[top.sub1.sub2]" is made into "DEV:[top.sub1]sub2.dir" . If
X* the directory does not exist , then create the original directory. There
X* may be higher levels missing, so we can recurse until we reach the top
X* level directory, then work our way back, creating directories at each
X* successive level.
X*/
X
Xint make_new(want)
Xchar want[];
X{
Xint i,len;
Xchar a[NAMSIZE],parent[NAMSIZE],*end,name[NAMSIZE];
X    strcpy(parent,want);
X    len = strlen(parent);
X    parent[len-1] =0 ;          /* Get rid of the "]" */
X    end = strrchr(parent,'.');  /* Find the last '.' */
X    if(end != NULL)
X        {
X        strcpy(a,end+1);        /* Get the last parent */
X        strcat(a,".dir");       /* Add the extension */
X        *end++ = ']' ;          /* Reduce the directory parent */
X        *end = 0;               /* Terminate the directory */
X        strcpy(name,parent);
X        strcat(name,a);
X        }
X
X    if(access(name,0) <0)       /* Does the directory exist ? */
X        {
X            if(strcmp(parent,top)!=0) /* No, are we at the top? */
X                if(make_new(parent))   /*  No, look again */
X                    return(-1); /* recurse */
X            if(mkdir(want,0755,0,0,0)) /* make it */
X                return(-1);             /* Leave on error */
X            else
X                if(verbose)
X                    printf("CREATED: %s\n",want);
X            return(0);
X        }
X    return(0);
X}
X
X /* Function to open and get data from the blocked input file */
Xint opentar()
X{
Xint fd;
X    fd = open(tarfile, 0, "rfm = fix","mrs = 512");
X    if(fd < 0)
X        {
X        printf("Can't open input file \n");
X        return(0);
X        }
X    return(fd);
X}
X
X/* Get the next file header from the input file buffer. We will always
X* move to the next 512 byte boundary.
X*/
Xint hdr_read(buffer)
Xchar *buffer;
X{
Xint stat;
X    stat = read(tarfd,buffer,DSIZE);    /* read the header */
X    return(stat);                               /* Catch them next read ? */
X}
X
X
X/* This is supposed to skip over data to get to the desired position */
X/* Position is the number of bytes to skip. We should never have to use
X* this during data transfers; just during listings. */
Xint tarskip(bytes)
Xint bytes;
X{
Xint i=0;
X    while(bytes > 0)
X        {
X        if((i=read(tarfd,buffer,DSIZE)) == 0)
X            {
X            printf("End of file encountered while skipping.\n");
X            return(-1);
X            }
X        bytes -= i;
X        }
X    return(0);
X}
X
X/* Decode the fields of the header */
X
Xint decode_header()
X{
Xint idate, *bintim;
Xchar ll;
Xbintim = &idate;
X    linktype=0; strcpy(linkname,"");
X    strcpy(pathname,header.title);
X    sscanf(header.time,"%o",bintim);
X    strcpy(creation,ctime(bintim));     /* Work on this! */
X    creation[24]=0;
X    sscanf(header.count,"%o",&bytecount);
X    sscanf(header.protection,"%o",&mode);
X    sscanf(header.field1,"%o",&uic1);
X    sscanf(header.field2,"%o",&uic2);
X    /* We may have the link written as binary or as character:  */
X    linktype = isdigit(header.linkcount)?
X            (header.linkcount - '0'):header.linkcount;
X    if(linktype != 0)
X        sscanf(header.linkname,"%s",linkname);
X    return(0);
X}
X
X
X/* remove illegal characters from directory and file names; replace
X* hyphens and commas with underscores.Returns number of translations
X* that were made.
X*/
Xvms_cleanup(string)
Xchar string[];
X{
Xint i,flag=0;
Xchar c;
X    for(i=0;c=string[i];i++)
X        {
X        switch (c)
X            {
X            case '-':           /* No hyphens in file names */
X            case ',':           /* No commas in file names  */
X                string[i]= '_';
X                flag++;         /* Record if any changes were made */
X                break;
X            default:
X                break;
X            }
X        }
X    return(flag);
X}
$ GoSub Convert_File
$ File_is="TAR2VMS.DOC"
$ Check_Sum_is=824507747
$ Copy SYS$Input VMS_SHAR_DUMMY.DUMMY
X                                        Dec.15/86
XGreetings:
X
X        Here is the program to extract files from a Tar format tape or
Xfile into a VMS system. This is a major update on  version 1.xx
Xthat I distributed earlier. The major changes:
X
X(1) It reads from either a tape or a file image of a tar tape
X(2) It transfers files as is, does NOT translate UNIX stream files to
X        the format that the VMS editor likes, but this is not a
X        problem unless you intend to edit the files. See below.
X        (The old "s" option is now the default).
X(3) It can usually leave the tape positioned ready to read another
X        Tar file from the tape. NOTE: there is a SET MAGTAPE/
X        option in VMS 4.x that will skip files to start reading in
X        the middle of a tape. The TAR2VMS program does not do any rewinds.
X(4) UNIX "linked" files are handled.
X
X        I will be glad to hear of your experiences with the code, since
Xoften when we get a Tar tape from a different system, we find something
Xthat I hadn't anticipated. The program was developed by looking at DUMP
Xoutput from various tar format tapes on a VMS system, so there are
Xundoubtedly variations that I haven't seen. ( I am not a UNIX expert..)
XWe looked at UNIX manuals as well, but found some discrepancies in real
Xtapes, so went with what seemed to work.
X
X        I also have a partially debugged version of a Tar writer; ask
Xfor it if you are willing to be a guinea pig, or need to transfer some
Xfiles to a UNIX system from VMS.
X
X
XSid Penstone,
XVLSI Group,
XDepartment of Electrical Engineering,
XQueen's University,
XKingston, Ontario, Canada, K7L3N6
Xphone (613) 545-2925
X
XBITNET:         PENSTONE@QUCDNEE1       (Preferred)
X                PENSTONE@QUCDN  (If the other doesn't work)
X
X
X
X
XNOTE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
XNOTE!!! The program must be separated at the "** CUT HERE **" lines
XNOTE!!! below before compiling.
XNOTE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
X
XIntroduction:
X
X        The program TAR2VMS.C reads from a /foreign tape,or a file
Xwhich is an image of a Tar format tape, and extracts the files into
Xa directory tree starting in the current default directory.
XDirectories will be created automatically.
XFor example, if your default is [JONES.MAIN], then the file
X"electric/sub/test.c" will be written into [JONES.MAIN.ELECTRIC.SUB]TEST.C .
X        For the simplest operation, just  RUN it after defining the
Xlogical "TAPE" to be the the Tar source and doing a
XMOUNT/FOREIGN/BLOCK=10240/RECORD=512 (if it is a tape); this
Xdoes the extraction automatically, reporting on stdout as it does.
X
X        The extracted files will be written to your system as C stream files.
XThe VMS editor EDT will complain about the format, but EVE will not.
X
X        To convert a text file to standard VMS format:
X(Thanks to Eric Gisin at U. of Waterloo:)
X        You can use the VMS CONVERT utility by first creating a xxxx.FDL file
Xcontaining:
X
XFILE
X        ORGANIZATION            sequential
XRECORD
X        BLOCK_SPAN              yes
X        CARRIAGE_CONTROL        carriage_return
X        FORMAT                  variable
X
XThen run Convert with the regular DCL:
XCONVERT/FDL=xxxx  input-file  output-file
X-------------------------------------------------------------------------
X
XUsage:
X
X        -Define the logical variable "TAPE" to be the desired tape
X         unit or the file containing the Tar data.
X
X        -Mount the tape /FOREIGN/BLOCK=10240/RECORD=512
X
X        -Set the default directory below which the tree will be created
X         before calling the program. Thus: if your default directory
X         is SYS$SYSDEVICE:[MYDIRE], the file "electric/dbase.c" will
X         be written in SYS$DEVICE:[MYDIRE.ELECTRIC]DBASE.C
X
X       -Then run TAR2VMS: (either by RUN or as a command)
X         if you use RUN, the operation is (extract, verbose)
X         otherwise:
X'command' [options]
X        where the options are:
X                "t" (listing only)       Listing of files on tape
X                "x" (extract)            Extract files from the tape
X                "v" (verbose):           Report activity
X                "w" (wait)               ...Not implemented
X    -to use the options, the program must be executed using the
X     foreign command feature of VMS, by defining a command:
Xcommand :== $path:tar2vms      !where path=complete location of tar2vms.exe
X
X        Example:
XIf the command is 'tar2vms', then:
Xtar2vms t                       will list the contents of the tar file
Xtar2vms xv                      will extract all of the files, reporting
X
XThe listing reports the UNIX protection (in octal), the file size in bytes,
Xthe modification date on the tape, and the file name.
X
XERRORS: Most probable causes:
X        "Can't open input file" - likely forgot to define TAPE, or mount
X                                        the tape.
X        "Error reading input"   - unexpected Tar format, or bad file.
X        "Error writing output " - directory access error
X        "Creation Error...   "  - illegal directory or file name
X
X--------------------------------------------------------------------------
XImportant assumptions for this version (2.1):
X
X    The defaults are (no options):
X    -Extract all of the files, reporting as each file is created
X
X    -Read from a tape, mounted foreign, or a fixed record length
X     file,with block size of 10240 bytes or less . If larger block
X     size, change the  definition of SIZE.
X
X    -Stop on the special (blank header) block written by UNIX.
X     (Note, like UNIX Tar, it does not move to the file mark at
X     the end of the file. Answer "y" to the prompt to get to another
X     tar file on the same tape.)THIS MIGHT NOT WORK...
X
X    -All files are assumed to be UNIX stream and are
X     just copied. The vms file-attribute will be "stream". This may
X     have to be changed in certain cases with CONVERT, or by writing
X     a little C program to read the file and rewrite it.
X
X    -When a UNIX linked file is encountered, there will be another
X     file on the tape that contains the actual data. It may not be an
X     earlier file that was the original file, since the files
X     are written on in alphabetical order. The program will create a
X     file under the name of the linked file, but it will contain only
X     a text messsage reporting the name of the file that contains the
X     data.
X
X
X    This version converts the path names to VMS format before creating
Xthe files. Some special cases:
X
X (1) File names with more than one period (".") in the name have those
X        after the first converted to underscores (e.g. "mults.s.c" is
X        written out under the name "mults.s_c"
X (2) It is assumed that all of the pathnames on the Tar tape have
X        complete directory info, with no device parts.
X (3) Commas and hyphens in file or directory names are converted to
X        underscores. If this causes any problems, you can modify the
X        code in vms_cleanup().Any such translations are reported in
X        "verbose" mode.
X (4) Files are created with the user's default protection. The mode on
X        the tape is ignored.
X (5) The dates of files extracted are the date of the extraction, not the
X        date of the Tar version.
X (6) unix FILES THAT HAVE NO EXTENSION, AND END IN A LETTER WILL HAVE
X        A "." ADDED TO THE NAME AUTOMATICALLY. tHIS CAN CAUSE SOME
X        MYSTERIES WITH LARGE PROGRAMS THAT LOOK FOR OTHER FILES WITH
X        AN EXACT STRING SEARCH. aLSO, IF THE FILES ARE WRITTEN OUT
X        TO unix AS A tar TAPE FROM vms, THE "." GOES ALONG WITH THE FILE
X        name.
X
X------------------------------------------------------------------------
XKnown Bugs:
X
X    - Can't always read another file on the same tape. The program
X      only works correctly when the tape had regular EOF marks on it,
X      which apparently is not always true.
X    - Can't selectively extract files from the tape. The "wait" option
X      could be useful, but haven't got around to it..
X
X
X
$ GoSub Convert_File
$ File_is="TGTAR.C"
$ Check_Sum_is=1685857467
$ Copy SYS$Input VMS_SHAR_DUMMY.DUMMY
X/* Read a TAR format tape or file , move files into VMS directories */
X/* Copyright 1986, Sid Penstone,
X*  Department of Electrical Engineering,
X*  Queen's University,
X*  Kingston, Ontario, Canada K7L3N6
X* (613)-545-5925
X* BITNET:          PENSTONE@QUCDNEE1  (Preferred)
X*       or  PENSTONE@QUCDN
X*
X* Version 2.2, Oct.21,1986
X* mods: - corrected header size (thanks to Eric Gisin, U .of Waterloo)
X*       - No more of the dreaded QIO's ( "  "  " )
X*       - tried to sort out link flag format
X*       - uses a tape or a file as input
X*       - NOTE: default is NO conversion to vms standard text format (cr)
X* 2.1   - trapped commas in file names, converted to '_'
X* 2.2   - reported translations of names
X*       - continued after error in opening output file
X*       - exit correctly on cannot open input file
X*/
X
X
X/* The input data is in record format, length 512, blocks of 10240 bytes;
X */
X
X
X#include stdio
X#include time
X#include ssdef
X#include iodef
X#include descrip
X#include ctype
X
X#define ERROR1 -1
X#define BUFFSIZE 512
X#define ISDIRE 1
X#define ISFILE 0
X#define NAMSIZE 100
X#define SIZE 10240              /* Block size */
X#define DSIZE 512               /* Data block size */
X
Xstruct                  /* A Tar header */
X    {
X    char title[NAMSIZE];
X    char protection[8];
X    char field1[8];             /* this is the user id */
X    char field2[8];             /*  this is the group id */
X    char count[12];             /*  was 11 in error */
X    char time[12];              /* UNIX format date  */
X    char chksum[8];             /* Header Checksum (ignored) */
X    char linkcount;             /* 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
Xstatic char buffer[DSIZE];      /* BUFFER for a record */
X
X/* Function flags, options:*/
Xint extract,            /* x option (default) */
X    list,                       /* t option : list tape contents */
X    verbose,            /* v option, report actions */
X    wait;
X
X/* Miscellaneous globals, etc. */
X
Xchar *tarfile = "tape", /* Input file name  */
X    pathname[NAMSIZE],  /* File name as found on tape (UNIX) */
X    directory[NAMSIZE], /* Current directory */
X    new_directory[NAMSIZE],     /* Directory of current file */
X    top[NAMSIZE],               /* Top level or root */
X    newfile[NAMSIZE],   /* VMS format of file name */
X    outfile[NAMSIZE],   /* Complete output file specification */
X    temp[256],          /* Scratch */
X    creation[NAMSIZE],  /* Date as extracted from the TAR file */
X    *ctime(),           /* System function */
X    linkname[NAMSIZE];  /* Linked file name  */
X
Xint bytecount,  mode, uic1, uic2, linktype;/* Data from header */
Xint tarfd;                      /* The input file descriptor */
X
Xmain(argc,argv)
Xint argc;
Xchar *argv[];
X{
Xint isterm,status,file_type,j,c, flag;
Xchar *make_directory(), *cp;
X
X/* Decode the options and parameters: */
X
X    if(argc ==1)
X        {
X        extract = 1;            /* Default for now */
X        verbose = 1;
X        wait = 0;               /* Don't wait for prompt */
X        }
X    while(--argc > 0)
X        {
X        cp = argv[1];
X        while(c = *cp++)
X            {
X            switch(c)
X            {
X            case 't':
X                list=1;
X                break;
X            case 'x':
X                extract=1;
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/* Find if this is a terminal */
X    isterm = isatty(0);
X
X/* Set up directory names */
X    strcpy(top,getenv("PATH"));
X
X/* Start with the default as the top */
X    strcpy(directory,top);
X
X/* open the file for reading */
X    if((tarfd = opentar()) <= 0)
X        {
X        printf("Error opening the Tar tape\n");
X        exit(2);
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        {
X        if(strlen(header.title)!=0)     /* Valid header */
X            {
X            decode_header();
X            if(extract)
X                {
X                file_type=scan_title(pathname,new_directory,newfile);
X                if( make_new(new_directory)!=0)
X                    printf("Error creating %s\n",new_directory);
X                if(file_type == ISDIRE)
X                    {}
X                if(file_type == ISFILE)
X/*  Now move the data into the output file */
X                    if(bytecount>0)
X                        {
X                        strcpy(outfile,new_directory);
X                        strcat(outfile,newfile);
X                        if((j=copyfile(outfile,bytecount))<0)
X                            printf("Error writing file %s\n",outfile);
X                        }
X                }
X            else                        /* listing only */
X                {
X                printf("%o %6d %s %s\n",
X                    mode,bytecount,creation+4,pathname);
X                if(linktype == 0)
X                    tarskip(bytecount);
X                else
X                    printf("     *****( Linked to file: %s)\n",linkname);
X                }
X            }
X        else                    /* Empty header means the end!!! */
X            {
X            status = 1;
X            printf("End of Tar file found.\n");
X            break;
X            }
X
X        }       /* end while  */
X    if(status == 1)                     /* Empty header */
X        {
X        printf("Do you wish to move past the EOF mark ? y/n\n");
X        gets(temp);
X        if(tolower(temp[0]) == 'y')
X            while((status=hdr_read(&header)) >0);
X        else
X            exit(SS$_NORMAL);
X        }
X    if(status==0)                       /* End of tar file  */
X        {
X        printf("End of file encountered\n");
X        exit(SS$_NORMAL);
X        }
X    if(status<0)                        /* An error  */
X        {
X        printf("Error reading input.\n");
X        exit(2);
X        }
X}
X
X
X/* This function simply copies the file to the output, no conversion */
X
Xint copyfile(outfile,nbytes)
Xchar outfile[]; /* name of output version */
Xint nbytes;
X
X{
Xint inbytes, fil;
X/*  Open the output file */
X    if((fil=creat(outfile,0)) == ERROR1)
X        {
X        printf(" Creation error in opening %s \n",outfile);
X        tarskip(bytecount);
X        return(-2);
X        }
X    if(linktype !=0)
X        {
X        sprintf(buffer,"This file is linked to %s\n",linkname);
X        write(fil,buffer,strlen(temp));
X        }
X    else
X        {
X        while(nbytes>0)
X            {
X            if((inbytes=read(tarfd,buffer,DSIZE)) > 0)
X                {
X                write(fil,buffer,(nbytes > DSIZE)? DSIZE:nbytes);
X                nbytes -= inbytes;
X                }
X            else
X                {
X                printf("End of input file detected\n");
X                close(fil);
X                return(-1);
X                }
X            }
X        }
X/* Close the file */
X    close(fil);
X    if(verbose)
X        {
X        printf("CREATED: %s\n",outfile);
X        if(linktype!=0)
X            printf(" *** REAL DATA IS IN: %s\n",linkname);
X        }
X    return(0);
X}
X
X/* Decode a file name into the directory, and the name, return
X* 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[],dire[],fname[];
X{
Xchar temp[NAMSIZE],*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    strcpy(dire,top);                   /* Start with the top level */
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        {                               /* End of directory name is '/' */
X        *end1 = 0;                      /* Terminate directory name */
X        strcpy(fname,end1+1);           /* File name without directory */
X        for (i=0;temp[i];i++)           /* Change '/' to '.' in directory */
X            if(temp[i]=='/')
X                temp[i]='.';
X        dire[strlen(dire)-1] = (temp[0]=='.')?0:'.' ;
X                 /* "." to indicate a subdirectory (unless already there )*/
X        strcat(dire,temp);      /* Add on the new directory  */
X        strcat(dire,"]") ;              /* And close with ']' */
X        }
X    if(strlen(fname)==0)        /* Could this cause problems ? */
X        {
X        return(ISDIRE);
X        }
X    else
X        for(i=0,end1=fname;*end1;end1++) /* Replace multiple . */
X            if(*end1 == '.')
X                if(i++)*end1 = '_'; /* After the first */
X        if((i>1||ind)&& verbose )       /* Any translations ? */
X            printf("****RENAMED: %s \n         TO: %s\n",line,fname);
X    return(ISFILE);
X}
X
X/* Create a new directory, finding out any higher levels that are missing */
X
X/* We will parse the directory name into the next higher directory, and the
X* desired directory as "desired.dir".
X* Thus: "DEV:[top.sub1.sub2]" is made into "DEV:[top.sub1]sub2.dir" . If
X* the directory does not exist , then create the original directory. There
X* may be higher levels missing, so we can recurse until we reach the top
X* level directory, then work our way back, creating directories at each
X* successive level.
X*/
X
Xint make_new(want)
Xchar want[];
X{
Xint i,len;
Xchar a[NAMSIZE],parent[NAMSIZE],*end,name[NAMSIZE];
X    strcpy(parent,want);
X    len = strlen(parent);
X    parent[len-1] =0 ;          /* Get rid of the "]" */
X    end = strrchr(parent,'.');  /* Find the last '.' */
X    if(end != NULL)
X        {
X        strcpy(a,end+1);        /* Get the last parent */
X        strcat(a,".dir");       /* Add the extension */
X        *end++ = ']' ;          /* Reduce the directory parent */
X        *end = 0;               /* Terminate the directory */
X        strcpy(name,parent);
X        strcat(name,a);
X        }
X
X    if(access(name,0) <0)       /* Does the directory exist ? */
X        {
X            if(strcmp(parent,top)!=0) /* No, are we at the top? */
X                if(make_new(parent))   /*  No, look again */
X                    return(-1); /* recurse */
X            if(mkdir(want,0755,0,0,0)) /* make it */
X                return(-1);             /* Leave on error */
X            else
X                if(verbose)
X                    printf("CREATED: %s\n",want);
X            return(0);
X        }
X    return(0);
X}
X
X /* Function to open and get data from the blocked input file */
Xint opentar()
X{
Xint fd;
X    fd = open(tarfile, 0, "rfm = fix","mrs = 512");
X    if(fd < 0)
X        {
X        printf("Can't open input file \n");
X        return(0);
X        }
X    return(fd);
X}
X
X/* Get the next file header from the input file buffer. We will always
X* move to the next 512 byte boundary.
X*/
Xint hdr_read(buffer)
Xchar *buffer;
X{
Xint stat;
X    stat = read(tarfd,buffer,DSIZE);    /* read the header */
X    return(stat);                               /* Catch them next read ? */
X}
X
X
X/* This is supposed to skip over data to get to the desired position */
X/* Position is the number of bytes to skip. We should never have to use
X* this during data transfers; just during listings. */
Xint tarskip(bytes)
Xint bytes;
X{
Xint i=0;
X    while(bytes > 0)
X        {
X        if((i=read(tarfd,buffer,DSIZE)) == 0)
X            {
X            printf("End of file encountered while skipping.\n");
X            return(-1);
X            }
X        bytes -= i;
X        }
X    return(0);
X}
X
X/* Decode the fields of the header */
X
Xint decode_header()
X{
Xint idate, *bintim;
Xchar ll;
Xbintim = &idate;
X    linktype=0; strcpy(linkname,"");
X    strcpy(pathname,header.title);
X    sscanf(header.time,"%o",bintim);
X    strcpy(creation,ctime(bintim));     /* Work on this! */
X    creation[24]=0;
X    sscanf(header.count,"%o",&bytecount);
X    sscanf(header.protection,"%o",&mode);
X    sscanf(header.field1,"%o",&uic1);
X    sscanf(header.field2,"%o",&uic2);
X    /* We may have the link written as binary or as character:  */
X    linktype = isdigit(header.linkcount)?
X            (header.linkcount - '0'):header.linkcount;
X    if(linktype != 0)
X        sscanf(header.linkname,"%s",linkname);
X    return(0);
X}
X
X
X/* remove illegal characters from directory and file names; replace
X* hyphens and commas with underscores.Returns number of translations
X* that were made.
X*/
Xvms_cleanup(string)
Xchar string[];
X{
Xint i,flag=0;
Xchar c;
X    for(i=0;c=string[i];i++)
X        {
X        switch (c)
X            {
X            case '-':           /* No hyphens in file names */
X            case ',':           /* No commas in file names  */
X                string[i]= '_';
X                flag++;         /* Record if any changes were made */
X                break;
X            default:
X                break;
X            }
X        }
X    return(flag);
X}
$ GoSub Convert_File
$ 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
$ Goto Part2

Dick_Alrutz.WBST147@Xerox.COM, info-vax@kl.sri.COM (03/29/88)

Sid,
	I have been looking for the updates to tar, and received 1 and not the second
in the 5.03 distribution. I also noticed a fix sent along recently. Can you
resend parts 1 & 2  with the fix?

Thank you,

Dick

pjh@mccc.UUCP (Peter J. Holsberg) (04/08/88)

Does anyone have a VMS utility that will read a UNIX TAR-formatted
9-track tape?  I'd appreciate a mailing or a posting.  Thank you.

-- 
Peter Holsberg                  UUCP: {rutgers!}princeton!mccc!pjh
Technology Division             CompuServe: 70240,334
Mercer College                  GEnie: PJHOLSBERG
Trenton, NJ 08690               Voice: 1-609-586-4800