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 Part2Dick_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