$!/* acf4:vmsnet.sources / tp@mccall.com / 9:12 am Sep 24, 1990 */ $!Submitted-by: FAUCONNE@FRSIM51.BITNET (Alain Fauconnet) $!Archive-name: vmstar/part1 $! $! ------------------ CUT HERE ----------------------- $ v='f$verify(f$trnlnm("SHARE_VERIFY"))' $! $! This archive created by VMS_SHARE Version 7.2-007 22-FEB-1990 $! On 24-SEP-1990 13:09:12.49 By user TP $! $! This VMS_SHARE Written by: $! Andy Harper, Kings College London UK $! $! Acknowledgements to: $! James Gray - Original VMS_SHARE $! Michael Bednarek - Original Concept and implementation $! $! TO UNPACK THIS SHARE FILE, CONCATENATE ALL PARTS IN ORDER $! AND EXECUTE AS A COMMAND PROCEDURE ( @name ) $! $! THE FOLLOWING FILE(S) WILL BE CREATED AFTER UNPACKING: $! 1. AAAREADME.TXT;5 $! 2. VMSTAR.C;36 $! $set="set" $set symbol/scope=(nolocal,noglobal) $f=f$parse("SHARE_TEMP","SYS$SCRATCH:.TMP_"+f$getjpi("","PID")) $e="write sys$error ""%UNPACK"", " $w="write sys$output ""%UNPACK"", " $ if f$trnlnm("SHARE_LOG") then $ w = "!" $ ve=f$getsyi("version") $ if ve-f$extract(0,1,ve) .ges. "4.4" then $ goto START $ e "-E-OLDVER, Must run at least VMS 4.4" $ v=f$verify(v) $ exit 44 $UNPACK: SUBROUTINE ! P1=filename, P2=checksum $ if f$search(P1) .eqs. "" then $ goto file_absent $ e "-W-EXISTS, File ''P1' exists. Skipped." $ delete 'f'* $ exit $file_absent: $ if f$parse(P1) .nes. "" then $ goto dirok $ dn=f$parse(P1,,,"DIRECTORY") $ w "-I-CREDIR, Creating directory ''dn'." $ create/dir 'dn' $ if $status then $ goto dirok $ e "-E-CREDIRFAIL, Unable to create ''dn'. File skipped." $ delete 'f'* $ exit $dirok: $ w "-I-PROCESS, Processing file ''P1'." $ if .not. f$verify() then $ define/user sys$output nl: $ EDIT/TPU/NOSEC/NODIS/COM=SYS$INPUT 'f'/OUT='P1' PROCEDURE Unpacker ON_ERROR ENDON_ERROR;SET(FACILITY_NAME,"UNPACK");SET( SUCCESS,OFF);SET(INFORMATIONAL,OFF);f:=GET_INFO(COMMAND_LINE,"file_name");b:= CREATE_BUFFER(f,f);p:=SPAN(" ")@r&LINE_END;POSITION(BEGINNING_OF(b)); LOOP EXITIF SEARCH(p,FORWARD)=0;POSITION(r);ERASE(r);ENDLOOP;POSITION( BEGINNING_OF(b));g:=0;LOOP EXITIF MARK(NONE)=END_OF(b);x:=ERASE_CHARACTER(1); IF g=0 THEN IF x="X" THEN MOVE_VERTICAL(1);ENDIF;IF x="V" THEN APPEND_LINE; MOVE_HORIZONTAL(-CURRENT_OFFSET);MOVE_VERTICAL(1);ENDIF;IF x="+" THEN g:=1; ERASE_LINE;ENDIF;ELSE IF x="-" THEN IF INDEX(CURRENT_LINE,"+-+-+-+-+-+-+-+")= 1 THEN g:=0;ENDIF;ENDIF;ERASE_LINE;ENDIF;ENDLOOP;t:="0123456789ABCDEF"; POSITION(BEGINNING_OF(b));LOOP r:=SEARCH("`",FORWARD);EXITIF r=0;POSITION(r); ERASE(r);x1:=INDEX(t,ERASE_CHARACTER(1))-1;x2:=INDEX(t,ERASE_CHARACTER(1))-1; COPY_TEXT(ASCII(16*x1+x2));ENDLOOP;WRITE_FILE(b,GET_INFO(COMMAND_LINE, "output_file"));ENDPROCEDURE;Unpacker;QUIT; $ delete/nolog 'f'* $ CHECKSUM 'P1' $ IF CHECKSUM$CHECKSUM .eqs. P2 THEN $ EXIT $ e "-E-CHKSMFAIL, Checksum of ''P1' failed." $ ENDSUBROUTINE $START: $ create 'f' X General information X ------------------- X XVMSTAR is a TAR reader/writer for VMS. It can read archives ("tarfile Vs") Xcreated by the Un*x command "tar" and also create such archives. Tarfiles V can Xbe disk files or directly on tape. X XVMSTAR is based on the TAR2VMS and VMS2TAR programs written by: 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 XThe extra work has been done by: X XAlain Fauconnet XSIM/INSERM U194 (complete address at the end of this file) XPARIS - FRANCE X XBitnet: FAUCONNE@FRSIM51 X XTAR2VMS and VMS2TAR have been merged into a single program. I made seve Vral Ximprovements, bug fixes and message cleanup. For those who know TAR2VMS V and XVMS2TAR, the main differences are: X X- everything is now in a single program that can be used for extracting file Vs Xfrom tar archives, listing the contents of tar archives or creating them. X X- VMSTAR now accepts a `60f tarfile' option to explicitely specify the tarfi Vle Xname (either a VMS file name or a VMS device name). X X- if this option is not used, the logical name "$TAPE" is translated. X X- checksums are verified at file extraction. X X- VMSTAR will extract files from archives as VMS rfm=stream_lf, rat=cr files V, Xexcept if new option `60b' is specified. In this case, extracted files ared Xcreated as rfm=fixed, mrs=512, rat=none i.e. suitable for compressed files t Vo Xbe decompressed using LZDCMP or for VMS images. X X- VMSTAR has a more Un*x-like syntax, if several file names are specified as Xcommand line parameters they must be separated by spaces (not commas) and th Vere Xis not context propagation "a la BACKUP". X X- VMSTAR allows VMS-style wildcarded strings for Un*x-style file names to V be Xspecified when extracting from a tar archive, e.g. : X X$ tar xvf foo.tar */source/*/sa%%%.c X X- VMSTAR will attempt to create relative tar archives i.e. archives where Xfilenames are recorded as "./foo/bar/baz" whenever possible. This can be Xspecifically avoided by having a device name in file name argument, e.g. : X X$ tar cvf foo.tar DISK$USERS`5B...`5D*.c X Xor specifying an absolute VMS file specification, e.g. : X X$ tar cvf foo.tar `5BSMITH.C...`5D X X- VMSTAR will handle tar archives which when restored would create more than V 8 Xlevels of directories (the X11 distribution from MIT for instance !). Excess Vive Xlevels of directories will be resolved as follows: X Xd1/d2/d3/d4/d5/d6/d7/d8/d9/foo -> `5BD1.D2.D3.D4.D5.D6.D7.D8$D9`5DFOO X X- VMSTAR no longer requires the creation of an intermediate scratch file whe Vn Xarchiving text files as VMS2TAR did. X X- VMSTAR does *not* allow to read tarfiles past the EOF mark as TAR2VMS did. X X- the `60w' option (same as "/CONFIRM" for VMS commands) has been implemente Vd for Xcreate archive and extract functions. X X- many other differences, the code has been extensively reworked with Xsimplification as a goal. This probably caused the introduction of some bugs V... X X X Build and installation instructions X ----------------------------------- X XCompile and link VMSTAR.C as follows: X X$ CC VMSTAR X$ LINK VMSTAR,SYS$INPUT:/OPT XSYS$SHARE:VAXCRTL/SHARE X X XDefine a foreign command symbol in SYLOGIN.COM: X X$ VMSTAR :== $ VMSTAR X XI used VAX/VMS C V3.1 to build VMSTAR. I have no idea whether it can be buil Vt Xusing other versions or other compilers... X X Usage X ----- X X tar x`7Ct`7Cc`5Bv`5D`5Bw`5D`5Bb`5D`5Bd`5D`5Bf tarfile`5D `5Bfile `5B Vfile...`5D`5D X x - extract from tarfile, create VMS files X t - type directory of tarfile X c - create tarfile, archive VMS files X v - verbose (list names of files being archived/extracted) X w - wait for confirmation before extracting/archiving X b - binary mode extract, create (rfm=fixed, rat=none, mrs=512) files X d - keep trailing dots in file names X f - specify tarfile name, default is $TAPE X file - space-separated list of file names, can include VMS-style X string wildcards on extract, can be any VMS file name X specification (except DECnet) on create archive. X X XTapes for reading/writing of tarfiles should be mounted X/FOREIGN/RECORD=512/BLOCK=10240 X XExample: X X$ MOUNT/FOREIGN/RECORD=512/BLOCK=10240 MUA0: "" $TAPE X$ VMSTAR XV X X Restrictions X ------------ X XBecause of diffrences in the Un*x and VMS filesystems, some files may fail V to Xbe correctly transferred to/from the tarfile. This can be caused by V : X X- restrictions in VMS file naming scheme: extra dots in file names will be Xmapped to underscores, dummy directory names will be generated if archive Xcontains more than 8 levels of subdirectories, links are extracted as empty Xfiles containing only a short message "this file is only a link to...", all Xfile names are mapped to uppercase etc. X X- restrictions of the Un*x filesystem: tar will only get the latest version V of Xa VMS file to enter it into the archive, no trace of the orginal file device Xname is kept in the archive. X X- VMS strong file typing: VMSTAR can only safely tranfer back and forth`20 XVMS "text" files (rfm=vfc or stream_lf with rat=cr) or VMS fixed size record V, X512 bytes/record, rat=none files (e.g. .EXE image files). XVMSTAR will skip other file types (this includes .OBJ and library files, Xthey *can't* be archived). X XOther restrictions: X XRMS file attributes are lost in the archive process, text files are archived V as X, fixed files are archived as is. X XVMSTAR will always restore files relative to your current RMS default if na Vmes Xin tarfile do not begin by `60/'. If file names in tarfile begin with a `60 V/' (bad Xpractice), an attempt will be made to restore files to the absolute path. Th Vere Xis currently no way to explicitely specify the target VMS directory where fi Vles Xshould be extracted. X XNo attempt has been made to handle search list as RMS defaults (e.g. SYS VTEM Xaccount). Be very careful about that. X XThe current version of VMSTAR has *not* been fully tested. I proba Vbly Xintroduced many bugs not existing in Sid Penstone's programs. VMSTAR V is Xprovided "as-is", I cannot guarantee it will do what you want or even what i Vt's Xsupposed to do but I'd like to hear about it if you have problems. If V you Xreport a problem, don't bother with providing me a fix but *do* try to V be Xprecise on what happened and how it happened. X X X+-------------------------------------------------------------------------+ X`7C Alain ("HAL 1") Fauconnet Research laboratory in medical informatics V `7C X`7C System Manager (expert systems, NL proc., statistics...) V `7C X`7C SIM/INSERM U194 EARN/Bitnet: FAUCONNE@FRSIM51 V `7C X`7C Faculte de Medecine VMS PSI Mail: PSI%+208075090517::FAUCONNET V `7C X`7C 91 Boulevard de l'Hopital FAX: (+33) 1-45-86-56-85 V `7C X`7C 75634 PARIS CEDEX 13 FRANCE PTT net: (+33) 1-45-85-15-29 V `7C X`7C "HAL... open the door, please!" (2001 Space Odyssey) V `7C X`7C Disclaimer: This is machine-generated random text, no meaning at all. V `7C X+-------------------------------------------------------------------------+ $ CALL UNPACK AAAREADME.TXT;5 1596691805 $ create 'f' X/* X *`09VMSTAR.C - a Un*x-like tar reader/writer for VMS X *`09 based on TAR2VMS and VMS2TAR X * X * Usage: X * `09tar x`7Ct`7Cc`5Bv`5D`5Bw`5D`5Bb`5Bd`5D`5D`5Bf tarfile`5D `5Bfile `5Bfi Vle...`5D`5D X *`09x - extract from tarfile X *`09t - type contents of tarfile X *`09c - create tarfile, archive VMS files X *`09v - verbose X *`09w - wait for confirmation before extracting/archiving X *`09b - binary mode extract, create (rfm=fixed, rat=none, mrs=512) files X *`09d - keep trailing dots in file names X *`09f - specify tarfile name, default is $TAPE X *`09file - space-separated list of file names, can include VMS-style X *`09 string wildcards on extract, can be any VMS file name X * specification (except DECnet) on create archive. X X * Original author of the VMS2TAR and TAR2VMS programs: 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 * X * Deeply modified by: X * Alain Fauconnet X * System Manager X * SIM - Public Health Research Laboratories X * 91 Boulevard de l'Hopital X * 75634 PARIS CEDEX 13 - FRANCE X * Bitnet: FAUCONNE@FRSIM51 X * X * PROBLEMS SHOULD BE REPORTED TO ME. PLEASE DON'T BOTHER SID PENSTONE X * WITH MY OWN BUGS ! X * X * Version 1.1 17-SEP-1990 X * Based on TAR2VMS V2.2 21-OCT-1986 and VMS2TAR V1.8 23-DEC-1986 X * X * Sid Penstone did not include any copyright information in his program so X * this only applies if Sid Penstone agrees: you may use VMSTAR, distribute V it, X * modify it freely provided you don't use it for commercial X * or military purposes. Please include the two above author names in the X * source file of any modified version of VMSTAR. X * X * Modification history: X * 1.1 - reworked handling of current VMS default X * - will now create *relative* tarfiles (i.e. files known X * as "./..." in tar archive directory) except when X * device name is specified or wilcard search gives filenames X * located above current default (tar cvf foo.tar `5B-...`5D*.* will X * lead to this kind of situation) X * - attempt to handle more than 8 levels of directories upon X * extract : .../d7/d8/d9 will be mapped to `5B...D7.D8$D9`5D X * - greatly simplified make_new() because mkdir() creates X * intermediate levels of directories if missing X * 1.0`09Original version from Sid Penstone's code X *`09- merged VMS2TAR & TAR2VMS into a single source file X *`09- code reworked, messages cleaned up X *`09- added support for 'f tarfile' option, changed default to $TAPE X *`09- added support for VMS style wildcard file names on extract X *`09- added support for 'b' (binary file extract) option X *`09- suppressed usage of intermediate scratch file for create operation X *`09- file list on create should now be space separated (removed difficult X *`09 support of comma-separated list with context "a la BACKUP") X *`09- global code simplification attempt, may have broken some X *`09 odd case handling X *`09- added some error handling in tarfile write operations X *`09- probably millions of bugs introduced... sorry. X */ X X X#include stdio X#include time X#include ssdef X#include iodef X#include descrip X#include ctype X#include strdef X#include rms X#include stsdef X#include file X#include stat X#include types X#include iodef X#include string X#include errno X X#define ERROR1 -1 X#define BUFFSIZE 512 X#define ISDIRE 1 X#define ISFILE 0 X#define NAMSIZE 100 X#define BLKSIZE 10240 /* Block size */ X#define DSIZE 512 /* Data block size */ X#define FIXED FAB$C_FIX X Xstruct tarhdr /* A tar header */ X`7B X char title`5BNAMSIZE`5D; X char protection`5B8`5D; X char uid`5B8`5D; /* this is the user id */ X char gid`5B8`5D; /* this is the group id */ X char count`5B12`5D; /* was 11 in error */ X char time`5B12`5D; /* UNIX format date */ X char chksum`5B8`5D; /* header checksum */ X char linkcount; /* hope this is right */ X char linkname`5BNAMSIZE`5D; /* Space for the name of the link */ X char dummy`5B255`5D; /* and the rest */ X`7D header; X Xchar buffer`5BDSIZE`5D; /* buffer for a tarfile record */ X X/* Function flags, options */ X Xint extract, /* x option, extract */ X list, /* t option, list tape contents */ X verbose, /* v option, report actions */ X wait, /* w option, prompt */ X dot, /* d option, suppress dots */ X create, /* c option, create */ X binmode, /* z option, binary mode */ X foption;`09`09/* f option, specify tarfile */ X X/* Miscellaneous globals, etc. */ X Xchar tarfile`5BNAMSIZE`5D, /* Tarfile name */ X pathname`5BNAMSIZE`5D, /* File name as found on tape (UNIX) */ X curdir`5BNAMSIZE`5D, /* Current directory */ X topdir`5BNAMSIZE`5D, /* Top level directory of current default */ X curdev`5BNAMSIZE`5D, /* Current device */ X new_directory`5BNAMSIZE`5D, /* Directory of current file */ X newfile`5BNAMSIZE`5D, /* VMS format of file name */ X outfile`5BNAMSIZE`5D, /* Complete output file specification */ X temp`5BNAMSIZE`5D, /* Scratch */ X creation`5BNAMSIZE`5D, /* Date as extracted from the TAR file */ X *ctime(), /* System function */ X linkname`5BNAMSIZE`5D, /* Linked file name */ X searchname`5BNAMSIZE`5D, /* used in the NAM block for SYS$SEARCH */ X dbuffer`5BDSIZE`5D; /* input file buffer for create operation */ X Xstruct stat sblock; /* structure returned from stat() */ Xstruct FAB fblock; /* File attribute block */ Xstruct NAM nblock; /* Name attribute block for rms */ X Xint bytecount, mode, uic1, uic2, linktype; /* Data from header */ Xint uid, gid, bufferpointer; /* current values used by create */ Xint tarfd; /* The input file descriptor */ X X/* Global file characteristics */ X XFILE *vmsfile; Xint vmsfd, outfd; Xunsigned int vmsmrs, vmstime; /* maximum record size */ Xint vmsrat,vmsorg,vmsrfm; /* other format (as integers) */ Xchar default_name`5B`5D = `7B"*.*;"`7D; /* only get the most recent vers Vion */ X X/* main -- parses options, dispacthes to tar2vms and vms2tar */ X Xmain(argc,argv) Xint argc; Xchar *argv`5B`5D; X`7B Xchar *cp, c; X X/* Decode the options and parameters: */ X X if(argc ==1) X usage(); X extract = 0; /* Defaults for now */ X verbose = 0; X wait = 0; /* Don't wait for prompt */ X binmode = 0; X create = 0; X dot = 0; X foption = 0; X strcpy(tarfile,"$TAPE"); X X cp = argv`5B1`5D; X while(c = *cp++) X `7B X switch(c) X `7B X case 't': X list=1; X break; X case 'x': X extract=1; X break; X case 'c': X create=1; X break; X case 'v': X verbose=1; X break; X case 'w': X wait=1; X break; X case 'd': X dot=1; X break; X case 'b': X binmode=1; X break; X case 'f': X if (*cp != '\0' `7C`7C argc < 3) X usage(); X else X foption = 1; X strcpy(tarfile,argv`5B2`5D); X break; X case '-': X break; X default: X printf("tar: option '%c' not recognized.\n",c); X usage(); X `7D X `7D X X X/* Check options are coherent */ X X if (extract + list + create == 0) X `7B X printf("tar: no action specified.\n"); X exit(1); X `7D X if (extract + create == 2) X `7B X printf("tar: incompatible options specified.\n"); X exit(1); X `7D X X/* Set up directory names - current and top level */ X X strcpy(curdev, getenv("PATH")); X for (cp = curdev; *cp != '\0'; ++cp) X *cp = toupper(*cp);`09`09/* map to uppercase */ X X cp = strchr(curdev, ':'); /* split into device and directory */ X *cp++ = '\0'; X strcpy(curdir, cp); X X strcpy(topdir, curdir); X cp = strchr(topdir,'.');`09`09/* isolate top level directory */ X if (cp != NULL) X `7B X *cp = '`5D'; X *++cp = '\0'; X `7D X X if (create == 0) X tar2vms(argc,argv); X else X vms2tar(argc,argv); X`7D X X/* tar2vms -- handles extract and list options */ X Xtar2vms(argc,argv) Xint argc; Xchar **argv; X X`7B Xint status,file_type,j, flag, argi, process; Xchar *make_directory(), *argp, *ptr; Xstruct dsc$descriptor pattern, candidate; X X/* open the file for reading */ X X if((tarfd = opentar()) <= 0) X `7B X printf("tar: error opening tarfile.\n"); X exit(1); X `7D X X/* Now keep reading headers from this file, and decode the names, etc. */ X X while((status=hdr_read(&header))==DSIZE) /* 0 on end of file */ X `7B X process = 0; X if(strlen(header.title)!=0) /* Valid header */ X `7B X decode_header(); X process = 1; X X/* Now if file names were specified on the command line, check if they X match the current one */ X X if ((foption == 0 && argc > 2) `7C`7C argc > 3) X `7B X process = 0; X argi = foption ? 3 : 2; X while (argi < argc) X `7B X pattern.dsc$w_length = strlen(argv`5Bargi`5D); X pattern.dsc$a_pointer = argv`5Bargi`5D; X pattern.dsc$b_dtype = DSC$K_DTYPE_T; X pattern.dsc$b_class = DSC$K_CLASS_S; X candidate.dsc$w_length = strlen(pathname); X candidate.dsc$a_pointer = pathname; X candidate.dsc$b_dtype = DSC$K_DTYPE_T; X candidate.dsc$b_class = DSC$K_CLASS_S; X X ++argi; X X if (STR$MATCH_WILD(&candidate, &pattern) == STR$_MATCH) X `7B X process = 1; X break; X `7D X `7D X `7D X `7D X else X `7B X status = 1; X break; X `7D `20 X if (process && wait) X `7B X *temp = '\0'; X while (*temp != 'y' && *temp != 'n') X `7B X printf("%s (y/n) ? ", pathname); X scanf("%s", temp); X *temp = tolower(*temp); X `7D X process = (*temp == 'y'); X `7D X if (process && extract) X `7B `20 X file_type=scan_title(pathname,new_directory,newfile); X cleanup_dire(new_directory); X if( make_new(new_directory)!=0) X printf("tar: error creating %s\n",new_directory); X if(file_type == ISDIRE) X `7B`7D X if(file_type == ISFILE) X X/* Now move the data into the output file */ X X if(bytecount>0) X `7B X strcpy(outfile,new_directory); X strcat(outfile,newfile); X if((j=copyfile(outfile,bytecount))<0) X printf("tar: error writing file %s\n",outfile); X `7D X `7D X else X `7B X if (process && list) /* listing only */ X `7B X printf("%6o %6d %s %s\n", X mode,bytecount,creation+4,pathname); X if (linktype == 1 `7C`7C linktype == 2) X printf(" ---> %s\n",linknam Ve); X `7D X if(linktype == 0) X tarskip(bytecount); X `7D X `7D /* end while */ X if(status == 1) /* Empty header */ X `7B X X/* printf("Do you wish to move past the EOF mark (y/n) ? "); X** fflush(stdout); X** gets(temp); X** if(tolower(*temp) == 'y') X** while((status=hdr_read(&header)) >0); X** else X*/ X exit(SS$_NORMAL); X `7D X if(status==0) /* End of tar file */ X `7B X printf("tar: EOF hit on tarfile.\n"); X exit(SS$_NORMAL); X `7D X if(status<0) /* An error */ X `7B X printf("tar: error reading tarfile.\n"); X exit(SS$_NORMAL); X `7D X`7D X X X/* This function simply copies the file to the output, no conversion */ X Xint copyfile(outfile,nbytes) Xchar outfile`5B`5D; /* name of output version */ Xint nbytes; X X`7B Xint inbytes, fil; X X/* Open the output file */ X X if (binmode) X fil = creat(outfile,0,"rfm=fix","mrs=512","alq=5"); X else X fil = creat(outfile,0,"rfm=stmlf","rat=cr"); X X if(fil == ERROR1) X `7B X printf("tar: error creating %s \n",outfile); X tarskip(bytecount); X return(-2); X `7D X if(linktype !=0) X `7B X sprintf(buffer,"*** This file is only a link to %s\n",linkname); X write(fil,buffer,strlen(temp)); X `7D X else X `7B X while(nbytes>0) X `7B X if((inbytes=read(tarfd,buffer,DSIZE)) > 0) X `7B X write(fil,buffer,(nbytes > DSIZE)? DSIZE:nbytes); X nbytes -= inbytes; X `7D X else X `7B X printf("tar: EOF hit on input file.\n"); X close(fil); X return(-1); X `7D X `7D X `7D X/* Close the file */ X close(fil); X if(verbose) X `7B X printf("%s %6d %s\n",creation+4,bytecount,outfile); X if(linktype!=0) X printf(" --> %s\n",linkname); X `7D X return(0); X`7D X X/* scan_title -- decode a Un*x file name into the directory and name */ X X/* Return a value to indicate if this is a directory name, or another file X* We return the extracted directory string in "dire", and the X* filename (if it exists) in "fname". The full title is in "line" X* at input. X*/ X Xint scan_title(line,dire,fname) Xchar line`5B`5D,dire`5B`5D,fname`5B`5D; X`7B Xchar *end1; Xint len,len2,i,ind; X/* The format will be UNIX at input, so we have to scan for the X* UNIX directory separator '/' X* If the name ends with '/' then it is actually a directory name. X* If the directory consists only of '.', then don't add a subdirectory X* The output directory will be a complete file spec, based on the default X* directory. X*/ X X strcpy(dire,curdir); /* Start with the current dir */ X if(strncmp(line,"./",2)==0) X strcpy(line,line+2); /* ignore "./" */ X strcpy(temp,line); /* Start in local buffer */ X ind=vms_cleanup(temp); /* Remove illegal vms characters */ X if((end1=strrchr(temp,'/'))==0) /* No directory at all ? */ X strcpy(fname,temp); /* Only a file name */ X else X `7B /* End of directory name is '/' */ X *end1 = 0; /* Terminate directory name */ X strcpy(fname,end1+1); /* File name without directory */ X for (i=1;temp`5Bi`5D;i++) /* Change '/' to '.' in director Vy */ X if(temp`5Bi`5D=='/') X temp`5Bi`5D='.'; X if (*temp == '/') /* absolute path ? */ X `7B X *temp = '`5B';`09`09/* yes, build absolute VMS path */ X strcpy(dire,temp + 1); X `7D X else X `7B X dire`5Bstrlen(dire)-1`5D = (*temp=='.')?0:'.' ; X /* "." to indicate a subdirectory (unless already there )*/ X strcat(dire,temp); /* Add on the new directory */ X `7D X strcat(dire,"`5D") ; /* And close with '`5D' */ X `7D X if(strlen(fname)==0) /* Could this cause problems ? */ X `7B X return(ISDIRE); X `7D X else X for(i=0,end1=fname;*end1;end1++) /* Replace multiple . */ X if(*end1 == '.') X if(i++)*end1 = '_'; /* After the first */ X return(ISFILE); X`7D X X/* make_new -- create a new directory */ X Xint make_new(want) Xchar want`5B`5D; X`7B Xint status, created; Xchar *dotp; X X created = 1; X status = mkdir(want, 0); /* mkdir in VAX C creates all missing levels V */ X if (status != 0) X `7B X if (errno == EEXIST) X return (0); X if (errno != EINVAL) X return (-1); /* unknown error, simply return */ X else /* maybe too many levels of directories */ X `7B /* change "`5B...FOO.BAR`5D" to "`5B...F VOO$BAR`5D" */ X for (dotp = &want`5Bstrlen(want) - 1`5D;dotp > want && status != 0;) X if (*--dotp == '.')`20 X `7B X *dotp = '$'; X status = mkdir(want, 0); X if (status != 0 && errno == EEXIST) X `7B X status = created = 0; X break; X `7D X `7D X `7D X `7D X if (status != 0) X return (-1); X if(verbose && created) X printf(" %s\n",want); X return(0); X`7D X X /* Function to open and get data from the blocked input file */ Xint opentar() X`7B Xint fd; X fd = open(tarfile, 0, "rfm = fix","mrs = 512"); X if(fd < 0) X `7B X printf("tar: can't open tarfile.\n"); X return(0); X `7D X return(fd); X`7D 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`7B Xint stat; X stat = read(tarfd,buffer,DSIZE); /* read the header */ X return(stat); /* catch them next read ? */ X`7D 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`7B Xint i=0; X while(bytes > 0) X `7B X if((i=read(tarfd,buffer,DSIZE)) == 0) X `7B X printf("tar: EOF hit while skipping.\n"); X return(-1); X `7D X bytes -= i; X `7D X return(0); X`7D X X/* Decode the fields of the header */ X Xint decode_header() X`7B Xint idate, *bintim, chksum, value; Xchar ll, *ptr; 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`5B24`5D=0; X sscanf(header.count,"%o",&bytecount); X sscanf(header.protection,"%o",&mode); X sscanf(header.uid,"%o",&uic1); X sscanf(header.gid,"%o",&uic2); X sscanf(header.chksum,"%o",&chksum); X X/* Verify checksum */ X X for(value = 0, ptr = &header; ptr < &header.chksum; ptr++) 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/* Remove illegal characters from directory and file names; replace X* hyphens and commas with underscores.Returns number of translations X* that were made. X*/ X Xvms_cleanup(string) Xchar string`5B`5D; X`7B Xint i,flag=0; Xchar c; X for(i=0;c=string`5Bi`5D;i++) X `7B X switch (c) X `7B X case ',': /* No commas in file names */ X string`5Bi`5D= '_'; X flag++; /* Record if any changes were made */ X break; X default: X string`5Bi`5D = toupper(c); /* map to uppercase */ X break; X `7D 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* 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*/ 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 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;36 2015640688 $ v=f$verify(v) $ EXIT