🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: vmsnet.internals
1 messages
1 total messages Started by raxco!galaxy.dnet!gleeve Tue, 26 Jan 1993 13:23
ODS2 reader for unix
#516
Author: raxco!galaxy.dnet!gleeve
Date: Tue, 26 Jan 1993 13:23
1032 lines
32928 bytes
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");
}
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads