home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1993 #3 / NN_1993_3.iso / spool / vmsnet / internal / 1805 < prev    next >
Encoding:
Text File  |  1993-01-27  |  31.1 KB  |  1,043 lines

  1. 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
  2. Newsgroups: vmsnet.internals
  3. Subject: ODS2 reader for unix
  4. Message-ID: <9301261335.AA23211@relay2.UU.NET>
  5. From: raxco!galaxy.dnet!gleeve@uunet.UU.NET
  6. Date: Tue, 26 Jan 93 08:23:09 -0500
  7. Organization: Macro32<==>Vmsnet.Internals Gateway
  8. X-Gateway-Source-Info: Mailing List
  9. Lines: 1032
  10.  
  11. The following code might help the person trying to distribute ODS2
  12. info to unix machines. I have not tested it to this point, but it stands
  13. a better chance of working than a unix filesystem create for VMS, since
  14. there have been so many incompatible unix filesystems over the years.
  15. Offered for what it's worth...
  16. Glenn
  17. Everhart@Raxco.com
  18. ----------
  19. /* Following sent by Carl Lydick of CalTech. */
  20. /* note: original version knows nothing about filenames longer than
  21.   9.3 chars, and this knows nothing about ACLs. */
  22. /*% cc -O -o getvms %
  23.  *
  24.  *  Copy files from VMS (ODS-2) filesystem.  Files may be copied to
  25.  *  disk or to standard output.  Transfer modes supported are "text"
  26.  *  (RMS stuff is thrown away, newline is tacked on the end of each
  27.  *  VMS record), and "image" (straight byte-by-byte transfer).  There
  28.  *  were once plans to support a third mode ("binary"), but this has
  29.  *  not yet been implemented.  Defaults for the output destination and
  30.  *  transfer mode are set by #defines, but the destination/mode can be
  31.  *  specified at runtime by using various flags (see "options()").
  32.  *
  33.  *  The input device and directory, if omitted, will default to that of
  34.  *  the previous filespec.  Note that this means that the first filespec
  35.  *  MUST have a directory specified, and (if DFLTDEV is not defined) also
  36.  *  a device as well.  The filename syntax is the same as the standard
  37.  *  VMS naming scheme, except that a "." may be used to separate the
  38.  *  filetype from the version number, and some delimiters may be changed
  39.  *  via #defines, if desired.  (This is all to avoid the possibility of
  40.  *  having to escape some of the characters that the shell treats as
  41.  *  special.)  The device name is the name of the UNIX special file in
  42.  *  /dev, rather than what VMS thinks it would be.
  43.  *
  44.  *  If the first character of argv[0] is "l", or if the "-l" option is
  45.  *  used, the program lists the contents of the directory rather than
  46.  *  copying a file.  At present, only one directory may be listed per
  47.  *  command.
  48.  *
  49.  *  Written by Mark Bartelt, based on an earlier program which copied
  50.  *  files from ODS-1 volumes.
  51.  *
  52.  *      hacked 6-aug-82 norman wilson:
  53.  *              in getvb, don't let h_use get sign extended
  54.  *              added -T & line number stripping
  55.  *              bwk'd putch a bit in the process
  56.  *              added access checks to openout to plug a security hole
  57.  *              this last should probably be commented out for non-unix
  58.  *
  59.  *      hacked 16-aug-84  Sam Sjogren:
  60.  *              In gethdr(), check to see if the user is the
  61.  *              superuser.  If so, ignore file protection.
  62.  *
  63.  *      hacked 26-feb-85  Carl J Lydick
  64.  *              In getde(), check for end-of-file occurring as first word
  65.  *              in the block returned by getvb().  Failure to do so causes
  66.  *              garbage and core dumps.
  67.  */
  68.  
  69.  
  70. #define DFLTDEV "disk$users"
  71.  
  72. #define err0(msg)       { errmsg(msg); return(0); }
  73. #define err1(msg,arg)   { errmsg(msg,arg); return(0); }
  74.  
  75. #define alphnum(x)      ( ( 'a'<=(x) && (x)<='z' ) || ( 'A'<=(x) && (x)<='Z' ) |
  76. | (
  77.  '0'<=(x) && (x)<='9' ) )
  78.  
  79. #define decimal(x)      ( '0'<=(x) && (x)<='9' )
  80.  
  81. #include <stdio.h>
  82.  
  83. typedef unsigned short  ushort;
  84.  
  85. struct filnam {
  86.         char    f_nam[14];      /* File name (ASCII) */
  87.         ushort  f_ver;          /* Version number */
  88. };
  89.  
  90. struct uic {
  91.         ushort  u_prog;         /* Programmer number */
  92.         ushort  u_proj;         /* Project number */
  93. };
  94.  
  95. struct fileid {
  96.         ushort  f_num;          /* File number */
  97.         ushort  f_seq;          /* File sequence number (worthless concept) */
  98.         ushort  f_rvn;          /* Relative volume number (ditto and MBZ) */
  99. };
  100.  
  101. struct rms {
  102.         char    f_forg;         /* Record format and file organization */
  103.         char    f_ratt;         /* Record attributes */
  104.         ushort  f_rsiz;         /* Record size */
  105.         ushort  f_hvbn[2];      /* Highest VBN allocated */
  106.         ushort  f_heof[2];      /* End of file block */
  107.         ushort  f_ffby;         /* First free byte */
  108.         char    f_bksz;         /* Bucket size */
  109.         char    f_hdsz;         /* Fixed header size */
  110.         ushort  f_mrs;          /* Maximum record size */
  111.         ushort  f_deq;          /* Default extend quantity */
  112. };
  113.  
  114. struct ident {
  115.         char    i_fnam[20];     /* File name */
  116.         ushort  i_rvno;         /* Revision number */
  117.         char    i_crdt[8];      /* Creation date and time */
  118.         char    i_rvdt[8];      /* Revision date and time */
  119.         char    i_exdt[8];      /* Expiration date and time */
  120.         char    i_bkdt[8];      /* Backup date and time */
  121.         char    i_ulab[80];     /* User label */
  122. };
  123.  
  124. struct header {
  125.         char    h_idof;         /* Ident area offset */
  126.         char    h_mpof;         /* Map area offset */
  127.         char    h_acof;         /* Access control list offset */
  128.         char    h_rsof;         /* Reserved area offset */
  129.         ushort  h_fseg;         /* Extension segment number */
  130.         ushort  h_flev;         /* Structure level and version */
  131.         ushort  h_fnum;         /* File number */
  132.         ushort  h_fseq;         /* File sequence number */
  133.         ushort  h_frvn;         /* Relative volume number */
  134.         ushort  h_efnu;         /* Extension file number */
  135.         ushort  h_efsq;         /* Extension file sequence number */
  136.         ushort  h_ervn;         /* Extension relative volume number */
  137.         union {
  138.                 char    hu_ufat[32];    /* User file attributes */
  139.                 struct rms hu_rms;      /* RMS file attributes */
  140.         } h_ufat;
  141. #define h_rms   h_ufat.hu_rms
  142.         char    h_fcha[4];      /* File characteristics */
  143. #define h_ucha  h_fcha[0]       /* User controlled characteristics */
  144. #define h_scha  h_fcha[1]       /* System controlled characteristics */
  145.         char    h_UU1[2];       /* Unused 1 */
  146.         char    h_use;          /* Map words in use */
  147.         char    h_priv;         /* Accessor privilege level */
  148.         struct uic h_fown;      /* File owner UIC */
  149. #define h_prog  h_fown.u_prog   /* Programmer (member) number */
  150. #define h_proj  h_fown.u_proj   /* Project (group) number */
  151.         ushort  h_fpro;         /* File protection code */
  152.         ushort  h_rpro;         /* Record protection code */
  153.         char    h_UU2[4];       /* Ununsed 2 */
  154.         char    h_semk[4];      /* Security mask */
  155.         struct ident h_ident;   /* Ident area */
  156.         char    h_other[300];   /* Map area, access control area, etc */
  157. };
  158.  
  159. struct homeblock {
  160.         long    H_hblb;         /* Home block LBN */
  161.         long    H_ahlb;         /* Alternate home block LBN */
  162.         long    H_ihlb;         /* Backup index file header LBN */
  163.         char    H_vlev[2];      /* Structure level and version */
  164.         ushort  H_sbcl;         /* Storage bitmap cluster factor */
  165.         ushort  H_hbvb;         /* Home block VBN */
  166.         ushort  H_ahvb;         /* Backup home block VBN */
  167.         ushort  H_ihvb;         /* Backup index file header VBN */
  168.         ushort  H_ibvb;         /* Index file bitmap VBN */
  169.         ushort  H_iblb[2];      /* Index file bitmap LBN */
  170.         long    H_fmax;         /* Maximum number of files */
  171.         ushort  H_ibsz;         /* Index file bitmap size */
  172.         ushort  H_rsvf;         /* Number of reserved files */
  173.         ushort  H_dvty;         /* Disk device type */
  174.         ushort  H_rvn;          /* Relative volume number */
  175.         ushort  H_nvol;         /* Number of volumes */
  176.         ushort  H_vcha;         /* Volume characteristics */
  177.         struct uic H_vown;      /* Volume owner UIC */
  178.         long    H_vsmx;         /* Volume security mask */
  179.         ushort  H_vpro;         /* Volume protection code */
  180.         ushort  H_dfpr;         /* Default file protection */
  181.         ushort  H_drpr;         /* Default record protection */
  182.         ushort  H_chk1;         /* First checksum */
  183.         char    H_vdat[8];      /* Volume creation date */
  184.         char    H_wisz;         /* Default window size */
  185.         char    H_lruc;         /* Directory pre-access limit */
  186.         ushort  H_fiex;         /* Default file extend */
  187.         char    H_UU1[388];     /* Unused 1 */
  188.         char    H_snam[12];     /* Structure name */
  189.         char    H_indn[12];     /* Volume name */
  190.         char    H_indo[12];     /* Volume owner */
  191.         char    H_indf[12];     /* Format type */
  192.         char    H_UU2[2];       /* Unused 2 */
  193.         ushort  H_chk2;         /* Second checksum */
  194. } hblock;
  195.  
  196. struct directory {
  197.         ushort  d_rbc;          /* Record byte count */
  198.         ushort  d_vrlm;         /* Version limit */
  199.         char    d_flags;        /* Flags */
  200.         char    d_nbc;          /* Name byte count */
  201.         char    d_fname[1];     /* File name string */
  202. };
  203.  
  204. struct dirval {
  205.         ushort  d_ver;          /* Version number */
  206.         struct fileid d_fid;    /* File ID */
  207. };
  208.  
  209. #define BUFSIZE 512
  210.  
  211. #define bit(x)  ((01)<<(x))
  212.  
  213. #define DEV     bit(0)
  214. #define DIR     bit(1)
  215. #define FIL     bit(2)
  216. #define EXT     bit(3)
  217. #define VER     bit(4)
  218.  
  219. #define DIRBEG  '['
  220. #define DIREND  ']'
  221.  
  222. #define NULLCHR '\0'
  223. #define NULLSTR ""
  224.  
  225. #define FSMAX   255
  226. #define DEVMAX  10
  227.  
  228. #define TEXT    0
  229. #define IMGRMS  1
  230. #define IMGFULL 2
  231. #define BINARY  3
  232.  
  233. #define DISK    0
  234. #define STDOUT  1
  235.  
  236. #define DFLTMOD TEXT
  237. #define DFLTOUT DISK
  238.  
  239. char    **av;                           /* Global argv */
  240. char    lsflag = 0;                     /* Nonzero ==> list directory */
  241. int     xfermode = DFLTMOD;             /* Transfer mode */
  242. int     rmlineno = 0;                   /* ntw - remove sos line numbers */
  243. int     outdest = DFLTOUT;              /* Output destination */
  244. char    filspec[FSMAX];                 /* Full filename string being processed
  245. */
  246. int     pflags;                         /* Flags returned by crack() */
  247. char    *dev, *dir, *fil, *typ, *ver;   /* Pointers to cracked filename fields *
  248. /
  249. char    vmsdev[DEVMAX+6];               /* Special file name for VMS filesystem
  250. */
  251. int     vms = -1;                       /* File descriptor for reading VMS files
  252. ystem */
  253. FILE    *of;                            /* Stream pointer for output file */
  254. char    dirfound;                       /* Directory found */
  255.  
  256. struct header   indexh, mfdh, dirh, fileh;      /* File headers for index file,
  257. MFD,
  258.  UFD, and file */
  259.  
  260.  
  261. main(argc,argv)
  262. int     argc;
  263. char    **argv;
  264. {
  265.         char    *basename();
  266.  
  267.         av = argv;
  268.  
  269.         if ( --argc == 0 )
  270.                 usage();
  271.  
  272.         if ( *basename(*argv) == 'l' )
  273.                 ++lsflag;
  274.  
  275.         while ( argc-- ) {
  276.                 if ( **++av == '-' )
  277.                         options(*argv);
  278.                 else
  279.                         getvms();
  280.         }
  281. }
  282.  
  283.  
  284. usage()
  285. {
  286.         fprintf(stderr,"usage: %s [-t] [-i] [-b] [-d] [-f] [-s] vmsfile\n",*av);
  287.         exit(-1);
  288. }
  289.  
  290.  
  291. char *
  292. basename(s)
  293. register char   *s;
  294. {
  295. /* NOTE:  Some versions of UNIX use the name strrchr() rather than rindex() */
  296.         char            *rindex();
  297.         register char   *t;
  298.  
  299.         if ( (t=rindex(s,'/')) == NULL )
  300.                 return(s);
  301.         else
  302.                 return(t+1);
  303. }
  304.  
  305.  
  306. /*
  307.  *  Process option flags
  308.  */
  309.  
  310. options()
  311. {
  312.         register char   *p;
  313.  
  314.         for ( p = *av; *++p; ) {
  315.  
  316.                 switch ( *p ) {
  317.  
  318.                 case 'd':
  319.                 case 'f':       outdest = DISK; break;
  320.                 case 's':       outdest = STDOUT; break;
  321.  
  322.                 case 't':       xfermode = TEXT; break;
  323.                 case 'T':       xfermode = TEXT; rmlineno++; break;     /* ntw *
  324. /
  325.                 case 'i':       xfermode = IMGRMS; break;
  326.                 case 'I':       xfermode = IMGFULL; break;
  327.                 case 'b':       xfermode = BINARY; break;
  328.  
  329.                 case 'l':       ++lsflag; break;
  330.                 case 'c':       lsflag = 0; break;
  331.  
  332.                 default:        fprintf(stderr,"Invalid option (%c)\n",*p);
  333.  
  334.                 }
  335.         }
  336. }
  337.  
  338.  
  339. /*
  340.  *  Get the next requested file from the VMS filesystem
  341.  */
  342.  
  343. getvms()
  344. {
  345.         if ( strlen(*av) > FSMAX )
  346.                 err0("Filespec too long");
  347.         strcpy(filspec,*av);
  348.  
  349.         if ( lsflag ) {
  350.                 if ( openin() )
  351.                         listdir();
  352.         } else {
  353.                 if ( openin() && openout() ) {
  354.                         copyfile();
  355.                         if ( of != stdout )
  356.                                 fclose(of);
  357.                 }
  358.         }
  359. }
  360.  
  361.  
  362. /*
  363.  *  Open VMS file for input
  364.  */
  365.  
  366. openin()
  367. {
  368.         static int      filecnt = 0;
  369.         struct filnam   fn;
  370.         ushort          fnum;
  371.         ushort          search();
  372.         int             gh;
  373.  
  374.         ++filecnt;
  375.         if (crack() == 0)
  376.                 return (0);
  377.         if ( pflags&DEV && !openvms(dev) )
  378.                 return(0);
  379. #ifdef DFLTDEV
  380.         if ( !(pflags&DEV) && filecnt==1 && !openvms(DFLTDEV) )
  381.                 return(0);
  382. #endif
  383.         if ( vms < 0 )
  384.                 err0("No device specified");
  385.         if ( pflags&(DEV|DIR) && !finddir() )
  386.                 return(0);
  387.         if ( !dirfound )
  388.                 err0("No directory specified");
  389.         if ( lsflag ) {
  390.                 if ( pflags & (FIL|EXT|VER) )
  391.                         err0("Invalid directory specification");
  392.                 return(1);
  393.         }
  394.         if ( !(pflags&EXT) )
  395.                 typ = NULLSTR;
  396.         if ( !(pflags&VER) )
  397.                 ver = NULLSTR;
  398.         if ( !convert(fil,typ,ver,&fn) )
  399.                 return(0);
  400.         if ( !(fnum=search(&dirh,&fn)) )
  401.                 err0("File does not exist");
  402.         if ( !(gh=gethdr(fnum,&fileh)) )
  403.                 err0("Can't get file header for file");
  404.         if ( gh == -1 )
  405.                 err0("No access privilege for file");
  406.         return(1);
  407. }
  408.  
  409.  
  410. /*
  411.  *  Crack the filename string -- First step in parsing it; just
  412.  *  locates the fields, doesn't do much real validity checking
  413.  */
  414.  
  415. crack()
  416. {
  417.         register char   *p = filspec;
  418.         register char   *q;
  419.  
  420.         for ( pflags=0; *p; ) {
  421.  
  422.                 if ( *p == DIRBEG ) {
  423.                         if ( pflags & (DIR|FIL|EXT|VER) )
  424.                                 err0("Bad filename syntax");
  425.                         dir = p+1;
  426.                         while ( *p != DIREND ) {
  427.                                 if ( 'a' <= *p && *p <= 'z' )   /* SHOUT the dir
  428. ectory */
  429.                                         *p += 'A' - 'a';        /* name in UPPER
  430.  CASE */
  431.                                 if ( *p++ == NULLCHR )
  432.                                         err0("Bad filename syntax");
  433.                         }
  434.                         *p++ = NULLCHR;
  435.                         pflags |= DIR;
  436.                         continue;
  437.                 }
  438.  
  439.                 for ( q=p; alphnum(*q); ++q )
  440.                         ;
  441.  
  442.                 if ( *q == ':' ) {
  443.                         if ( pflags&(DEV|DIR|FIL|EXT|VER) )
  444.                                 err0("Bad filename syntax");
  445.                         dev = p;
  446.                         pflags |= DEV;
  447.                         *q = NULLCHR;
  448.                         p = q + 1;
  449.                         continue;
  450.                 }
  451.  
  452.                 if ( *q == '.' || *q == ';' || *q == NULLCHR ) {
  453.  
  454.                         if ( !(pflags&FIL) ) {
  455.                                 if ( p == q )
  456.                                         err0("Filename missing");
  457.                                 fil = p;
  458.                                 pflags |= FIL;
  459.                                 if ( *q == ';' ) {
  460.                                         typ = NULLSTR;
  461.                                         pflags |= EXT;
  462.                                 }
  463.                         } else if ( !(pflags&EXT) ) {
  464.                                 typ = p;
  465.                                 pflags |= EXT;
  466.                         } else if ( !(pflags&VER) ) {
  467.                                 ver = p;
  468.                                 pflags |= VER;
  469.                         } else
  470.                                 err0("Bad filename syntax");
  471.  
  472.                         if ( *q == NULLCHR ) {
  473.                                 if ( !(pflags&EXT) )
  474.                                         typ = NULLSTR;
  475.                                 if ( !(pflags&VER) )
  476.                                         ver = NULLSTR;
  477.                                 break;
  478.                         }
  479.                         *q = NULLCHR;
  480.                         p = q + 1;
  481.                         continue;
  482.                 }
  483.  
  484.                 err0("Bad filename syntax");
  485.         }
  486.  
  487.         return(1);
  488. }
  489.  
  490.  
  491. /*
  492.  *  Open a disk containing an VMS filesystem
  493.  */
  494.  
  495. openvms(devname)
  496. char    *devname;
  497. {
  498.         long    ifhbn;
  499.  
  500.         if ( strlen(devname) > DEVMAX )
  501.                 err1("Device name too long (%s)",devname);
  502.         strcpy(vmsdev,"/dev/");
  503.         if ( strncmp(devname,"disk$",5) == 0 )
  504.                 devname += 5;
  505.         if ( strncmp(devname,"vms",3) != 0 )
  506.                 strcat(vmsdev,"vms");
  507.         strcat(vmsdev,devname);
  508.         if ( (vms=open(vmsdev,0)) < 0 )
  509.                 err1("Can't open %s",vmsdev);
  510.  
  511.         if ( !getlb(1L,&hblock) )
  512.                 err1("Can't read homeblock on %s",vmsdev);
  513.  
  514.         ifhbn = ((long)hblock.H_iblb[1]<<16) + (long)hblock.H_iblb[0] + hblock.H
  515. _ibsz;
  516.         if ( !getlb(ifhbn,(char *)&indexh) )
  517.                 err1("Can't read index file header on %s\n",vmsdev);
  518.  
  519.         if ( !getlb(ifhbn+3,(char *)&mfdh) )
  520.                 err1("Can't read mfd header on %s",vmsdev);
  521.  
  522.         return(1);
  523. }
  524.  
  525.  
  526. /*
  527.  *  Locate the directory whose name is pointed to by "dir"
  528.  */
  529.  
  530. finddir()
  531. {
  532. #define direrr(msg,dirname,ptr) { dirmsg(msg,dirname,ptr); return(0); }
  533.         struct header   *hp = &mfdh;
  534.         register char   *p = dir;
  535.         register char   *q;
  536.         char            *strchr();
  537.         int             nch;
  538.         struct filnam   dirfn;
  539.         ushort          dirfnum;
  540.         ushort          search();
  541.         int             gh;
  542.  
  543.         do {
  544.                 for ( q=p; alphnum(*q); ++q )
  545.                         ;
  546.                 if ( ( *q && *q!='.' ) || (nch=q-p) == 0 || nch > 9 )
  547.                         err1("Invalid directory ([%s])",dir);
  548.                 strncpy(dirfn.f_nam,p,nch);
  549.                 dirfn.f_nam[nch] = '\0';
  550.                 strcat(dirfn.f_nam,".DIR");
  551.                 dirfn.f_ver = 1;
  552.                 if ( !(dirfnum=search(hp,&dirfn)) )
  553.                         direrr("Directory [%s] does not exist",dir,q);
  554.                 if ( !(gh=gethdr(dirfnum,(hp=(&dirh)))) )
  555.                         direrr("Can't get file header for directory [%s]",dir,q)
  556. ;
  557.                 if ( gh == -1 )
  558.                         direrr("No access privilege for directory [%s]",dir,q);
  559.                 p = q + 1;
  560.         } while (*q);
  561.         dirfound = 1;
  562.         return(1);
  563. }
  564.  
  565.  
  566. /*
  567.  *  Error accessing a directory
  568.  */
  569.  
  570. dirmsg(msg,dirname,ptr)
  571. char    *msg;
  572. char    *dirname;
  573. char    *ptr;
  574. {
  575.         char    c;
  576.  
  577.         c = *ptr;
  578.         *ptr = '\0';
  579.         errmsg(msg,dirname);
  580.         *ptr = c;
  581. }
  582.  
  583.  
  584. /*
  585.  *  Convert file name, type, and version number to "struct filnam" format
  586.  */
  587.  
  588. convert(fl,tp,vr,f)
  589. char            *fl;
  590. char            *tp;
  591. char            *vr;
  592. struct filnam   *f;
  593. {
  594.         register char *p;
  595.  
  596. /*      if ( strlen(fl) > 9 )
  597.                 err0("Filename longer than 9 characters"); */
  598. /*      if ( strlen(tp) > 3 )
  599.                 err0("File type longer than 3 characters"); */
  600. /* Kludge-o addition by glenn everhart to handle longer names. Also bumped
  601.    array size. */
  602.         if ( strlen(fl) > 39 )
  603.                 err0("Filename longer than 39 characters");
  604.         if ( strlen(tp) > 39 )
  605.                 err0("File type longer than 39 characters");
  606.         strcpy(f->f_nam,fl);
  607.         strcat(f->f_nam,".");
  608.         strcat(f->f_nam,tp);
  609.         for ( p=f->f_nam; *p; ++p )             /* This code is needed since */
  610.                 if ( 'a' <= *p && *p <= 'z' )   /* VMS loves to SHOUT at you */
  611.                         *p += 'A' - 'a';        /* in UPPER CASE all the time */
  612. /* (this is a holdover from the old RAD50 code on RSX and DOS-11) */
  613.         for ( f->f_ver=0; *vr; ) {
  614.                 if ( !decimal(*vr) )
  615.                         err0("Non-digit in version number");
  616.                 f->f_ver *= 10;
  617.                 f->f_ver += *vr++ - '0';
  618.         }
  619.         return(1);
  620. }
  621.  
  622.  
  623. /*
  624.  *  Search a directory (identified by dhp) for a filename
  625.  */
  626.  
  627. ushort
  628. search(dhp,fn)
  629. register struct header  *dhp;
  630. register struct filnam  *fn;
  631. {
  632.         int                             len;
  633.         int                             bod;
  634.         register struct directory       *de;
  635.         struct directory                *getde();
  636.         register struct dirval          *vp;
  637.         register struct dirval          *vplim;
  638.  
  639.         len = strlen(fn->f_nam);
  640.         for ( bod=1; de=getde(dhp,bod); bod=0 ) {
  641.                 if ( de->d_nbc!=len || strncmp(de->d_fname,fn->f_nam,len)!=0 )
  642.                         continue;
  643.                 vp = (struct dirval *) ( de->d_fname + ((de->d_nbc+1)&0376) );
  644.                 if ( !fn->f_ver )
  645.                         return(vp->d_fid.f_num);
  646.                 for ( vplim=(struct dirval *)((char *)(&de->d_vrlm)+de->d_rbc);
  647. vp<vplim; ++vp
  648.  ) {
  649.                         if ( vp->d_ver > fn->f_ver )
  650.                                 continue;
  651.                         if ( vp->d_ver == fn->f_ver )
  652.                                 return(vp->d_fid.f_num);
  653.                         return(0);
  654.                 }
  655.                 return(0);
  656.         }
  657.         return(0);
  658. }
  659.  
  660.  
  661. /*
  662.  *  Open output file
  663.  */
  664.  
  665. openout()
  666. {
  667. /* used to be dimensioned 14 next. Changed to 84 for LONG names. */
  668.         char    outfile[84];
  669.  
  670.         if ( outdest == STDOUT ) {
  671.                 of = stdout;
  672.                 return(1);
  673.         }
  674.  
  675.         strcpy(outfile,fil);
  676.         strcat(outfile,".");
  677.         strcat(outfile,typ);
  678.         if (okwrite(outfile) == 0               /* ntw */
  679.         ||   (of=fopen(outfile,"w")) == NULL )
  680.                 err0("Can't open output file");
  681.         return(1);
  682. }
  683.  
  684.  
  685. /*
  686.  * see if ok to write/create this file
  687.  * needed because we might be setuid or setgid
  688.  * to get at the special files for disks
  689.  * nb we assume the file is in the working directory
  690.  * always true at the moment;  might neeed more mess in future
  691.  */
  692.  
  693. int
  694. okwrite(file)
  695. char *file;
  696. {
  697.  
  698.         if (access(file, 02) == 0)
  699.                 return (1);             /* exists and is writeable */
  700.         if (access(file, 0) == 0)
  701.                 return (0);             /* exists although not writeable */
  702.         if (index(file, '/'))
  703.                 return (0);             /* snh */
  704.         if (access(".", 02) == 0)
  705.                 return (1);             /* file doesn't exist and can create it
  706. */
  707.         return (0);
  708. }
  709.  
  710.  
  711. /*
  712.  *  Copy input file to output destination
  713.  */
  714.  
  715. copyfile()
  716. {
  717.         long            eofblk;
  718.         register long   block = 0;
  719.         register long   b = 0;
  720.         char            buf[BUFSIZE];
  721.         int             nbytes = BUFSIZE;
  722.         register char   *p;
  723.  
  724.         if ( xfermode == BINARY )
  725.                 err0("Binary mode not yet supported");
  726.         if ( xfermode != IMGFULL )
  727.                 eofblk = ( (long)fileh.h_rms.f_heof[0] << 16 ) + fileh.h_rms.f_h
  728. eof[1];
  729.         while ( getvb(++block,buf,&fileh) ) {
  730.                 if ( xfermode == IMGFULL ) {
  731.                         if ( fwrite(buf,1,BUFSIZE,of) == BUFSIZE )
  732.                                 continue;
  733.                         err0("write error");
  734.                 }
  735.                 if ( ++b > eofblk )
  736.                         return(1);
  737.                 if ( b == eofblk )
  738.                         nbytes = fileh.h_rms.f_ffby;
  739.                 if ( xfermode == IMGRMS ) {
  740.                         if ( fwrite(buf,1,nbytes,of) == nbytes )
  741.                                 continue;
  742.                         err0("write error");
  743.                 }
  744.                 for ( p=buf; p<buf+nbytes; )
  745.                         putch(*p++);
  746.         }
  747.         return(1);
  748. }
  749.  
  750.  
  751. /*
  752.  *  Process next character from input file
  753.  *  for text mode
  754.  */
  755.  
  756. /*
  757.  * possible states of the machine:
  758.  */
  759.  
  760. #define INIT    0       /* waiting for the beginning of a record */
  761. #define COUNT   1       /* in byte count */
  762. #define LINENO  2       /* in line number */
  763. #define DATA    3       /* in data */
  764. #define NULLPAD 4       /* eating the padding null at the end */
  765.  
  766. putch(c)
  767. register char   c;
  768. {
  769.         static unsigned count;
  770.         static int      state = INIT;
  771.         static int      nextstate;
  772.         static int      lnbytes;
  773.  
  774.         switch (state) {
  775.         case INIT:
  776.                 count = (c&0377);
  777.                 state = COUNT;
  778.                 break;
  779.  
  780.         case COUNT:
  781.                 if ( (count+=((c&0377)<<8)) == 0 ) {
  782.                         putc('\n',of);
  783.                         state = INIT;
  784.                 } else {
  785.                         if (rmlineno == 0)
  786.                                 state = DATA;
  787.                         else {
  788.                                 lnbytes = 0;
  789.                                 state = LINENO;
  790.                         }
  791.                         nextstate = INIT;
  792.                         if ( count&1 )
  793.                                 nextstate = NULLPAD;
  794.                 }
  795.                 break;
  796.  
  797.         case LINENO:
  798.                 if (lnbytes == 0)
  799.                         lnbytes++;
  800.                 else
  801.                         state = DATA;
  802.                 if (--count == 0) {
  803.                         putc('\n', of);
  804.                         state = INIT;
  805.                 }
  806.                 break;
  807.  
  808.         case DATA:
  809.                 putc(c,of);
  810.                 if ( --count == 0 ) {
  811.                         state = nextstate;
  812.                         putc('\n',of);
  813.                 }
  814.                 break;
  815.  
  816.         case NULLPAD:
  817.                 state = INIT;
  818.                 break;
  819.  
  820.         default:
  821.                 errmsg("internal error in putch");
  822.                 abort();
  823.         }
  824. }
  825.  
  826.  
  827. /*
  828.  *  List contents of a UFD
  829.  */
  830.  
  831. listdir()
  832. {
  833.         register int                    bod;
  834.         register struct directory       *de;
  835.         struct directory                *getde();
  836.         register struct dirval          *vp;
  837.         register struct dirval          *vplim;
  838.  
  839.         for ( bod=1; de=getde(&dirh,bod); bod=0 ) {
  840.                 vp = (struct dirval *) ( de->d_fname + ((de->d_nbc+1)&0376) );
  841.                 vplim = (struct dirval *) ((char *)(&de->d_vrlm)+de->d_rbc);
  842.                 for ( ; vp<vplim; ++vp )
  843.                         prtfn(de,vp);
  844.         }
  845. }
  846.  
  847.  
  848. /*
  849.  *  Write filename to standard output
  850.  */
  851.  
  852. prtfn(de,vp)
  853. register struct directory       *de;
  854. register struct dirval          *vp;
  855. {
  856.         register char   *p;
  857.         register int    i;
  858.  
  859.         for ( p=de->d_fname, i=de->d_nbc; i>0; --i )
  860.                 putc(*p++,stdout);
  861.         fprintf(stdout,";%d\n",vp->d_ver);
  862. }
  863.  
  864.  
  865. /*
  866.  *  Return pointer to next directory entry
  867.  */
  868.  
  869. struct directory *
  870. getde(dhp,bod)
  871. register struct header  *dhp;
  872. int                     bod;
  873. {
  874. #define recsize (*((ushort *)de))
  875. #define STOP    ((ushort)0177777)
  876.         static long             vb;
  877.         static long             eofblk;
  878.         static char             *limit;
  879.         static char             dirbuf[BUFSIZE];
  880.         static char             *de;
  881.  
  882.         if ( bod ) {
  883.                 vb = 0;
  884.                 eofblk = ( (long)dhp->h_rms.f_heof[0] << 16 ) + dhp->h_rms.f_heo
  885. f[1];
  886.                 limit = &dirbuf[BUFSIZE];
  887.         }
  888.         if ( bod || (de+=(recsize+2))>=limit || recsize==STOP ) {
  889.                 if ( ++vb == eofblk )
  890.                         limit = &dirbuf[dhp->h_rms.f_ffby];
  891.                 if ( !getvb(vb,dirbuf,dhp) || (*((ushort *)dirbuf)) == STOP)
  892.                         return((struct directory *)0);
  893.                 de = dirbuf;
  894.         }
  895.         if ( de >= limit )
  896.                 return((struct directory *)0);
  897.         return((struct directory *)de);
  898. }
  899.  
  900.  
  901. /*
  902.  *  Get a file header, given the file number; check access privilege
  903.  */
  904.  
  905. gethdr(fnum,hp)
  906. register ushort         fnum;
  907. register struct header  *hp;
  908. {
  909. #define G_DENY  bit(8)
  910. #define W_DENY  bit(12)
  911.         register long   bn;
  912.         int             grp;
  913.         int             ogrp;
  914.  
  915.         bn = (long)fnum + hblock.H_ibvb + hblock.H_ibsz -1;
  916.         if ( !getvb(bn,(char *)hp,&indexh) )
  917.                 return(0);
  918.         if ( !(hp->h_fpro&W_DENY) || !getuid())
  919.                 return(1);
  920.         grp = getgid();
  921.         ogrp = 64*(grp/100) + 8*((grp/10)%10) + (grp%10);
  922.         if ( ogrp != hp->h_proj || hp->h_fpro&G_DENY )
  923.                 return(-1);
  924.         else
  925.                 return(1);
  926. }
  927.  
  928.  
  929. /*
  930.  *  Routine to get specified virtual block from a file.  Returns 0
  931.  *  on EOF, 1 otherwise.  Note that vbn is 1-based, not 0-based.
  932.  */
  933.  
  934. getvb(vbn,buf,hp)
  935. register long           vbn;
  936. char                    *buf;
  937. register struct header  *hp;
  938. {
  939. #define WTPMASK 0140000
  940. #define WTP00   0000000
  941. #define WTP01   0040000
  942. #define WTP10   0100000
  943. #define WTP11   0140000
  944.         register ushort         *rp;
  945.         register long           block;
  946.         register ushort         *limit;
  947.         register ushort         wtype;
  948.         register long           lbn;
  949.         register long           size;
  950.         ushort                  getsize();
  951.  
  952.         rp = (ushort *)hp + (hp->h_mpof&0377);
  953.         block = 1;
  954.         limit = rp + (hp->h_use & 0377);                /* ntw */
  955.         while ( rp < limit && vbn >= ( block + (size=getsize(rp)) ) ) {
  956.                 wtype = (*rp) & WTPMASK;
  957.                 switch (wtype) {
  958.                         case WTP00:     rp += 1; break;
  959.                         case WTP01:     rp += 2; break;
  960.                         case WTP10:     rp += 3; break;
  961.                         case WTP11:     rp += 4; break;
  962.                 }
  963.                 block += size;
  964.         }
  965.         if ( rp >= limit )
  966.                 return(0);
  967.         lbn = lbnbase(rp) + vbn - block;
  968.         return(getlb(lbn,buf));
  969. }
  970.  
  971.  
  972. /*
  973.  *  Return number of blocks mapped by the current window
  974.  */
  975.  
  976. ushort
  977. getsize(rp)
  978. register ushort *rp;
  979. {
  980.         register ushort wtype;
  981.  
  982.         wtype = (*rp) & WTPMASK;
  983.         switch (wtype) {
  984.                 case WTP00:     return(0);
  985.                 case WTP01:     return(((*((char *)rp))&0377)+1);
  986.                 case WTP10:     return(((*rp)&037777)+1);
  987.                 case WTP11:     return(((((long)(*rp)&037777)<<16)+rp[1])+1);
  988.         }
  989. }
  990.  
  991.  
  992. /*
  993.  *  Return base lbn mapped by the current window
  994.  */
  995.  
  996. long
  997. lbnbase(rp)
  998. register ushort *rp;
  999. {
  1000.         register ushort wtype;
  1001.  
  1002.         wtype = (*rp)&WTPMASK;
  1003.         switch ( wtype ) {
  1004.                 case WTP00:     return(0L);
  1005.                 case WTP01:     return(((((char *)rp)[1]&077L)<<16)+rp[1]);
  1006.                 case WTP10:     return((((long)rp[2])<<16)+(long)rp[1]);
  1007.                 case WTP11:     return((((long)rp[3])<<16)+(long)rp[2]);
  1008.         }
  1009. }
  1010.  
  1011.  
  1012. /*
  1013.  *  Get block from the filesystem, given the logical block number
  1014.  */
  1015.  
  1016. getlb(lbn,buf)
  1017. long    lbn;
  1018. char    *buf;
  1019. {
  1020.         if ( lbn == 0L )
  1021.                 err0("Bad block in file");
  1022.         if ( lseek(vms,BUFSIZE*lbn,0) == -1L ||  read(vms,buf,BUFSIZE) != BUFSIZ
  1023. E )
  1024.                 err0("Read error");
  1025.         return(1);
  1026. }
  1027.  
  1028.  
  1029. /*
  1030.  *  Issue an error message
  1031.  */
  1032.  
  1033. /* VARARGS1 */
  1034.  
  1035. errmsg(msg,arg)
  1036. char    *msg;
  1037. int     arg;
  1038. {
  1039.         fprintf(stderr,"%s -- ",*av);
  1040.         fprintf(stderr,msg,arg);
  1041.         fprintf(stderr,"\n");
  1042. }
  1043.