-+-+-+-+-+-+-+-+ START OF PART 2 -+-+-+-+-+-+-+-+ X value += *ptr; /* make the checksum */ X for(ptr = &header.linkcount; ptr <= &header.dummy`5B255`5D; ptr++) X value += *ptr; X value += (8 * ' ');`09 /* checksum considered as all space Vs */ X X if (chksum != value) X `7B /* abort if incorrect */ X printf("tar: directory checksum error for %s\n",pathname); X exit(1); X `7D X X X/* We may have the link written as binary or as character: */ X 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`7D X X X/* vms_cleanup -- removes illegal characters from directory and file names X * Replaces hyphens and commas with underscores. Returns number of translati Vons X * that were made. X */ X Xvms_cleanup(string) Xchar string`5B`5D; X`7B X int i,flag=0; X char c; X X for(i=0; c=string`5Bi`5D; ++i) X `7B X if (strchr(badchars, c) != NULL) X `7B /* Replace illegal characters by underscores V */ X string`5Bi`5D= '_'; X flag++; /* Record if any changes were made */ X `7D X else X string`5Bi`5D = toupper(c); /* Map to uppercase */ X `7D X return(flag); X`7D X X/* vms2tar -- handles create function */ X Xvms2tar(argc,argv) Xint argc; Xchar **argv; X`7B X int argi, process, file_type, absolute; X char string`5BNAMSIZE`5D, *cp, *dp, *wp; X X if (argc < 3 `7C`7C (foption && argc < 4)) usage(); X X bufferpointer = 0; X gid = getgid(); X uid = getuid(); X mode = 0644; X X/* Open the output file */ X X outfd = creat(tarfile,0600,"rfm=fix","mrs=512"); X if (outfd < 0) X `7B X printf("tar: error opening output tarfile %s\n", tarfile); X exit(SS$_NORMAL); X `7D `20 X X for (argi = foption ? 3 : 2; argi < argc; ++argi) X `7B X strcpy(string, argv`5Bargi`5D); X absolute = 0; X cp = strchr(string, ':'); /* device name in argument ? */ X if (cp != NULL) /* yes, force absolute mode */ X absolute = 1; X else X `7B X cp = strchr(string, '`5B'); /* test argument for absolute... */ X if (cp != NULL) /* ...or relative filespec */ X `7B X ++cp; X if (*cp != '.' && *cp != '-') X absolute = 1; X `7D X `7D X if(initsearch(string) <= 0) X printf("tar: no files matching %s\n",string); X else X while(search(newfile,NAMSIZE)!=0) X `7B X strcpy(linkname, newfile); X cleanup_dire(newfile); X file_type = scan_name(newfile,new_directory,outfile,absolute); X strcpy(pathname,new_directory); X strcat(pathname,outfile); X get_attributes(newfile); X process = 1; X if(wait) X `7B X *temp = '\0'; X while (*temp != 'y' && *temp != 'n') X `7B X printf("%s (y/n) ? ", linkname); X scanf("%s", temp); X *temp = tolower(*temp); X `7D X process = (*temp == 'y'); X `7D X if (process) X `7B X if(file_type == ISDIRE) X `7B X bytecount = 0; X mode = 0755; X fill_header(pathname); X write_header(outfd); X `7D X if(file_type == ISFILE) X `7B X mode = 0644; X if(addfile(newfile, pathname) < 0) X `7B X printf("tar:error copying %s\n",linkname); X exit(SS$_NORMAL); X `7D X `7D X if (bytecount == 0 && file_type == ISFILE) X printf("*** skipped %s\n", linkname); X if (verbose && (bytecount `7C`7C file_type == ISDIRE)) X `7B X strcpy(creation,ctime(&vmstime)); /* work on this */ X creation`5B24`5D=0; X printf("%s %6d %s\n",creation + 4,bytecount,pathname); X `7D X `7D X `7D X `7D X write_trailer(outfd); X close(outfd); X`7D X X/* addfile - copy the vms file to the output file */ X Xint addfile(vmsname,unixname) Xchar vmsname`5B`5D,unixname`5B`5D; X`7B 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`7D X X X/* out_file - 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* read the file twice in case of a text file X* so that we get the correct byte count. X* We set the bytecount=0 if this is funny file. X*/ X Xint out_file(filename,nbytes,fdout) Xchar filename`5B`5D; Xint fdout, nbytes; X`7B Xint i, n, pos, fdin; Xchar *bufp, *linep; XFILE *filein; X X if(vmsrfm == FIXED) X `7B X if((fdin=open(filename,0)) <=0) X `7B X printf("tar: error opening input file %s\n",filename); X return(-1); X `7D X fill_header(pathname); /* We have all of the information */ X write_header(outfd); /* So write to the output */ X while(nbytes > 0) X `7B X n = read(fdin,buffer,nbytes>DSIZE? DSIZE:nbytes); X if(n<0) X `7B X close(fdin); X printf("tar: error reading input file %s\n",filename); X return(-1); X `7D X nbytes -= n; X flushout(fdout); X `7D X close(fdin); X return(0); X `7D X else X if(vmsrat != 0) /* must be a text file */ X `7B /* compute "Unix" file size */ X if((filein = fopen(filename,"r")) == NULL) X `7B X printf("tar: error opening input file %s\n",filename); X return(-1); X `7D X nbytes = 0; X while(fgets(dbuffer,DSIZE,filein) != NULL) X nbytes += strlen(dbuffer); X rewind(filein); /* 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 bufp = buffer; X X while(fgets(dbuffer,DSIZE,filein) != NULL) X `7B /* Now copy to the output */ X linep = dbuffer; X while (*linep != '\0') /* read source file line by line V */ X `7B X *bufp++ = *linep++; /* copy in fixed size output buffer V */ X if (bufp >= &buffer`5BDSIZE`5D) X `7B X bufp = buffer; X flushout(fdout); /* if buffer full, flush it V */ X `7D X `7D X `7D X flushout(fdout); X fclose(filein); X return(0); X `7D X /* Other formats e.g. .OBJ are not done */ X bytecount = 0; X return(0); X`7D X X/* flushout - write a fixed size block in output tarfile */ X Xflushout(fdout) Xint fdout; X`7B X if (write(fdout,buffer,DSIZE) != DSIZE) X `7B X printf("tar: error writing tarfile.\n"); X exit(SS$_NORMAL); X `7D X bufferpointer += DSIZE; X`7D X X/* write_header - copy the header to the output file */ X Xint write_header(fd) Xint fd; X`7B Xint n; X if((n=write(fd,&header,DSIZE))!=DSIZE) X `7B X printf("tar: error writing header in tarfile.\n"); X exit(SS$_NORMAL); X `7D X bufferpointer += DSIZE; X return(n); X`7D X X/* get_attributes - get the file attributes via stat() */ X Xint get_attributes(fname) Xchar fname`5B`5D; X`7B X if(stat(fname,&sblock)) X `7B X printf("tar: can't get file status on %s\n",fname); X vmstime = 0; /* Prevent garbage printoout */ X bytecount = 0; /* of inaccessible files */ X return(-1); X `7D 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`7D X X X/* write_trailer - write the two blank blocks on the output file */ X/* pad the output to a full blocksize if needed. */ X Xwrite_trailer(fdout) Xint fdout; X`7B Xint i; X for (i=0; i < NAMSIZE; ++i) X header.title`5Bi`5D = '\0'; X write_header(fdout); X write_header(fdout); X bufferpointer = bufferpointer%BLKSIZE; X while (bufferpointer < BLKSIZE) X write_header(fdout); X return(1); X`7D X X/* scan_name - decode a file name */ 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,absolute) Xchar line`5B`5D,dire`5B`5D,fname`5B`5D; Xint absolute; X`7B Xchar *cp1,*cp2; Xint len,len2,i; Xchar *strindex(); X 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* '`5B' and '`5D'. X* If the name ends with '.dir;1' then it is actually a directory name. X* The outputs dire and fname will be a complete file spec, based on the def Vault X* directory. X* It may be a rooted directory, in which case there will be a "`5D`5B" strin Vg, X* remove it. X* Strip out colons from the right, in case there is a node name (should not V be!) X* If the filename ends in a trailing '.', suppress it , unless the "d" optio Vn X* is set. X*/ X X X strcpy(temp,strrchr(line,':')+1); /* Start with the whole name V */ X X/* If relative path, get rid of default directory part of the name */ X X if (absolute == 0) X `7B X strcpy(dire,"./"); X for(cp1 = temp ,cp2 = curdir; *cp2 && (*cp1 == *cp2); X cp1++, cp2++); X if(*cp2 == 0) X *cp1 = 0; /* Perfect match, no directory spec */ X else X `7B X switch(*cp1) X `7B X case '.': X case '`5B': /* Legal beginnings or ends */ X break; X default: /* We are above the default, use full name * V/ X cp1 = strchr(temp,'`5B'); /* Fixed this from 1.5 */ X *dire = '\0'; X break; X `7D X cp1++; /* Get past the starting . or `5B */ X `7D X strcat(dire, cp1); X `7D X else X strcpy(dire, temp + 1); X cp1 = strrchr(dire, '`5D'); /* change trailing directory mark */ X if (cp1 != NULL) X `7B X *cp1++ = '/'; X *cp1 = '\0'; /* and terminate string (no file name) * V/ X `7D X strcpy(temp,strrchr(line,'`5D')+1); /* Now get the file name */ X if((cp1=strindex(temp,".DIR;1"))!=0) X `7B X *cp1++ = '/'; /* Terminate directory name * V/ X *cp1 = '\0'; X strcat(dire,temp); X *fname = '\0'; X `7D X else X `7B X strcpy(fname,temp); X *strchr(fname,';') = '\0';; /* no version numbers */ X lowercase(fname); /* map to lowercase */ X `7D X X /* Now rewrite the directory name */ X X lowercase(dire); X X for (cp1 = dire + 1; *cp1; ++cp1) /* Change '.' to '/' */ X if(*cp1 == '.') X *cp1 = '/'; X if((len=strlen(fname))==0) X return(ISDIRE); X else X if(fname`5B--len`5D == '.') X if (dot == 0) X fname`5Blen`5D = 0; /* No trailing dots */ X return(ISFILE); X`7D X/* initsearch - parse input file name */ 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`5B`5D; X`7B Xint status; Xchar *strindex(); X X if(strindex(string,"::")!=NULL) X `7B X printf("tar: DECnet file access is not supported.\n"); X return(-1); X `7D 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 `7B X if(status == RMS$_DNF) X printf("tar: directory not found %s\n",searchname); X else X printf("tar: error in SYS$PARSE.\n"); X return (-1); X `7D X searchname`5Bnblock.nam$b_esl`5D = 0; /* Terminate the string */ X X /* Now reset for searching, pointing to the parsed name block */ X X fblock = cc$rms_fab; X fblock.fab$l_nam = &nblock; X return(nblock.nam$b_esl); /* return the length of the string */ X`7D X X/* search - get the next file name that matches the namblock */ X/* that was set up by the sys$search() function. */ X Xint search(buff,maxlen) Xchar buff`5B`5D; Xint maxlen; X`7B 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 `7B X buff`5Bnblock.nam$b_rsl`5D = 0; X if(status == RMS$_NORMAL) X return(nblock.nam$b_rsl); X else X `7B X if (status == RMS$_PRV) X printf("tar: no privilege to access %s\n",buff); X else if (status == RMS$_FNF) X printf("tar: file not found %s\n",buff); X else X `7B X printf("tar: error in SYS$SEARCH for %s\n", buff); X return (0); X `7D X `7D X `7D X return (0); X`7D X/* fill_header - fill the fields of the header */ X/* enter with the file name, if the file name is empty, */ X/* then this is a trailer, and we should fill it with zeroes. */ X Xint fill_header(name) Xchar name`5B`5D; X`7B Xint i,chksum; Xint zero = 0, hdrsize = DSIZE; Xchar *ptr,tem`5B15`5D; X X/* Fill the header with zeroes */ X X LIB$MOVC5(&zero, &zero, &zero, &hdrsize, &header); `20 X if(strlen(name)!=0) /* only fill if there is a file */ X `7B 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 X/* I know that the next two are already zero, but do them */ X X header.linkcount = 0; /* always zero */ X sprintf(header.linkname,"%s",""); /* always blank */ X for(chksum=0, ptr = &header;ptr < &header.linkcount;ptr++) X chksum += *ptr; /* make the checksum */ X sprintf(header.chksum,"%6o",chksum); X `7D X return(0); X`7D X X/* strindex - search for string2 in string1, return address pointer */ X Xchar *strindex(string1,string2) Xchar *string1,*string2; X`7B Xchar *c1, *c2, *cp; X for(c1 = string1; *c1 !=0; c1++) X `7B 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 `7D X return(NULL); X`7D X X/* lowercase - function to change a string to lower case */ X Xint lowercase(string) Xchar string`5B`5D; X`7B Xint i; X for(i=0;string`5Bi`5D=tolower(string`5Bi`5D);i++); X return (--i); /* return string length */ X`7D X X/* cleanup_dire - routine to get rid of rooted directory problems */ X/* and any others that turn up */ X Xint cleanup_dire(string) Xchar string`5B`5D; X`7B Xchar *ptr; X if((ptr=strindex(string,"`5D`5B")) != NULL) X `7B /* Just collapse around the string */ X strcpy(ptr,ptr+2); X return(1); X `7D X if((ptr=strindex(string,"`5B000000.")) != NULL) X `7B /* remove "000000." */ X strcpy(ptr + 1, ptr + 8); X return(1); X `7D X return(0); X`7D X X/* Syntax error exit */ X Xusage() X`7B X printf("usage: tar x`7Cc`7Ct`5Bvbd`5D`5Bf tarfile`5D `5Bfile `5Bfile...` V5D`5D\n"); X exit(1); X`7D $ CALL UNPACK VMSTAR.C;37 1144747505 $ create 'f' X1 VMSTAR X X VMSTAR is a TAR reader/writer for VMS. It can read archives X ("tarfiles") created by the Un*x command "tar" (VMSTAR has a similar X syntax) and also create such archives so that they can be read later X by a Un*x system. Tarfiles can be VMS disk files or directly on tape. X Default tarfile is whatever the logical name "$TAPE" points to X (either device or file name) unless specified by the "f" modifier. X X Tapes read/written by VMSTAR must be mounted /FOREIGN/RECORD=512/BLOCK=1024 V0 X X Usage: $ VMSTAR `5Boptions`5D `5Bfilespec `5Bfilespec...`5D`5D X2 Options X Options are single letters grouped together (no space). There must be X at list one of "x" (extract), "t" (type) or "c" (create) to indicate X what kind of action VMSTAR should have. Other single letters are X modifiers. The group of options may optionally include a leading "-" X (dash). X3 x (extract) X This option instructs VMSTAR that files are to be extracted from the X tar archive and copied as VMS files. One or more Un*x-like file X specifications including VMS wildcard characters may be present on X the command line. Only files matching one of the patterns will be X actually extracted. Default is to extract all files. X X VMSTAR will attempt to re-create the directory hierarchy present in X the tar archive. If files are named "./foo/bar..." in the tar archive X (common case) the VMS directory tree will be created relative to X current default. All illegal characters in file names will be X replaced by "_" (underscore). X3 t (type) X This option produces a listing of the contents of the tar archive, X including file name (Un*x style), size (in bytes) and modification X date. X3 c (create) X This option directs VMSTAR to create a tar archive and to copy VMS X files as directed by file specification(s) into this archive in such X a way it can be further extracted on an Un*x machine. File X specifications (space separated, no commas) can include standard VMS X wildcards in file and directory name. X X If a relative specification is given (no directory or directory X beginning with "`5B." and no device name), the file name given is the X tar archive will be relative too (not beginning with "/") X3 v (verbose) X Adding this modifier to a "x" or "c" option will cause VMSTAR to X display file names and sizes stored when archiving VMS files and VMS X directory and file names created when extracting from an archive. X3 w (wait) X VMSTAR asks for a confirmation before each file is archived or X extracted when this modifier is specified. X3 b (binary) X This modifier is meaningful only when VMSTAR extracts files from a X tar archive. If it is specified, VMSTAR will create VMS files in X fixed format, record size = 512 bytes and no record attributes. Use X the "b" modifier when you extract compressed files, tar archives, X executable VMS images or any kind of files other than ASCII files X with line-feed terminated lines. X X When this modifier is *NOT* present, VMS files are created as X stream-LF files with implied (CR) record attributes. X3 d (dots) X This modifier is only meaningful for the "c" (create) option. When it X is specified, VMSTAR will keep the trailing dot in file names without X extension in the archive. X3 f tarfile X This modifier allows to specify the tarfile (either VMS file name of X VMS device name) read or written by VMSTAR. Default is whatever the X logical name $TAPE points to, either file or device. X2 Filespec X One or more file specifications may be present on the command line as X last arguments. They must be separated by spaces, *NOT* commas like X in most VMS commands. They may include VMS wildcard characters "*" X and "%". Case is never significant. X X Upon create, the file specifications must be valid VMS file or X directory names. If only a directory name is specified, "*.*;" is X automatically appended. The resultant specifications are the names of X the VMS file names that will be archived in the tarfile. Use of X device names and absolute paths ("`5BFOO.BAR`5D") is strongly discouraged X unless absolute archives are to be created (see "c" option). X X Upon extract, the file specifications must be Un*x file names or X patterns for Un*x file names using VMS wildcard characters. Files in X the tarfile having names matching one of the specifications will be X extracted. If no specification is given, all files are extracted. X Matching is done using pure wildcarded strings matching algorithms, X i.e. "/" is a normal character. X2 Examples X $ MOUNT/FOREIGN/RECORD=512/BLOCK=10240 X $ VMSTAR TVF MUA0: X X Will give a full listing of the tar tape loaded in MUA0: X X $ SET DEF `5BFOO_ROOT`5D X $ TAR XVF MUA0: X X Will extract files from the tar tape in `5BFOO_ROOT...`5D provided the X files in the tar archive do not begin with "/". X X $ DEFINE $TAPE MUA0: X $ TAR XV *SOURCES/*.C X X Will only extract C source files in the subdirectory "sources" (or X "Sources" or "SOURCES", case is not significant) from the tar tape X mounted in MUA0: X X $ TAR XVF EMACS.TAR X X Will extract files in tar archive file EMACS.TAR which may has been X transmitted from a Un*x system by network. X X $ TAR XVBF EMACS.TAR ./EXECUTABLE/EMACS.EXE X X Will only extract the specified file and create it as a VMS fixed X format, record size = 512 bytes, no record attributes file. X X $ TAR CWVF MUA0: `5B.GNUCC...`5D X X Will archive the contents of the whole "`5B.GNUCC...`5D" subtree in a X tape tar archive on MUA0:. VMSTAR will prompt user before archiving X each file. X X $ DEFINE $TAPE TARFILE.TAR X $ TAR CV *.DOC `5B.GNUCC...`5D X X Will create a tar archive file TARFILE.TAR and write all files with X type ".DOC" and all the "`5B.GNUCC...`5D" subtree in it. X2 Restrictions X Because of diffrences in the Un*x and VMS filesystems, some files may X fail to be correctly transferred to/from the tarfile. This can be X caused by : X X - restrictions in VMS file naming scheme: extra dots in file names X will be mapped to underscores, dummy directory names will be X generated if archive contains more than 8 levels of subdirectories, X links are extracted as empty files containing only a short message X "this file is only a link to...", all file names are mapped to X uppercase etc. X X - restrictions of the Un*x filesystem: tar will only get the latest X version of a VMS file to enter it into the archive, no trace of the X orginal file device name is kept in the archive. X X - VMS strong file typing: VMSTAR can only safely tranfer back and X forth VMS "text" files (rfm=vfc or stream_lf with rat=cr) or VMS X fixed size record, 512 bytes/record, rat=none files (e.g. .EXE image X files). VMSTAR will skip other file types (this includes .OBJ and X library files, they *can't* be archived). X X Other restrictions: X X RMS file attributes are lost in the archive process, text files are X archived as , fixed files are archived as is. X X VMSTAR will always restore files relative to your current RMS default X if names in tarfile do not begin by `60/'. If file names in tarfile X begin with a `60/' (bad practice), an attempt will be made to restore X files to the absolute path. There is currently no way to explicitely X specify the target VMS directory where files should be extracted. X X No attempt has been made to handle search list as RMS defaults (e.g. X SYSTEM account). Be very careful about that. $ CALL UNPACK VMSTAR.HLP;9 540810232 $ v=f$verify(v) $ EXIT