home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-01-27 | 31.1 KB | 1,043 lines |
- Path: sparky!uunet!stanford.edu!agate!spool.mu.edu!howland.reston.ans.net!sol.ctr.columbia.edu!hamblin.math.byu.edu!arizona.edu!mvb.saic.com!macro32
- Newsgroups: vmsnet.internals
- Subject: ODS2 reader for unix
- Message-ID: <9301261335.AA23211@relay2.UU.NET>
- From: raxco!galaxy.dnet!gleeve@uunet.UU.NET
- Date: Tue, 26 Jan 93 08:23:09 -0500
- Organization: Macro32<==>Vmsnet.Internals Gateway
- X-Gateway-Source-Info: Mailing List
- Lines: 1032
-
- The following code might help the person trying to distribute ODS2
- info to unix machines. I have not tested it to this point, but it stands
- a better chance of working than a unix filesystem create for VMS, since
- there have been so many incompatible unix filesystems over the years.
- Offered for what it's worth...
- Glenn
- Everhart@Raxco.com
- ----------
- /* Following sent by Carl Lydick of CalTech. */
- /* note: original version knows nothing about filenames longer than
- 9.3 chars, and this knows nothing about ACLs. */
- /*% cc -O -o getvms %
- *
- * Copy files from VMS (ODS-2) filesystem. Files may be copied to
- * disk or to standard output. Transfer modes supported are "text"
- * (RMS stuff is thrown away, newline is tacked on the end of each
- * VMS record), and "image" (straight byte-by-byte transfer). There
- * were once plans to support a third mode ("binary"), but this has
- * not yet been implemented. Defaults for the output destination and
- * transfer mode are set by #defines, but the destination/mode can be
- * specified at runtime by using various flags (see "options()").
- *
- * The input device and directory, if omitted, will default to that of
- * the previous filespec. Note that this means that the first filespec
- * MUST have a directory specified, and (if DFLTDEV is not defined) also
- * a device as well. The filename syntax is the same as the standard
- * VMS naming scheme, except that a "." may be used to separate the
- * filetype from the version number, and some delimiters may be changed
- * via #defines, if desired. (This is all to avoid the possibility of
- * having to escape some of the characters that the shell treats as
- * special.) The device name is the name of the UNIX special file in
- * /dev, rather than what VMS thinks it would be.
- *
- * If the first character of argv[0] is "l", or if the "-l" option is
- * used, the program lists the contents of the directory rather than
- * copying a file. At present, only one directory may be listed per
- * command.
- *
- * Written by Mark Bartelt, based on an earlier program which copied
- * files from ODS-1 volumes.
- *
- * hacked 6-aug-82 norman wilson:
- * in getvb, don't let h_use get sign extended
- * added -T & line number stripping
- * bwk'd putch a bit in the process
- * added access checks to openout to plug a security hole
- * this last should probably be commented out for non-unix
- *
- * hacked 16-aug-84 Sam Sjogren:
- * In gethdr(), check to see if the user is the
- * superuser. If so, ignore file protection.
- *
- * hacked 26-feb-85 Carl J Lydick
- * In getde(), check for end-of-file occurring as first word
- * in the block returned by getvb(). Failure to do so causes
- * garbage and core dumps.
- */
-
-
- #define DFLTDEV "disk$users"
-
- #define err0(msg) { errmsg(msg); return(0); }
- #define err1(msg,arg) { errmsg(msg,arg); return(0); }
-
- #define alphnum(x) ( ( 'a'<=(x) && (x)<='z' ) || ( 'A'<=(x) && (x)<='Z' ) |
- | (
- '0'<=(x) && (x)<='9' ) )
-
- #define decimal(x) ( '0'<=(x) && (x)<='9' )
-
- #include <stdio.h>
-
- typedef unsigned short ushort;
-
- struct filnam {
- char f_nam[14]; /* File name (ASCII) */
- ushort f_ver; /* Version number */
- };
-
- struct uic {
- ushort u_prog; /* Programmer number */
- ushort u_proj; /* Project number */
- };
-
- struct fileid {
- ushort f_num; /* File number */
- ushort f_seq; /* File sequence number (worthless concept) */
- ushort f_rvn; /* Relative volume number (ditto and MBZ) */
- };
-
- struct rms {
- char f_forg; /* Record format and file organization */
- char f_ratt; /* Record attributes */
- ushort f_rsiz; /* Record size */
- ushort f_hvbn[2]; /* Highest VBN allocated */
- ushort f_heof[2]; /* End of file block */
- ushort f_ffby; /* First free byte */
- char f_bksz; /* Bucket size */
- char f_hdsz; /* Fixed header size */
- ushort f_mrs; /* Maximum record size */
- ushort f_deq; /* Default extend quantity */
- };
-
- struct ident {
- char i_fnam[20]; /* File name */
- ushort i_rvno; /* Revision number */
- char i_crdt[8]; /* Creation date and time */
- char i_rvdt[8]; /* Revision date and time */
- char i_exdt[8]; /* Expiration date and time */
- char i_bkdt[8]; /* Backup date and time */
- char i_ulab[80]; /* User label */
- };
-
- struct header {
- char h_idof; /* Ident area offset */
- char h_mpof; /* Map area offset */
- char h_acof; /* Access control list offset */
- char h_rsof; /* Reserved area offset */
- ushort h_fseg; /* Extension segment number */
- ushort h_flev; /* Structure level and version */
- ushort h_fnum; /* File number */
- ushort h_fseq; /* File sequence number */
- ushort h_frvn; /* Relative volume number */
- ushort h_efnu; /* Extension file number */
- ushort h_efsq; /* Extension file sequence number */
- ushort h_ervn; /* Extension relative volume number */
- union {
- char hu_ufat[32]; /* User file attributes */
- struct rms hu_rms; /* RMS file attributes */
- } h_ufat;
- #define h_rms h_ufat.hu_rms
- char h_fcha[4]; /* File characteristics */
- #define h_ucha h_fcha[0] /* User controlled characteristics */
- #define h_scha h_fcha[1] /* System controlled characteristics */
- char h_UU1[2]; /* Unused 1 */
- char h_use; /* Map words in use */
- char h_priv; /* Accessor privilege level */
- struct uic h_fown; /* File owner UIC */
- #define h_prog h_fown.u_prog /* Programmer (member) number */
- #define h_proj h_fown.u_proj /* Project (group) number */
- ushort h_fpro; /* File protection code */
- ushort h_rpro; /* Record protection code */
- char h_UU2[4]; /* Ununsed 2 */
- char h_semk[4]; /* Security mask */
- struct ident h_ident; /* Ident area */
- char h_other[300]; /* Map area, access control area, etc */
- };
-
- struct homeblock {
- long H_hblb; /* Home block LBN */
- long H_ahlb; /* Alternate home block LBN */
- long H_ihlb; /* Backup index file header LBN */
- char H_vlev[2]; /* Structure level and version */
- ushort H_sbcl; /* Storage bitmap cluster factor */
- ushort H_hbvb; /* Home block VBN */
- ushort H_ahvb; /* Backup home block VBN */
- ushort H_ihvb; /* Backup index file header VBN */
- ushort H_ibvb; /* Index file bitmap VBN */
- ushort H_iblb[2]; /* Index file bitmap LBN */
- long H_fmax; /* Maximum number of files */
- ushort H_ibsz; /* Index file bitmap size */
- ushort H_rsvf; /* Number of reserved files */
- ushort H_dvty; /* Disk device type */
- ushort H_rvn; /* Relative volume number */
- ushort H_nvol; /* Number of volumes */
- ushort H_vcha; /* Volume characteristics */
- struct uic H_vown; /* Volume owner UIC */
- long H_vsmx; /* Volume security mask */
- ushort H_vpro; /* Volume protection code */
- ushort H_dfpr; /* Default file protection */
- ushort H_drpr; /* Default record protection */
- ushort H_chk1; /* First checksum */
- char H_vdat[8]; /* Volume creation date */
- char H_wisz; /* Default window size */
- char H_lruc; /* Directory pre-access limit */
- ushort H_fiex; /* Default file extend */
- char H_UU1[388]; /* Unused 1 */
- char H_snam[12]; /* Structure name */
- char H_indn[12]; /* Volume name */
- char H_indo[12]; /* Volume owner */
- char H_indf[12]; /* Format type */
- char H_UU2[2]; /* Unused 2 */
- ushort H_chk2; /* Second checksum */
- } hblock;
-
- struct directory {
- ushort d_rbc; /* Record byte count */
- ushort d_vrlm; /* Version limit */
- char d_flags; /* Flags */
- char d_nbc; /* Name byte count */
- char d_fname[1]; /* File name string */
- };
-
- struct dirval {
- ushort d_ver; /* Version number */
- struct fileid d_fid; /* File ID */
- };
-
- #define BUFSIZE 512
-
- #define bit(x) ((01)<<(x))
-
- #define DEV bit(0)
- #define DIR bit(1)
- #define FIL bit(2)
- #define EXT bit(3)
- #define VER bit(4)
-
- #define DIRBEG '['
- #define DIREND ']'
-
- #define NULLCHR '\0'
- #define NULLSTR ""
-
- #define FSMAX 255
- #define DEVMAX 10
-
- #define TEXT 0
- #define IMGRMS 1
- #define IMGFULL 2
- #define BINARY 3
-
- #define DISK 0
- #define STDOUT 1
-
- #define DFLTMOD TEXT
- #define DFLTOUT DISK
-
- char **av; /* Global argv */
- char lsflag = 0; /* Nonzero ==> list directory */
- int xfermode = DFLTMOD; /* Transfer mode */
- int rmlineno = 0; /* ntw - remove sos line numbers */
- int outdest = DFLTOUT; /* Output destination */
- char filspec[FSMAX]; /* Full filename string being processed
- */
- int pflags; /* Flags returned by crack() */
- char *dev, *dir, *fil, *typ, *ver; /* Pointers to cracked filename fields *
- /
- char vmsdev[DEVMAX+6]; /* Special file name for VMS filesystem
- */
- int vms = -1; /* File descriptor for reading VMS files
- ystem */
- FILE *of; /* Stream pointer for output file */
- char dirfound; /* Directory found */
-
- struct header indexh, mfdh, dirh, fileh; /* File headers for index file,
- MFD,
- UFD, and file */
-
-
- main(argc,argv)
- int argc;
- char **argv;
- {
- char *basename();
-
- av = argv;
-
- if ( --argc == 0 )
- usage();
-
- if ( *basename(*argv) == 'l' )
- ++lsflag;
-
- while ( argc-- ) {
- if ( **++av == '-' )
- options(*argv);
- else
- getvms();
- }
- }
-
-
- usage()
- {
- fprintf(stderr,"usage: %s [-t] [-i] [-b] [-d] [-f] [-s] vmsfile\n",*av);
- exit(-1);
- }
-
-
- char *
- basename(s)
- register char *s;
- {
- /* NOTE: Some versions of UNIX use the name strrchr() rather than rindex() */
- char *rindex();
- register char *t;
-
- if ( (t=rindex(s,'/')) == NULL )
- return(s);
- else
- return(t+1);
- }
-
-
- /*
- * Process option flags
- */
-
- options()
- {
- register char *p;
-
- for ( p = *av; *++p; ) {
-
- switch ( *p ) {
-
- case 'd':
- case 'f': outdest = DISK; break;
- case 's': outdest = STDOUT; break;
-
- case 't': xfermode = TEXT; break;
- case 'T': xfermode = TEXT; rmlineno++; break; /* ntw *
- /
- case 'i': xfermode = IMGRMS; break;
- case 'I': xfermode = IMGFULL; break;
- case 'b': xfermode = BINARY; break;
-
- case 'l': ++lsflag; break;
- case 'c': lsflag = 0; break;
-
- default: fprintf(stderr,"Invalid option (%c)\n",*p);
-
- }
- }
- }
-
-
- /*
- * Get the next requested file from the VMS filesystem
- */
-
- getvms()
- {
- if ( strlen(*av) > FSMAX )
- err0("Filespec too long");
- strcpy(filspec,*av);
-
- if ( lsflag ) {
- if ( openin() )
- listdir();
- } else {
- if ( openin() && openout() ) {
- copyfile();
- if ( of != stdout )
- fclose(of);
- }
- }
- }
-
-
- /*
- * Open VMS file for input
- */
-
- openin()
- {
- static int filecnt = 0;
- struct filnam fn;
- ushort fnum;
- ushort search();
- int gh;
-
- ++filecnt;
- if (crack() == 0)
- return (0);
- if ( pflags&DEV && !openvms(dev) )
- return(0);
- #ifdef DFLTDEV
- if ( !(pflags&DEV) && filecnt==1 && !openvms(DFLTDEV) )
- return(0);
- #endif
- if ( vms < 0 )
- err0("No device specified");
- if ( pflags&(DEV|DIR) && !finddir() )
- return(0);
- if ( !dirfound )
- err0("No directory specified");
- if ( lsflag ) {
- if ( pflags & (FIL|EXT|VER) )
- err0("Invalid directory specification");
- return(1);
- }
- if ( !(pflags&EXT) )
- typ = NULLSTR;
- if ( !(pflags&VER) )
- ver = NULLSTR;
- if ( !convert(fil,typ,ver,&fn) )
- return(0);
- if ( !(fnum=search(&dirh,&fn)) )
- err0("File does not exist");
- if ( !(gh=gethdr(fnum,&fileh)) )
- err0("Can't get file header for file");
- if ( gh == -1 )
- err0("No access privilege for file");
- return(1);
- }
-
-
- /*
- * Crack the filename string -- First step in parsing it; just
- * locates the fields, doesn't do much real validity checking
- */
-
- crack()
- {
- register char *p = filspec;
- register char *q;
-
- for ( pflags=0; *p; ) {
-
- if ( *p == DIRBEG ) {
- if ( pflags & (DIR|FIL|EXT|VER) )
- err0("Bad filename syntax");
- dir = p+1;
- while ( *p != DIREND ) {
- if ( 'a' <= *p && *p <= 'z' ) /* SHOUT the dir
- ectory */
- *p += 'A' - 'a'; /* name in UPPER
- CASE */
- if ( *p++ == NULLCHR )
- err0("Bad filename syntax");
- }
- *p++ = NULLCHR;
- pflags |= DIR;
- continue;
- }
-
- for ( q=p; alphnum(*q); ++q )
- ;
-
- if ( *q == ':' ) {
- if ( pflags&(DEV|DIR|FIL|EXT|VER) )
- err0("Bad filename syntax");
- dev = p;
- pflags |= DEV;
- *q = NULLCHR;
- p = q + 1;
- continue;
- }
-
- if ( *q == '.' || *q == ';' || *q == NULLCHR ) {
-
- if ( !(pflags&FIL) ) {
- if ( p == q )
- err0("Filename missing");
- fil = p;
- pflags |= FIL;
- if ( *q == ';' ) {
- typ = NULLSTR;
- pflags |= EXT;
- }
- } else if ( !(pflags&EXT) ) {
- typ = p;
- pflags |= EXT;
- } else if ( !(pflags&VER) ) {
- ver = p;
- pflags |= VER;
- } else
- err0("Bad filename syntax");
-
- if ( *q == NULLCHR ) {
- if ( !(pflags&EXT) )
- typ = NULLSTR;
- if ( !(pflags&VER) )
- ver = NULLSTR;
- break;
- }
- *q = NULLCHR;
- p = q + 1;
- continue;
- }
-
- err0("Bad filename syntax");
- }
-
- return(1);
- }
-
-
- /*
- * Open a disk containing an VMS filesystem
- */
-
- openvms(devname)
- char *devname;
- {
- long ifhbn;
-
- if ( strlen(devname) > DEVMAX )
- err1("Device name too long (%s)",devname);
- strcpy(vmsdev,"/dev/");
- if ( strncmp(devname,"disk$",5) == 0 )
- devname += 5;
- if ( strncmp(devname,"vms",3) != 0 )
- strcat(vmsdev,"vms");
- strcat(vmsdev,devname);
- if ( (vms=open(vmsdev,0)) < 0 )
- err1("Can't open %s",vmsdev);
-
- if ( !getlb(1L,&hblock) )
- err1("Can't read homeblock on %s",vmsdev);
-
- ifhbn = ((long)hblock.H_iblb[1]<<16) + (long)hblock.H_iblb[0] + hblock.H
- _ibsz;
- if ( !getlb(ifhbn,(char *)&indexh) )
- err1("Can't read index file header on %s\n",vmsdev);
-
- if ( !getlb(ifhbn+3,(char *)&mfdh) )
- err1("Can't read mfd header on %s",vmsdev);
-
- return(1);
- }
-
-
- /*
- * Locate the directory whose name is pointed to by "dir"
- */
-
- finddir()
- {
- #define direrr(msg,dirname,ptr) { dirmsg(msg,dirname,ptr); return(0); }
- struct header *hp = &mfdh;
- register char *p = dir;
- register char *q;
- char *strchr();
- int nch;
- struct filnam dirfn;
- ushort dirfnum;
- ushort search();
- int gh;
-
- do {
- for ( q=p; alphnum(*q); ++q )
- ;
- if ( ( *q && *q!='.' ) || (nch=q-p) == 0 || nch > 9 )
- err1("Invalid directory ([%s])",dir);
- strncpy(dirfn.f_nam,p,nch);
- dirfn.f_nam[nch] = '\0';
- strcat(dirfn.f_nam,".DIR");
- dirfn.f_ver = 1;
- if ( !(dirfnum=search(hp,&dirfn)) )
- direrr("Directory [%s] does not exist",dir,q);
- if ( !(gh=gethdr(dirfnum,(hp=(&dirh)))) )
- direrr("Can't get file header for directory [%s]",dir,q)
- ;
- if ( gh == -1 )
- direrr("No access privilege for directory [%s]",dir,q);
- p = q + 1;
- } while (*q);
- dirfound = 1;
- return(1);
- }
-
-
- /*
- * Error accessing a directory
- */
-
- dirmsg(msg,dirname,ptr)
- char *msg;
- char *dirname;
- char *ptr;
- {
- char c;
-
- c = *ptr;
- *ptr = '\0';
- errmsg(msg,dirname);
- *ptr = c;
- }
-
-
- /*
- * Convert file name, type, and version number to "struct filnam" format
- */
-
- convert(fl,tp,vr,f)
- char *fl;
- char *tp;
- char *vr;
- struct filnam *f;
- {
- register char *p;
-
- /* if ( strlen(fl) > 9 )
- err0("Filename longer than 9 characters"); */
- /* if ( strlen(tp) > 3 )
- err0("File type longer than 3 characters"); */
- /* Kludge-o addition by glenn everhart to handle longer names. Also bumped
- array size. */
- if ( strlen(fl) > 39 )
- err0("Filename longer than 39 characters");
- if ( strlen(tp) > 39 )
- err0("File type longer than 39 characters");
- strcpy(f->f_nam,fl);
- strcat(f->f_nam,".");
- strcat(f->f_nam,tp);
- for ( p=f->f_nam; *p; ++p ) /* This code is needed since */
- if ( 'a' <= *p && *p <= 'z' ) /* VMS loves to SHOUT at you */
- *p += 'A' - 'a'; /* in UPPER CASE all the time */
- /* (this is a holdover from the old RAD50 code on RSX and DOS-11) */
- for ( f->f_ver=0; *vr; ) {
- if ( !decimal(*vr) )
- err0("Non-digit in version number");
- f->f_ver *= 10;
- f->f_ver += *vr++ - '0';
- }
- return(1);
- }
-
-
- /*
- * Search a directory (identified by dhp) for a filename
- */
-
- ushort
- search(dhp,fn)
- register struct header *dhp;
- register struct filnam *fn;
- {
- int len;
- int bod;
- register struct directory *de;
- struct directory *getde();
- register struct dirval *vp;
- register struct dirval *vplim;
-
- len = strlen(fn->f_nam);
- for ( bod=1; de=getde(dhp,bod); bod=0 ) {
- if ( de->d_nbc!=len || strncmp(de->d_fname,fn->f_nam,len)!=0 )
- continue;
- vp = (struct dirval *) ( de->d_fname + ((de->d_nbc+1)&0376) );
- if ( !fn->f_ver )
- return(vp->d_fid.f_num);
- for ( vplim=(struct dirval *)((char *)(&de->d_vrlm)+de->d_rbc);
- vp<vplim; ++vp
- ) {
- if ( vp->d_ver > fn->f_ver )
- continue;
- if ( vp->d_ver == fn->f_ver )
- return(vp->d_fid.f_num);
- return(0);
- }
- return(0);
- }
- return(0);
- }
-
-
- /*
- * Open output file
- */
-
- openout()
- {
- /* used to be dimensioned 14 next. Changed to 84 for LONG names. */
- char outfile[84];
-
- if ( outdest == STDOUT ) {
- of = stdout;
- return(1);
- }
-
- strcpy(outfile,fil);
- strcat(outfile,".");
- strcat(outfile,typ);
- if (okwrite(outfile) == 0 /* ntw */
- || (of=fopen(outfile,"w")) == NULL )
- err0("Can't open output file");
- return(1);
- }
-
-
- /*
- * see if ok to write/create this file
- * needed because we might be setuid or setgid
- * to get at the special files for disks
- * nb we assume the file is in the working directory
- * always true at the moment; might neeed more mess in future
- */
-
- int
- okwrite(file)
- char *file;
- {
-
- if (access(file, 02) == 0)
- return (1); /* exists and is writeable */
- if (access(file, 0) == 0)
- return (0); /* exists although not writeable */
- if (index(file, '/'))
- return (0); /* snh */
- if (access(".", 02) == 0)
- return (1); /* file doesn't exist and can create it
- */
- return (0);
- }
-
-
- /*
- * Copy input file to output destination
- */
-
- copyfile()
- {
- long eofblk;
- register long block = 0;
- register long b = 0;
- char buf[BUFSIZE];
- int nbytes = BUFSIZE;
- register char *p;
-
- if ( xfermode == BINARY )
- err0("Binary mode not yet supported");
- if ( xfermode != IMGFULL )
- eofblk = ( (long)fileh.h_rms.f_heof[0] << 16 ) + fileh.h_rms.f_h
- eof[1];
- while ( getvb(++block,buf,&fileh) ) {
- if ( xfermode == IMGFULL ) {
- if ( fwrite(buf,1,BUFSIZE,of) == BUFSIZE )
- continue;
- err0("write error");
- }
- if ( ++b > eofblk )
- return(1);
- if ( b == eofblk )
- nbytes = fileh.h_rms.f_ffby;
- if ( xfermode == IMGRMS ) {
- if ( fwrite(buf,1,nbytes,of) == nbytes )
- continue;
- err0("write error");
- }
- for ( p=buf; p<buf+nbytes; )
- putch(*p++);
- }
- return(1);
- }
-
-
- /*
- * Process next character from input file
- * for text mode
- */
-
- /*
- * possible states of the machine:
- */
-
- #define INIT 0 /* waiting for the beginning of a record */
- #define COUNT 1 /* in byte count */
- #define LINENO 2 /* in line number */
- #define DATA 3 /* in data */
- #define NULLPAD 4 /* eating the padding null at the end */
-
- putch(c)
- register char c;
- {
- static unsigned count;
- static int state = INIT;
- static int nextstate;
- static int lnbytes;
-
- switch (state) {
- case INIT:
- count = (c&0377);
- state = COUNT;
- break;
-
- case COUNT:
- if ( (count+=((c&0377)<<8)) == 0 ) {
- putc('\n',of);
- state = INIT;
- } else {
- if (rmlineno == 0)
- state = DATA;
- else {
- lnbytes = 0;
- state = LINENO;
- }
- nextstate = INIT;
- if ( count&1 )
- nextstate = NULLPAD;
- }
- break;
-
- case LINENO:
- if (lnbytes == 0)
- lnbytes++;
- else
- state = DATA;
- if (--count == 0) {
- putc('\n', of);
- state = INIT;
- }
- break;
-
- case DATA:
- putc(c,of);
- if ( --count == 0 ) {
- state = nextstate;
- putc('\n',of);
- }
- break;
-
- case NULLPAD:
- state = INIT;
- break;
-
- default:
- errmsg("internal error in putch");
- abort();
- }
- }
-
-
- /*
- * List contents of a UFD
- */
-
- listdir()
- {
- register int bod;
- register struct directory *de;
- struct directory *getde();
- register struct dirval *vp;
- register struct dirval *vplim;
-
- for ( bod=1; de=getde(&dirh,bod); bod=0 ) {
- vp = (struct dirval *) ( de->d_fname + ((de->d_nbc+1)&0376) );
- vplim = (struct dirval *) ((char *)(&de->d_vrlm)+de->d_rbc);
- for ( ; vp<vplim; ++vp )
- prtfn(de,vp);
- }
- }
-
-
- /*
- * Write filename to standard output
- */
-
- prtfn(de,vp)
- register struct directory *de;
- register struct dirval *vp;
- {
- register char *p;
- register int i;
-
- for ( p=de->d_fname, i=de->d_nbc; i>0; --i )
- putc(*p++,stdout);
- fprintf(stdout,";%d\n",vp->d_ver);
- }
-
-
- /*
- * Return pointer to next directory entry
- */
-
- struct directory *
- getde(dhp,bod)
- register struct header *dhp;
- int bod;
- {
- #define recsize (*((ushort *)de))
- #define STOP ((ushort)0177777)
- static long vb;
- static long eofblk;
- static char *limit;
- static char dirbuf[BUFSIZE];
- static char *de;
-
- if ( bod ) {
- vb = 0;
- eofblk = ( (long)dhp->h_rms.f_heof[0] << 16 ) + dhp->h_rms.f_heo
- f[1];
- limit = &dirbuf[BUFSIZE];
- }
- if ( bod || (de+=(recsize+2))>=limit || recsize==STOP ) {
- if ( ++vb == eofblk )
- limit = &dirbuf[dhp->h_rms.f_ffby];
- if ( !getvb(vb,dirbuf,dhp) || (*((ushort *)dirbuf)) == STOP)
- return((struct directory *)0);
- de = dirbuf;
- }
- if ( de >= limit )
- return((struct directory *)0);
- return((struct directory *)de);
- }
-
-
- /*
- * Get a file header, given the file number; check access privilege
- */
-
- gethdr(fnum,hp)
- register ushort fnum;
- register struct header *hp;
- {
- #define G_DENY bit(8)
- #define W_DENY bit(12)
- register long bn;
- int grp;
- int ogrp;
-
- bn = (long)fnum + hblock.H_ibvb + hblock.H_ibsz -1;
- if ( !getvb(bn,(char *)hp,&indexh) )
- return(0);
- if ( !(hp->h_fpro&W_DENY) || !getuid())
- return(1);
- grp = getgid();
- ogrp = 64*(grp/100) + 8*((grp/10)%10) + (grp%10);
- if ( ogrp != hp->h_proj || hp->h_fpro&G_DENY )
- return(-1);
- else
- return(1);
- }
-
-
- /*
- * Routine to get specified virtual block from a file. Returns 0
- * on EOF, 1 otherwise. Note that vbn is 1-based, not 0-based.
- */
-
- getvb(vbn,buf,hp)
- register long vbn;
- char *buf;
- register struct header *hp;
- {
- #define WTPMASK 0140000
- #define WTP00 0000000
- #define WTP01 0040000
- #define WTP10 0100000
- #define WTP11 0140000
- register ushort *rp;
- register long block;
- register ushort *limit;
- register ushort wtype;
- register long lbn;
- register long size;
- ushort getsize();
-
- rp = (ushort *)hp + (hp->h_mpof&0377);
- block = 1;
- limit = rp + (hp->h_use & 0377); /* ntw */
- while ( rp < limit && vbn >= ( block + (size=getsize(rp)) ) ) {
- wtype = (*rp) & WTPMASK;
- switch (wtype) {
- case WTP00: rp += 1; break;
- case WTP01: rp += 2; break;
- case WTP10: rp += 3; break;
- case WTP11: rp += 4; break;
- }
- block += size;
- }
- if ( rp >= limit )
- return(0);
- lbn = lbnbase(rp) + vbn - block;
- return(getlb(lbn,buf));
- }
-
-
- /*
- * Return number of blocks mapped by the current window
- */
-
- ushort
- getsize(rp)
- register ushort *rp;
- {
- register ushort wtype;
-
- wtype = (*rp) & WTPMASK;
- switch (wtype) {
- case WTP00: return(0);
- case WTP01: return(((*((char *)rp))&0377)+1);
- case WTP10: return(((*rp)&037777)+1);
- case WTP11: return(((((long)(*rp)&037777)<<16)+rp[1])+1);
- }
- }
-
-
- /*
- * Return base lbn mapped by the current window
- */
-
- long
- lbnbase(rp)
- register ushort *rp;
- {
- register ushort wtype;
-
- wtype = (*rp)&WTPMASK;
- switch ( wtype ) {
- case WTP00: return(0L);
- case WTP01: return(((((char *)rp)[1]&077L)<<16)+rp[1]);
- case WTP10: return((((long)rp[2])<<16)+(long)rp[1]);
- case WTP11: return((((long)rp[3])<<16)+(long)rp[2]);
- }
- }
-
-
- /*
- * Get block from the filesystem, given the logical block number
- */
-
- getlb(lbn,buf)
- long lbn;
- char *buf;
- {
- if ( lbn == 0L )
- err0("Bad block in file");
- if ( lseek(vms,BUFSIZE*lbn,0) == -1L || read(vms,buf,BUFSIZE) != BUFSIZ
- E )
- err0("Read error");
- return(1);
- }
-
-
- /*
- * Issue an error message
- */
-
- /* VARARGS1 */
-
- errmsg(msg,arg)
- char *msg;
- int arg;
- {
- fprintf(stderr,"%s -- ",*av);
- fprintf(stderr,msg,arg);
- fprintf(stderr,"\n");
- }
-